home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume12 / mush / part09 < prev    next >
Text File  |  1990-05-05  |  57KB  |  1,875 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v12i037: Mail User's Shell, Part09/19
  3. from: argv@Eng.Sun.COM (Dan Heller)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 37
  7. Submitted-by: argv@Eng.Sun.COM (Dan Heller)
  8. Archive-name: mush/part09
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # If this archive is complete, you will see the following message at the end:
  17. #        "End of archive 9 (of 19)."
  18. # Contents:  mush/doproc.c mush/mail.c.a
  19. # Wrapped by argv@turnpike on Wed May  2 13:59:29 1990
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'mush/doproc.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'mush/doproc.c'\"
  23. else
  24. echo shar: Extracting \"'mush/doproc.c'\" \(21819 characters\)
  25. sed "s/^X//" >'mush/doproc.c' <<'END_OF_FILE'
  26. X/* @(#)doproc.c        (c) copyright    10/18/86 (Dan Heller) */
  27. X
  28. X/* do main panel item procedures */
  29. X#include "mush.h"
  30. X
  31. Xextern void start_textsw_edit();
  32. Xvoid set_comp_items();
  33. X
  34. Xextern Panel_item
  35. X    file_item, folder_text_item, folder_item, msg_num_item, read_item,
  36. X    reply_item, save_item, sub_hdr_item[6];
  37. X
  38. X/* following macro is for the next two procedures */
  39. X#define hdr_item(item) \
  40. X    (item == sub_hdr_item[0] || item == sub_hdr_item[1] || \
  41. X     item == sub_hdr_item[2] || item == sub_hdr_item[3] || \
  42. X     item == sub_hdr_item[4] || item == sub_hdr_item[5])
  43. X
  44. Xvoid
  45. Xdelete_mail(item, value, event)
  46. Xregister Panel_item item;
  47. Xint value;
  48. Xregister Event *event;
  49. X{
  50. X    int val = value; /* save cuz we reset value immediately */
  51. X    u_long bang = ison(glob_flags, IGN_BANG);
  52. X    char buf[128];
  53. X
  54. X    (void) panel_set(item, PANEL_VALUE, 0, 0);
  55. X    if (hdr_item(item) && event_id(event) != MS_LEFT || val == 2) {
  56. X    help(0, "delete", tool_help);
  57. X    return;
  58. X    }
  59. X    /* delete current message */
  60. X    wprint(sprintf(buf, "\\%sdelete %s\n",
  61. X    ((event_id(event) == MS_LEFT || val == 0)? "" : "un"),
  62. X    panel_get_value(msg_num_item)) + 1); /* +1 skips the backslash */
  63. X    turnon(glob_flags, IGN_BANG);
  64. X    (void) cmd_line(buf, msg_list);
  65. X    if (!bang)
  66. X    turnoff(glob_flags, IGN_BANG);
  67. X}
  68. X
  69. Xvoid
  70. Xread_mail(item, value, event)
  71. XPanel_item item;
  72. XEvent *event;
  73. X{
  74. X    int this_msg = current_msg;
  75. X
  76. X    /* check "event" in case we were called from hdr_sw.c
  77. X     * in which case event would be NULL
  78. X     */
  79. X    if (event && event_id(event) == MS_RIGHT && item &&
  80. X    (item == read_item ||
  81. X    (item == sub_hdr_item[0] || item == sub_hdr_item[1]))) {
  82. X    (void) help(0, "next", tool_help);
  83. X    return;
  84. X    }
  85. X    if (item && (item == sub_hdr_item[4] || item == sub_hdr_item[5])) {
  86. X    (void) help(0, "Menu Read", tool_help);
  87. X    return;
  88. X    }
  89. X    if (!msg_cnt) {
  90. X    wprint ("No Mail.\n");
  91. X    return;
  92. X    }
  93. X    if (item && item == read_item || ison(msg[current_msg].m_flags, DELETE))
  94. X    (void) next_msg();
  95. X    if (this_msg != current_msg || ison(msg[current_msg].m_flags, UNREAD) ||
  96. X        (current_msg < n_array[0] || current_msg > n_array[screen])) {
  97. X    set_isread(current_msg);
  98. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  99. X    }
  100. X    if (isoff(msg[current_msg].m_flags, DELETE))
  101. X    display_msg(current_msg, (u_long)0);
  102. X}
  103. X
  104. X/* the panel button that says "filename" and "directory", etc... text item */
  105. XPanel_setting
  106. Xfile_dir(item, event)
  107. XPanel_item item;
  108. XEvent *event;
  109. X{
  110. X    register char *p;
  111. X    u_long bang = ison(glob_flags, IGN_BANG);
  112. X    char buf[MAXPATHLEN];
  113. X
  114. X    if (event_id(event) == ESC) {
  115. X    /* file expansion request */
  116. X    int n;
  117. X    char **files;
  118. X    p = panel_get_value(item);
  119. X    (void) sprintf(buf, "%s*", p);
  120. X    timeout_cursors(1);
  121. X    if ((n = filexp(buf, &files)) > 0) {
  122. X        Debug("%d: ",n), print_argv(files);
  123. X        if (n > 1) {
  124. X        n = lcprefix(files, 0);
  125. X        files[0][n] = 0;
  126. X        }
  127. X        panel_set_value(item, trim_filename(files[0]));
  128. X        free_vec(files);
  129. X    } else
  130. X        errbell(n);    /* see curs_io.c */
  131. X    timeout_cursors(0);
  132. X    return PANEL_NONE;
  133. X    }
  134. X
  135. X    if (item == folder_text_item) {
  136. X    (void) sprintf(buf, "folder %s %s",
  137. X        (ison(glob_flags, READ_ONLY) || ison(glob_flags, DO_UPDATE) &&
  138. X        !ask("Folder has been modified.  Update changes?"))? "!" : "",
  139. X        panel_get_value(folder_text_item));
  140. X    }
  141. X    else if (item == file_item) {
  142. X    register char *b = buf;
  143. X    char msgstr[BUFSIZ];
  144. X
  145. X    if (event_id(event) == '\n' || event_id(event) == '\r')
  146. X        b += Strcpy(buf, "save  ");
  147. X    else
  148. X        b += Strcpy(buf, "write ");
  149. X    if ((p = panel_get_value(msg_num_item)) && *p)
  150. X        b += Strcpy(b, p);
  151. X    else {
  152. X        if (ison(msg[current_msg].m_flags, DELETE) &&
  153. X            !do_set(set_options, "show_deleted")) {
  154. X        (void) sprintf(msgstr, "Message %d deleted -- save anyway?",
  155. X                        current_msg+1);
  156. X        if (ask(msgstr) != TRUE) {
  157. X            wprint("Message not saved\n");
  158. X            return PANEL_NONE;
  159. X        }
  160. X        }
  161. X        b += strlen(sprintf(b, "%d", current_msg+1));
  162. X    }
  163. X    *b++ = ' ', *b = 0;
  164. X    if (!(p = panel_get_value(item)) || !*p &&
  165. X        (!(p = do_set(set_options, "mbox")) || !*p))
  166. X        p = DEF_MBOX;
  167. X    (void) sprintf(msgstr, "%s in \"%s\"?", buf, trim_filename(p));
  168. X    if (ask(msgstr) != TRUE) {
  169. X        wprint("Message not saved\n");
  170. X        return PANEL_NONE;
  171. X    }
  172. X    (void) strcpy(b, p); /* now add to command */
  173. X    }
  174. X    turnon(glob_flags, IGN_BANG);
  175. X    (void) cmd_line(buf, msg_list);
  176. X    if (!bang)
  177. X    turnoff(glob_flags, IGN_BANG);
  178. X    return PANEL_NONE;
  179. X}
  180. X
  181. X/*
  182. X * callback routine for the panel items that need filename input.
  183. X * (folder and save)
  184. X */
  185. Xvoid
  186. Xdo_file_dir(item, value, event)
  187. XPanel_item item;
  188. Xint value;
  189. XEvent *event;
  190. X{
  191. X    char buf[BUFSIZ];
  192. X    u_long bang = ison(glob_flags, IGN_BANG);
  193. X
  194. X    if (item == folder_item) {
  195. X    (void) sprintf(buf, "folder %s ",
  196. X        (ison(glob_flags, READ_ONLY) || ison(glob_flags, DO_UPDATE) &&
  197. X        !ask("Folder has been modified.  Update changes?"))? "!" : "");
  198. X    if (event_id(event) == MS_LEFT) {
  199. X        char *p = panel_get_value(folder_text_item);
  200. X        if (!*p) {
  201. X        ok_box("Enter folder name.");
  202. X        return;
  203. X        }
  204. X        (void) strcat(buf, p);
  205. X    } else if (!value)
  206. X        (void) strcat(buf, "%");
  207. X    else if (value == 1)
  208. X        (void) strcat(buf, "&");
  209. X    else if (value == 2)
  210. X        (void) strcat(buf, "#");
  211. X    else
  212. X        (void) strcat(buf, panel_get(item, PANEL_CHOICE_STRING, value));
  213. X    } else if (item == save_item) {
  214. X    char msgstr[BUFSIZ], *p;
  215. X    (void) strcpy(buf, "save ");
  216. X    if (event_id(event) == MS_LEFT) {
  217. X        if (!strcmp("Filename:", panel_get(file_item,PANEL_LABEL_STRING))) {
  218. X        event_id(event) = '\n';  /* let file_dir think it got a \n */
  219. X        file_dir(file_item, event);
  220. X        return;
  221. X        }
  222. X    } else if (value == 0) {
  223. X        register char *p2 = (char *)panel_get_value(msg_num_item);
  224. X
  225. X        if (!(p = do_set(set_options, "mbox")) || !*p)
  226. X        p = DEF_MBOX;
  227. X        if (p2 && *p2) {
  228. X        (void) strcat(buf, p2);
  229. X        (void) strcat(buf, " ");
  230. X        }
  231. X        (void) strcat(buf, p);
  232. X    } else
  233. X        (void) strcat(buf, p = panel_get(item, PANEL_CHOICE_STRING, value));
  234. X    (void) sprintf(msgstr, "Save in %s? ", trim_filename(p));
  235. X    if (ask(msgstr) != TRUE) {
  236. X        wprint("Message not saved\n");
  237. X        return;
  238. X    }
  239. X    }
  240. X    turnon(glob_flags, IGN_BANG);
  241. X    (void) cmd_line(buf, msg_list);
  242. X    if (!bang)
  243. X    turnoff(glob_flags, IGN_BANG);
  244. X    (void) panel_set(item, PANEL_VALUE, 0, NULL); /* remove last value */
  245. X}
  246. X
  247. X/*ARGSUSED*/
  248. Xvoid
  249. Xdo_help(item, value, event)
  250. XPanel_item item;
  251. Xregister int value;
  252. XEvent *event;
  253. X{
  254. X    register char *p, *helpfile = tool_help;
  255. X    if (!event || event_id(event) == MS_LEFT)
  256. X    value = 0;
  257. X    switch(value) {
  258. X    case 1: p = "help";
  259. X    when 2: p = "mouse";
  260. X    when 3: p = "windows";
  261. X    when 4: p = "hdr_format", helpfile = cmd_help;
  262. X    when 5: p = "msg_list", helpfile = cmd_help;
  263. X    when 6: p = "folder";
  264. X    otherwise: p = "general";
  265. X    }
  266. X    (void) help(0, p, helpfile);
  267. X}
  268. X
  269. X/*ARGSUSED*/
  270. Xvoid
  271. Xdo_update(item, value, event)
  272. XPanel_item item;
  273. Xint value;
  274. XEvent *event;
  275. X{
  276. X    char *argv[2];
  277. X    if (event && event_id(event) != MS_LEFT) {
  278. X    if (value == 0) {
  279. X        if (check_new_mail() == 0)
  280. X        print("No new mail.\n");
  281. X    } else
  282. X        (void) help(0, "update", tool_help);
  283. X    return;
  284. X    }
  285. X    argv[0] = "update";
  286. X    argv[1] = NULL;
  287. X    timeout_cursors(TRUE);
  288. X    (void) folder(0, argv, NULL);
  289. X    timeout_cursors(FALSE);
  290. X}
  291. X
  292. X/*ARGSUSED*/
  293. Xvoid
  294. Xtoolquit(item, value, event)
  295. XPanel_item item;
  296. Xint value;
  297. XEvent *event;
  298. X{
  299. X    void wmgr_changestate(), wmgr_changelevel();
  300. X    register int which;
  301. X
  302. X    if (!value || event_id(event) == MS_LEFT) {
  303. X    if (ison(glob_flags, DO_UPDATE)) {
  304. X        do_update(NO_ITEM, 0, NO_EVENT);
  305. X        turnoff(glob_flags, NEW_MAIL);
  306. X    }
  307. X    check_icons();
  308. X    mail_status(0); /* lower flag (if up) print current num of msgs */
  309. X    /* wmgr_changestate (window_get(tool, WIN_FD), rootfd, TRUE); */
  310. X    /* wmgr_changelevel (window_get(tool, WIN_FD), parentfd, TRUE); */
  311. X    window_set(tool, FRAME_CLOSED, TRUE, NULL);
  312. X    is_iconic = ((int) window_get(tool, FRAME_CLOSED));
  313. X    return;
  314. X    } else if (value == 2) {
  315. X    (void) help(0, "quit", tool_help);
  316. X    return;
  317. X    }
  318. X    /* modify this to check for "abort" choice when ternary return values
  319. X     * are possible!
  320. X     */
  321. X    if (isoff(glob_flags, DO_UPDATE) ||
  322. X        ask("Folder has been modified -- update?")) {
  323. X    if (!copyback("Quit anyway?"))
  324. X        return;
  325. X    }
  326. X    cleanup(0);
  327. X}
  328. X
  329. X/*ARGSUSED*/
  330. Xvoid
  331. Xdo_lpr(item, value, event)
  332. XPanel_item item;
  333. Xint value;
  334. XEvent *event;
  335. X{
  336. X    char buf[128];
  337. X
  338. X    if (event && (event_id(event) == MS_LEFT || value == 1)) {
  339. X    wprint("Sending message %d to printer...\n", current_msg+1);
  340. X    (void) strcpy(buf, "lpr ");
  341. X    if (value)
  342. X        (void) sprintf(buf, "lpr \"%s\"", panel_get_value(msg_num_item));
  343. X    timeout_cursors(TRUE);
  344. X    (void) cmd_line(buf, msg_list);
  345. X    timeout_cursors(FALSE);
  346. X    } else
  347. X    (void) help(0, "printer", tool_help);
  348. X}
  349. X
  350. X/* panel selection button pressed to send a letter.
  351. X * we've attached the sign panel item to this item to 1) avoid
  352. X * using a global and 2) make it general enough so that multiple
  353. X * compose windows can have multiple send_items and we can
  354. X * identify which sign/fortune items are associated with this
  355. X * particular letter.  The fortune item is attached to the sign
  356. X * item.
  357. X */
  358. X/*ARGSUSED*/
  359. Xvoid
  360. Xdo_send(item, value, event)
  361. XPanel_item item;
  362. Xint value;
  363. Xregister Event *event;
  364. X{
  365. X    Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
  366. X    Panel_item sign_item = (Panel_item)panel_get(item, PANEL_CLIENT_DATA);
  367. X    Panel_item fortune_item =
  368. X    (Panel_item)panel_get(sign_item, PANEL_CLIENT_DATA);
  369. X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
  370. X    char *argv[5], buf[64];
  371. X    char *file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
  372. X    char *p, *oldsign = NULL, *oldfortune = NULL;
  373. X    Textsw save_sw = wprint_sw;
  374. X
  375. X    if (textsw_store_file(textsw, file, 0, 0)) {
  376. X    error("Can't save to %s", file);
  377. X    return;
  378. X    }
  379. X    /* check if user changed variables before sending */
  380. X    if (p = do_set(set_options, "autosign"))
  381. X    oldsign = savestr(p);
  382. X    if (panel_get_value(sign_item) && !oldsign)
  383. X    cmd_line(strcpy(buf, "\\set autosign"), NULL);
  384. X    else if (!panel_get_value(sign_item) && oldsign)
  385. X    cmd_line(strcpy(buf, "\\unset autosign"), NULL);
  386. X    if (p = do_set(set_options, "fortune"))
  387. X    oldfortune = savestr(p);
  388. X    if (panel_get_value(fortune_item) && !oldfortune)
  389. X    (void) cmd_line(strcpy(buf, "set fortune"), NULL);
  390. X    else if (!panel_get_value(fortune_item) && oldfortune)
  391. X    (void) cmd_line(strcpy(buf, "\\unset fortune"), NULL);
  392. X    wprint_sw = NULL;
  393. X    wprint_sw = save_sw;
  394. X    turnoff(glob_flags, IS_GETTING);
  395. X    argv[0] = "mail";
  396. X    argv[1] = "-Uh";
  397. X    argv[2] = file;
  398. X    argv[3] = NULL;
  399. X    clear_msg_list(msg_list);
  400. X    timeout_cursors(TRUE);
  401. X    if (do_mail(3, argv, msg_list) == 0) {
  402. X    (void) unlink(file);
  403. X    set_comp_items(panel);
  404. X    }
  405. X    if (panel_get_value(sign_item) && !oldsign)
  406. X    (void) cmd_line(strcpy(buf, "\\unset autosign"), NULL);
  407. X    else if (!panel_get_value(sign_item) && oldsign) {
  408. X    argv[0] = "set";
  409. X    argv[1] = "autosign";
  410. X    if (*oldsign) {
  411. X        argv[2] = "=";
  412. X        argv[3] = oldsign;
  413. X        argv[4] = NULL;
  414. X        (void) set(4, argv, NULL);
  415. X    } else {
  416. X        argv[2] = NULL;
  417. X        (void) set(2, argv, NULL);
  418. X    }
  419. X    }
  420. X    if (panel_get_value(fortune_item) && !oldfortune)
  421. X    cmd_line(strcpy(buf, "\\unset fortune"), NULL);
  422. X    else if (!panel_get_value(fortune_item) && oldfortune) {
  423. X    argv[0] = "set";
  424. X    argv[1] = "fortune";
  425. X    if (*oldfortune) {
  426. X        argv[2] = "=";
  427. X        argv[3] = oldfortune;
  428. X        argv[4] = NULL;
  429. X        (void) set(4, argv, NULL);
  430. X    } else {
  431. X        argv[2] = NULL;
  432. X        (void) set(2, argv, NULL);
  433. X    }
  434. X    }
  435. X    xfree(oldsign), xfree(oldfortune);
  436. X    timeout_cursors(FALSE);
  437. X}
  438. X
  439. X/*ARGSUSED*/
  440. Xvoid
  441. Xdo_include(item, value, event)
  442. XPanel_item item;
  443. Xint value;
  444. XEvent *event;
  445. X{
  446. X    extern FILE *ed_fp;
  447. X    char *p, buf[64], *file;
  448. X    Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
  449. X    PANEL_CLIENT_DATA);
  450. X
  451. X    if (event && event_id(event) == MS_LEFT)
  452. X    value = 0;
  453. X    if (value == 2) {
  454. X    (void) help(0, "include", tool_help);
  455. X    return;
  456. X    }
  457. X    p = panel_get_value(msg_num_item);
  458. X    (void) sprintf(buf, "%c%c%s", *escape, value == 0? 'i' : 'f', p? p : "");
  459. X
  460. X    file = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
  461. X    if (textsw_store_file(textsw, file, 0, 0)) {
  462. X    (void) ask("Something's wrong... Click anything.");
  463. X    return;
  464. X    }
  465. X    if (ed_fp) {
  466. X    (void) ask("tmpfile already in use... Click anything.");
  467. X    (void) fclose(ed_fp);
  468. X    }
  469. X    if (!(ed_fp = mask_fopen(file, "a"))) {
  470. X    error("Cannot open %s to append msg.", file);
  471. X    return;
  472. X    }
  473. X    (void) add_to_letter(buf);
  474. X    (void) fclose(ed_fp), ed_fp = NULL_FILE;
  475. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  476. X    window_set(textsw, TEXTSW_FILE_CONTENTS, file, NULL);
  477. X#else /* SUN_4_0 */
  478. X    textsw_load_file(textsw, file, 1, 0, 0);
  479. X#endif /* SUN_4_0 */
  480. X    window_set(textsw, TEXTSW_UPDATE_SCROLLBAR, NULL);
  481. X    (void) unlink(file);
  482. X}
  483. X
  484. X/*ARGSUSED*/
  485. Xvoid
  486. Xdo_compose(item, value, event)
  487. XPanel_item item;
  488. Xint value;
  489. XEvent *event;
  490. X{
  491. X    char buf[5];
  492. X    Textsw textsw;
  493. X
  494. X    if (event && event_id(event) != MS_LEFT) {
  495. X    (void) help(0, "compose", tool_help);
  496. X    return;
  497. X    }
  498. X    open_compose();
  499. X    clear_msg_list(msg_list);
  500. X    if (do_mail(0, DUBL_NULL, msg_list) == 0) {
  501. X#ifdef SUN_4_0
  502. X    Panel panel = (Panel)window_get(compose_frame, FRAME_NTH_WINDOW, 1);
  503. X#else
  504. X    Panel panel = (Panel)window_get(compose_frame, FRAME_NTH_WINDOW, 0);
  505. X#endif /* SUN_4_0 */
  506. X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
  507. X    start_textsw_edit(textsw, TRUE);
  508. X    set_comp_items(panel);
  509. X    }
  510. X}
  511. X
  512. X/*
  513. X * notify proc for reply button -- also called from select.c (do_menu()) ,
  514. X * in which case "event" is null and "value" contains the message
  515. X * number of the message to reply to.
  516. X */
  517. X/*ARGSUSED*/
  518. Xvoid
  519. Xrespond_mail(item, value, event)
  520. XPanel_item item;
  521. Xint value;
  522. XEvent *event;
  523. X{
  524. X    int tmp = current_msg;
  525. X    char buf[256];
  526. X
  527. X    if (event && event_id(event) == MS_LEFT)
  528. X    value = 0;
  529. X    if (event && value == 4) {
  530. X    (void) help(0, "respond", tool_help);
  531. X    return;
  532. X    }
  533. X    if (!msg_cnt) {
  534. X    wprint("No messages to respond to.\n");
  535. X    return;
  536. X    }
  537. X    if (ison(glob_flags, IS_GETTING)) {
  538. X    wprint("Finish editing current message first.\n");
  539. X    return;
  540. X    }
  541. X    if (!event)
  542. X    tmp = value, value = 0;
  543. X    open_compose();
  544. X    (void) sprintf(buf, "%s %s %d",
  545. X    (value == 2 || value == 3)? "\\replyall" : "\\replysender",
  546. X    (value == 1 || value == 3)? "-i": NO_STRING, tmp+1);
  547. X    if (cmd_line(buf, NULL) != -1) {
  548. X#ifdef SUN_4_0
  549. X    Panel panel = (Panel)window_get(compose_frame, FRAME_NTH_WINDOW, 1);
  550. X#else
  551. X    Panel panel = (Panel)window_get(compose_frame, FRAME_NTH_WINDOW, 0);
  552. X#endif /* SUN_4_0 */
  553. X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
  554. X    wprint("Responding to message %d\n", tmp+1);
  555. X    start_textsw_edit(textsw, FALSE);
  556. X    set_comp_items(panel);
  557. X    }
  558. X}
  559. X
  560. X/*ARGSUSED*/
  561. Xvoid
  562. Xload_from_file(item, value, event)
  563. XPanel_item item;
  564. Xint value;
  565. XEvent *event;
  566. X{
  567. X    int x = 0;
  568. X    Textsw textsw;
  569. X    Panel_item filename_item = (Panel_item)panel_get(item, PANEL_CLIENT_DATA);
  570. X    char *file, *p = panel_get_value(filename_item);
  571. X#ifndef SUN_4_0 /* SunOS 4.0+ */
  572. X    char *sfile, buf[128];
  573. X    extern FILE *ed_fp;
  574. X#endif /* SUN_4_0 */
  575. X    
  576. X    if (!*p) {
  577. X    wprint("Specify Filename.\n");
  578. X    return;
  579. X    }
  580. X    file = getpath(p, &x);
  581. X    if (x == 1)
  582. X    wprint("%s: is a directory.\n", p);
  583. X    else if (x == -1)
  584. X    wprint("%s: %s\n", p, file);
  585. X    if (x)
  586. X    return;
  587. X    timeout_cursors(TRUE);
  588. X    textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
  589. X    PANEL_CLIENT_DATA);
  590. X    if (event_id(event) != MS_LEFT && value == 1)
  591. X    /* replace */
  592. X    textsw_load_file(textsw, file, 1, 0, 0);
  593. X    else {
  594. X    /* insert */
  595. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  596. X    window_set(textsw, TEXTSW_INSERT_FROM_FILE, file, NULL);
  597. X#else /* SUN_4_0 */
  598. X    /* best we can do with pre 4.0 is save the current file
  599. X     * and append the new file onto the end.
  600. X     */
  601. X    sfile = (char *)window_get(textsw, TEXTSW_CLIENT_DATA);
  602. X    if (textsw_store_file(textsw, sfile, 0, 0)) {
  603. X        (void) ask("Can't save file... Click anything.");
  604. X        return;
  605. X    }
  606. X    if (ed_fp) {
  607. X        (void) ask("tmpfile already in use... Click anything.");
  608. X        fclose(ed_fp);
  609. X    }
  610. X    if (!(ed_fp = mask_fopen(sfile, "a"))) {
  611. X        error("Cannot open %s.", sfile);
  612. X        return;
  613. X    }
  614. X    (void) sprintf(buf, "%c%c%s", *escape, 'r', trim_filename(p));
  615. X    (void) add_to_letter(buf);
  616. X    (void) fclose(ed_fp), ed_fp = NULL_FILE;
  617. X    textsw_load_file(textsw, sfile, 1, 0, 0);
  618. X    (void) unlink(sfile);
  619. X#endif /* SUN_4_0 */
  620. X    }
  621. X    window_set(textsw, TEXTSW_UPDATE_SCROLLBAR, NULL);
  622. X    panel_set_value(item, 0);
  623. X    timeout_cursors(FALSE);
  624. X}
  625. X
  626. X/*ARGSUSED*/
  627. Xvoid
  628. Xsave_to_file(item, value, event)
  629. XPanel_item item;
  630. XEvent *event;
  631. X{
  632. X    Panel_item filename_item = panel_get(item, PANEL_CLIENT_DATA);
  633. X    char *file = panel_get_value(filename_item);
  634. X    FILE *fp;
  635. X    Textsw textsw = (Textsw)panel_get(panel_get(item, PANEL_PARENT_PANEL),
  636. X    PANEL_CLIENT_DATA);
  637. X
  638. X    if (!*file) {
  639. X    wprint("Specify Filename\n");
  640. X    return;
  641. X    }
  642. X    timeout_cursors(TRUE);
  643. X    /* append to file -- no confirmation necessary */
  644. X    if (fp = open_file(file, FALSE, TRUE)) {
  645. X    char buf[BUFSIZ];
  646. X    Textsw_index next_pos = 0, tmp;
  647. X    Textsw_index length =
  648. X        (Textsw_index)window_get(textsw, TEXTSW_LENGTH);
  649. X    do  {
  650. X        tmp = next_pos;
  651. X        next_pos = (Textsw_index) window_get(textsw, TEXTSW_CONTENTS,
  652. X        next_pos, buf, sizeof(buf));
  653. X        if (fwrite(buf, sizeof(char), (int)(next_pos - tmp), fp) == 0)
  654. X        error("%s may be incomplete", file);
  655. X    } while (next_pos < length);
  656. X    (void) close_lock(file, fp);
  657. X    wprint("Wrote %d bytes to %s\n", length, trim_filename(file));
  658. X    }
  659. X    timeout_cursors(FALSE);
  660. X}
  661. X
  662. Xvoid
  663. Xabort_mail(item, event)
  664. XPanel_item item;
  665. XEvent *event;
  666. X{
  667. X    Panel panel = (Panel)panel_get(item, PANEL_PARENT_PANEL);
  668. X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
  669. X    wprint("Aborted letter.\n");
  670. X    textsw_reset(textsw, 0, 0);
  671. X    rm_edfile(0);
  672. X    set_comp_items(panel);
  673. X}
  674. X
  675. X/* set the compose panel items */
  676. Xvoid
  677. Xset_comp_items(panel)
  678. XPanel panel;
  679. X{
  680. X    Panel_item item, next;
  681. X    Textsw textsw = (Textsw)panel_get(panel, PANEL_CLIENT_DATA);
  682. X    int getting = ison(glob_flags, IS_GETTING) != 0;
  683. X    int i = 0;
  684. X
  685. X    window_set(textsw, TEXTSW_READ_ONLY, !getting, NULL);
  686. X    /* remove next line when multiple composes become a reality */
  687. X    (void) panel_set(reply_item, PANEL_SHOW_ITEM, !getting, NULL);
  688. X    /* skip "close" item */
  689. X    item = (Panel_item) panel_get(panel, PANEL_FIRST_ITEM);
  690. X    for (item = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
  691. X    item; item = next) {
  692. X    next = (Panel_item) panel_get(item, PANEL_NEXT_ITEM);
  693. X    (void) panel_set(item,
  694. X        PANEL_SHOW_ITEM, (i++ < 1)? !getting : getting, NULL);
  695. X    }
  696. X}
  697. X
  698. X/*
  699. X * Ask a yes/no question and return an answer: TRUE or FALSE.
  700. X */
  701. Xask(question)
  702. Xchar *question;
  703. X{
  704. X#ifdef SUN_4_0 /* SunOS 4.0+ */
  705. X    return alert_prompt(tool, (Event *)NULL,
  706. X    ALERT_MESSAGE_STRINGS,    question, NULL,
  707. X    ALERT_BUTTON_YES,    "Yes",
  708. X    ALERT_BUTTON_NO,    "No",
  709. X    NULL) == ALERT_YES;
  710. X#else /* SUN_4_0 */
  711. X    Event event;
  712. X    struct prompt prompt;
  713. X    Rect *rect = (Rect *)window_get(tool, WIN_RECT);
  714. X    char buf[MAXPATHLEN];
  715. X
  716. X    (void) sprintf(buf,
  717. X        "%s  \nPress LEFT Button to Confirm.  Anything else to cancel.",
  718. X        question);
  719. X    prompt.prt_rect.r_left = rect->r_left + (rect->r_width / 3);
  720. X    prompt.prt_rect.r_top = rect->r_top + (rect->r_height / 3);
  721. X    prompt.prt_rect.r_width = prompt.prt_rect.r_height = PROMPT_FLEXIBLE;
  722. X    prompt.prt_font = mush_font;
  723. X    prompt.prt_text = buf;
  724. X
  725. X    menu_prompt(&prompt, &event, window_get(tool, WIN_FD));
  726. X    return event_id(&event) == MS_LEFT;
  727. X#endif /* SUN_4_0 */
  728. X}
  729. X
  730. Xvoid
  731. Xok_box(buf)
  732. Xchar *buf;
  733. X{
  734. X#ifdef SUN_4_0
  735. X    (void) alert_prompt(tool, (Event *)NULL,
  736. X    ALERT_MESSAGE_STRINGS,    buf, NULL,
  737. X    ALERT_BUTTON_YES,        "Ok",
  738. X    NULL);
  739. X#else /* SUN_4_0 */
  740. X    Event event;
  741. X    struct prompt prompt;
  742. X    Rect *rect = (Rect *)window_get(tool, WIN_RECT);
  743. X    (void) strcat(buf, "  \nPress LEFT Button to Continue.");
  744. X    prompt.prt_rect.r_left = rect->r_left + (rect->r_width / 3);
  745. X    prompt.prt_rect.r_top = rect->r_top + (rect->r_height / 3);
  746. X    prompt.prt_rect.r_width = prompt.prt_rect.r_height = PROMPT_FLEXIBLE;
  747. X    prompt.prt_font = mush_font;
  748. X    prompt.prt_text = buf;
  749. X    menu_prompt(&prompt, &event, window_get(tool, WIN_FD));
  750. X#endif /* SUN_4_0 */
  751. X}
  752. X
  753. XPanel_setting
  754. Xmsg_num_done(item, event)
  755. XPanel_item item;
  756. XEvent *event;
  757. X{
  758. X    char buf[82];
  759. X    u_long bang = ison(glob_flags, IGN_BANG);
  760. X    register char *p;
  761. X    int n;
  762. X
  763. X    if (event_id(event) != '\n' && event_id(event) != '\r') {
  764. X    (void) help(0, "message range", tool_help);
  765. X    return PANEL_NONE;
  766. X    }
  767. X    (void) sprintf(buf, "headers %s", (p = (char *)panel_get_value(item)));
  768. X    (void) panel_set(item, PANEL_VALUE, NO_STRING, NULL);
  769. X    if (!(n = chk_msg(p)))
  770. X    return PANEL_NONE;
  771. X    current_msg = --n;
  772. X    turnon(glob_flags, IGN_BANG);
  773. X    (void) cmd_line(buf, msg_list);
  774. X    if (!bang)
  775. X    turnoff(glob_flags, IGN_BANG);
  776. X    (void) display_msg(n, (u_long)0);
  777. X    return PANEL_NONE;
  778. X}
  779. X
  780. Xvoid
  781. Xdo_sort(item, value, event)
  782. XPanel_item item;
  783. Xint value;
  784. XEvent *event;
  785. X{
  786. X    char *argv[3], list[MAXMSGS_BITS];
  787. X    char *p = (char *)panel_get_value(msg_num_item);
  788. X    int n = 0;
  789. X
  790. X    if (p && *p) {
  791. X    argv[0] = p;
  792. X    argv[1] = NULL;
  793. X    n = get_msg_list(argv, list);
  794. X    }
  795. X    argv[0] = "sort";
  796. X    argv[2] = NULL;
  797. X
  798. X    if (event_id(event) == MS_LEFT)
  799. X    argv[1] = do_set(set_options, "sort");
  800. X    else switch(value) {
  801. X    case 0: argv[1] = "d";
  802. X    when 1: argv[1] = "a";
  803. X    when 2: argv[1] = "l";
  804. X    when 3: argv[1] = "R";
  805. X    when 4: argv[1] = "s";
  806. X    when 5: argv[1] = "S";
  807. X    when 6: (void) help(0, "sort", tool_help);
  808. X    }
  809. X    if (value != 6) {
  810. X    if (n > 0) {
  811. X        turnon(glob_flags, IS_PIPE);
  812. X        (void) sort(2, argv, list);
  813. X        turnoff(glob_flags, IS_PIPE);
  814. X    } else
  815. X        (void) sort(2, argv, NULL);
  816. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  817. X    }
  818. X    (void) panel_set(item, PANEL_VALUE, 0, NULL);
  819. X}
  820. X
  821. Xvoid
  822. Xdo_options(item, value, event)
  823. XPanel_item item;
  824. Xint value;
  825. XEvent *event;
  826. X{
  827. X    if (event_id(event) == MS_LEFT) {
  828. X    view_options();
  829. X    return;
  830. X    }
  831. X    switch (value) {
  832. X    case 0:
  833. X        view_options();
  834. X    when 1:
  835. X        do_ignore();
  836. X    when 2:
  837. X        do_aliases();
  838. X    }
  839. X}
  840. END_OF_FILE
  841. if test 21819 -ne `wc -c <'mush/doproc.c'`; then
  842.     echo shar: \"'mush/doproc.c'\" unpacked with wrong size!
  843. fi
  844. # end of 'mush/doproc.c'
  845. fi
  846. if test -f 'mush/mail.c.a' -a "${1}" != "-c" ; then 
  847.   echo shar: Will not clobber existing file \"'mush/mail.c.a'\"
  848. else
  849. echo shar: Extracting \"'mush/mail.c.a'\" \(30778 characters\)
  850. sed "s/^X//" >'mush/mail.c.a' <<'END_OF_FILE'
  851. X/* @(#)mail.c     (c) copyright 1986 (Dan Heller) */
  852. X
  853. X#include "mush.h"
  854. X
  855. X/*
  856. X * mail.c --
  857. X *    do_mail()     external interface to these functions; parses options.
  858. X *    mail_someone()    called from do_mail() to begin composing the message.
  859. X *    start_file()      creates the editing file and reset signal catching.
  860. X *    add_to_letter()    adds the next line to letter --determine ~ escapes.
  861. X *    finish_up_letter()  prompts for Cc:, verifies send, adds signatures.
  862. X *    send_it()     expands aliases, invokes mailer, sends to record file.
  863. X *    add_headers()    adds all headers to a FILE *, reads draft files
  864. X *    rm_edfile()    signals are directed here. remove letter, longjmp
  865. X *    dead_letter()     make a dead.letter if mail failed.
  866. X */
  867. X
  868. Xstatic char Subject[BUFSIZ],To[HDRSIZ],Cc[HDRSIZ],Bcc[HDRSIZ],in_reply_to[256];
  869. Xstatic int killme;
  870. Xstatic u_long flags;
  871. Xstatic SIGRET (*oldterm)(), (*oldint)(), (*oldquit)();
  872. Xstatic int finish_up_letter(), send_it(), start_file();
  873. Xstatic long add_headers();
  874. Xstatic jmp_buf cntrl_c_buf;
  875. Xstatic char *Hfile, *edfile;
  876. XFILE *ed_fp;
  877. Xchar *hfile, *mktemp();
  878. X
  879. X/* argc and argv could be null if coming from tool mode compose */
  880. Xdo_mail(n, argv, list)
  881. Xregister int n;   /* no need for "argc", so use the space for a variable */
  882. Xregister char **argv, *list;
  883. X{
  884. X    char firstchar = (argv)? **argv: 'm';
  885. X    char *to = NULL, *cc = NULL, *addcc = NULL, *bcc = NULL, *subj = NULL;
  886. X    char *route = NULL;
  887. X    char inc_list[MAXMSGS_BITS], buf[HDRSIZ];
  888. X    u_long flgs = 0;
  889. X
  890. X    if (ison(glob_flags, IS_GETTING)) {
  891. X    wprint("You must finish the letter you are editing first.\n");
  892. X    return -1;
  893. X    }
  894. X    if (ison(glob_flags, DO_PIPE)) {
  895. X    wprint("You can't pipe through the mail command.\n");
  896. X    return -1;
  897. X    }
  898. X    clear_msg_list(inc_list);
  899. X    hfile = Hfile = NULL;
  900. X
  901. X    /* If piped to mail, include the messages piped */
  902. X    if (ison(glob_flags, IS_PIPE) ||
  903. X    (lower(firstchar) == 'r' && do_set(set_options, "autoinclude"))) {
  904. X    turnon(flgs, INCLUDE);
  905. X    bitput(list, inc_list, msg_cnt, =);
  906. X    }
  907. X    /* Set SIGN and DO_FORTUNE now so we can turn them off later */
  908. X    if (do_set(set_options, "autosign"))
  909. X    turnon(flgs, SIGN);
  910. X    if (do_set(set_options, "fortune"))
  911. X    turnon(flgs, DO_FORTUNE);
  912. X    while (argv && *argv && *++argv && **argv == '-') {
  913. X    n = 1;
  914. X    while (n && argv[0][n])
  915. X        switch (argv[0][n]) {
  916. X#ifdef VERBOSE_ARG
  917. X        case 'v': turnon(flgs, VERBOSE); n++; break;
  918. X#endif /* VERBOSE_ARG */
  919. X        case 'H':
  920. X            if (argv[1]) {
  921. X            n = 0;
  922. X            Hfile = *++argv;
  923. X            } else {
  924. X            wprint("Must specify a file\n");
  925. X            return -1;
  926. X            }
  927. X        when 'h':
  928. X            if (argv[1]) {
  929. X            n = -1; /* it gets incremented below */
  930. X            hfile = savestr(*++argv);
  931. X            if (ison(glob_flags, REDIRECT)) {
  932. X                turnoff(glob_flags, REDIRECT);
  933. X                turnon(flgs, SEND_NOW);
  934. X            }
  935. X            } else {
  936. X            wprint("Must specify a file containing headers\n");
  937. X            return -1;
  938. X            }
  939. X            /* Fall through */
  940. X        case 'E': turnon(flgs, EDIT_HDRS); n++;
  941. X        when 'e': turnon(flgs, EDIT); n++;
  942. X        when 'F': turnon(flgs, DO_FORTUNE); n++;
  943. X        when 'b':
  944. X            if (argv[1]) {
  945. X            n = 0, bcc = *++argv;
  946. X            fix_up_addr(bcc);
  947. X            } else {
  948. X            wprint("Must specify blind-carbon list\n");
  949. X            return -1;
  950. X            }
  951. X        when 'c':
  952. X            if (argv[1]) {
  953. X            n = 0, addcc = *++argv;
  954. X            fix_up_addr(addcc);
  955. X            } else {
  956. X            wprint("Must specify carbon-copy list\n");
  957. X            return -1;
  958. X            }
  959. X        when 's':
  960. X            if (argv[1])
  961. X            n = 0, subj = *++argv;
  962. X            else
  963. X            n++, turnon(flgs, NEW_SUBJECT);
  964. X        when 'i': case 'I': case 'f': {
  965. X            int m;
  966. X            if (!msg_cnt) {
  967. X            wprint("No message to include!\n");
  968. X            return -1;
  969. X            }
  970. X            if (argv[0][n] == 'i') {
  971. X            turnon(flgs, INCLUDE);
  972. X            turnoff(flgs, INCLUDE_H);
  973. X            turnoff(flgs, FORWARD);
  974. X            } else if (argv[0][n] == 'I') {
  975. X            turnon(flgs, INCLUDE_H);
  976. X            turnoff(flgs, INCLUDE);
  977. X            turnoff(flgs, FORWARD);
  978. X            } else if (argv[0][n] == 'f') {
  979. X            turnon(flgs, FORWARD);
  980. X            turnon(flgs, SEND_NOW);
  981. X            turnoff(flgs, INCLUDE_H);
  982. X            turnoff(flgs, INCLUDE);
  983. X            }
  984. X            /* "-i 3-5" or "-i3-5"  Consider the latter case first */
  985. X            if (!argv[0][++n])
  986. X            argv++, n = 0;
  987. X            (*argv) += n;
  988. X            m = get_msg_list(argv, inc_list);
  989. X            (*argv) -= n;
  990. X            if (m == -1)
  991. X            return -1;
  992. X            /* if there were args, then go back to the first char
  993. X             * in the next argv
  994. X             */
  995. X            if (m)
  996. X            n = 0;
  997. X            if (!n) /* n may be 0 from above! */
  998. X            argv += (m-1);
  999. X        }
  1000. X        when 'U':
  1001. X            turnon(flgs, SEND_NOW);
  1002. X            n++;
  1003. X        when 'u':
  1004. X            turnoff(flgs, SIGN);
  1005. X            turnoff(flgs, DO_FORTUNE);
  1006. X            n++;
  1007. X        when 'r':
  1008. X            if (lower(firstchar) == 'r') {
  1009. X            route = *++argv;
  1010. X            n = 0;
  1011. X            break;
  1012. X            }
  1013. X            /* fall thru */
  1014. X        default:
  1015. X            if (argv[0][n] != '?') {
  1016. X            wprint("%c: unknown option\n\n", argv[0][n]);
  1017. X            return -1;
  1018. X            } else
  1019. X            return help(0, "mail", cmd_help);
  1020. X        }
  1021. X    }
  1022. X    if (isoff(flgs, FORWARD)) {
  1023. X    if (ison(flgs, SEND_NOW)) {
  1024. X        if (!hfile && !Hfile) {
  1025. X        wprint("Can't send immediately without draft file.\n");
  1026. X        return -1;
  1027. X        }
  1028. X        turnoff(flgs, EDIT); /* -U overrides -e */
  1029. X    } else if (do_set(set_options, "autoedit"))
  1030. X        turnon(flgs, EDIT);
  1031. X    } else if (ison(flgs, EDIT)) /* -e modifies -f */
  1032. X    turnoff(flgs, SEND_NOW);
  1033. X#ifdef VERBOSE_ARG
  1034. X    if (do_set(set_options, "verbose"))
  1035. X    turnon(flgs, VERBOSE);
  1036. X#endif /* VERBOSE_ARG */
  1037. X    *in_reply_to = *To = *Subject = *Cc = *Bcc = 0;
  1038. X    if (lower(firstchar) == 'r') {
  1039. X    char *in_reply_fmt, *pcc = NULL;
  1040. X    to = To, cc = Cc;
  1041. X    /*
  1042. X     * Generate a reply to all the messages passed to respond().  This
  1043. X     * list is different than the include-msg list above.  Get info about
  1044. X     * whom the messages were sent to for reply-all.
  1045. X     * BUG: currently, redundant addresses aren't pruned from Bcc list!
  1046. X     */
  1047. X    for (n = 0; n < msg_cnt; n++)
  1048. X        if (msg_bit(list, n)) {
  1049. X        if (to != To)
  1050. X            *to++ = ',', *to++ = ' ';
  1051. X        (void) reply_to(n, (firstchar == 'R'), buf);
  1052. X        if (strlen(buf) + (to - To) > sizeof(To) - 1) {
  1053. X            wprint("# recipients exceeded at msg %d\n", n);
  1054. X            break;
  1055. X        }
  1056. X        to += Strcpy(to, buf);
  1057. X        if (firstchar == 'R') {
  1058. X            if (pcc = cc_to(n, buf)) {
  1059. X            /* if there was a previous cc, append ", " */
  1060. X            if (cc != Cc)
  1061. X                *cc++ = ',', *cc++ = ' ';
  1062. X            if (strlen(pcc) + (cc - Cc) > sizeof(Cc) - 1)
  1063. X                wprint("# Cc's exceeded at msg %d\n", n);
  1064. X            else
  1065. X                cc += Strcpy(cc, pcc);
  1066. X            }
  1067. X        }
  1068. X        /* remove redundant addresses now, or headers could get too
  1069. X         * long before the list runs out (it still might)
  1070. X         */
  1071. X        rm_redundant_addrs(To, Cc);
  1072. X        to = To + strlen(To);
  1073. X        cc = Cc + strlen(Cc);
  1074. X        }
  1075. X    /* clean up end of Cc line for replyall's */
  1076. X    while (*cc == ' ' || *cc == ',')
  1077. X        *cc-- = '\0';
  1078. X    if (firstchar == 'R' && !do_set(set_options, "metoo")) {
  1079. X        /* Each reply_to() call above will leave at least
  1080. X         * one person in To.  If that one person was us,
  1081. X         * we need to get removed from the complete list.
  1082. X         */
  1083. X        (void) take_me_off(to);
  1084. X    }
  1085. X    to = To, cc = Cc;
  1086. X    if (route || (route = do_set(set_options, "auto_route")))
  1087. X        /* careful! This routine could add lots-o-bytes and lose addresses
  1088. X         * to avoid writing out of segment.
  1089. X         */
  1090. X        route_addresses(To, Cc, route);
  1091. X    if (in_reply_fmt = do_set(set_options, "in_reply_to"))
  1092. X        /* "9" here is a magic # --see compose_hdr() */
  1093. X        (void) strcpy(in_reply_to,
  1094. X                format_hdr(current_msg, in_reply_fmt, FALSE)+9);
  1095. X    }
  1096. X    if (ison(flgs, FORWARD) && ison(flgs, EDIT) ||
  1097. X        lower(firstchar) == 'r' && isoff(flgs, NEW_SUBJECT)) {
  1098. X    turnoff(flgs, NEW_SUBJECT);
  1099. X    if (subj && *subj && (isoff(flgs, FORWARD) || ison(flgs, EDIT)))
  1100. X        subj = strcpy(Subject, subj);
  1101. X    else if (subj = subject_to(current_msg, buf))
  1102. X        subj = strcpy(Subject, buf + 4*(lower(firstchar) != 'r'));
  1103. X    } else if (isoff(flgs, NEW_SUBJECT) && isoff(flgs, FORWARD) &&
  1104. X    (do_set(set_options, "ask") || do_set(set_options, "asksub")))
  1105. X    turnon(flgs, NEW_SUBJECT);
  1106. X    if (argv && *argv) {
  1107. X    char buf[HDRSIZ];
  1108. X    (void) argv_to_string(buf, argv);
  1109. X    fix_up_addr(buf);
  1110. X    to = &To[strlen(To)];
  1111. X    if (*To)
  1112. X        *to++ = ',', *to++ = ' ';
  1113. X    (void) strcpy(to, buf);
  1114. X    to = To;
  1115. X    }
  1116. X    if (addcc && *addcc) {
  1117. X    cc = &Cc[strlen(Cc)];
  1118. X    if (*Cc)
  1119. X        *cc++ = ',', *cc++ = ' ';
  1120. X    (void) strcpy(cc, addcc); /* addcc has already been fixed up */
  1121. X    cc = Cc;
  1122. X    }
  1123. X    /* remove any redundant addresses that just got added */
  1124. X    rm_redundant_addrs(To, Cc);
  1125. X    if (bcc && *bcc)
  1126. X    (void) strncpy(Bcc, bcc, sizeof(Bcc)); /* bcc already fixed up */
  1127. X    bcc = Bcc;
  1128. X
  1129. X    return mail_someone(to, subj, cc, bcc, flgs, inc_list);
  1130. X}
  1131. X
  1132. Xstatic
  1133. Xmail_someone(to, subject, cc, bcc, flgs, list)
  1134. Xregister char *to, *subject, *cc, *bcc, *list;
  1135. Xu_long flgs;
  1136. X{
  1137. X    register char *p;
  1138. X
  1139. X    flags = flgs;
  1140. X    if (to && *to) {
  1141. X    if (!*To)
  1142. X        (void) strncpy(To, to, sizeof(To));
  1143. X    } else
  1144. X    to = NO_STRING;
  1145. X    if (subject && *subject) {
  1146. X    if (!*Subject)
  1147. X        (void) strncpy(Subject, subject, sizeof(Subject));
  1148. X    } else
  1149. X    subject = NO_STRING;
  1150. X    if (cc && *cc) {
  1151. X    if (!*Cc)
  1152. X        (void) strncpy(Cc, cc, sizeof(Cc));
  1153. X    } else
  1154. X    Cc[0] = '\0';
  1155. X    if (bcc && *bcc) {
  1156. X    if (!*Bcc)
  1157. X        (void) strncpy(Bcc, bcc, sizeof(Bcc));
  1158. X    } else
  1159. X    Bcc[0] = '\0';
  1160. X
  1161. X    if (ison(glob_flags, REDIRECT)) {
  1162. X    /*
  1163. X     * NOTE: Could change this to finish_up_letter() to allow
  1164. X     * signatures to be appended.  The -U! option to mush would
  1165. X     * be extended to suppress signing when redirection is on.
  1166. X     */
  1167. X    int sent = send_it();
  1168. X    if (sent == -1) {
  1169. X        wprint("Message not sent!\n");
  1170. X        rm_edfile(-1);
  1171. X    }
  1172. X    return sent;
  1173. X    }
  1174. X    /* if (!*to) then prompting will be done */
  1175. X    if (!istool && !hfile) {
  1176. X    if (p = set_header("To: ", to, !*to)) {
  1177. X        if (!*to) /* if user typed To-line here, fix up the addresses */
  1178. X        fix_up_addr(p);
  1179. X        (void) strcpy(To, p);
  1180. X    }
  1181. X    if (!*To && ison(flags, FORWARD) && ison(flags, SEND_NOW)) {
  1182. X        turnoff(flags, SEND_NOW); /* user must edit To: line or do again */
  1183. X        print("(You must add a To: address.)\n");
  1184. X    }
  1185. X    /* don't prompt for subject if forwarding mail */
  1186. X    if (isoff(flags, FORWARD) && (*subject || ison(flags, NEW_SUBJECT)) &&
  1187. X        (p = set_header("Subject: ", subject,
  1188. X            !*subject && ison(flags, NEW_SUBJECT))))
  1189. X        (void) strcpy(Subject, p);
  1190. X    if (*Cc || ison(flags, EDIT_HDRS) && do_set(set_options, "askcc")) {
  1191. X        if ((p = set_header("Cc: ", cc, !*Cc)) && *p) {
  1192. X        fix_up_addr(p);
  1193. X        (void) strcpy(Cc, p);
  1194. X        }
  1195. X    }
  1196. X    if (*Bcc)
  1197. X        print("Bcc: %s\n", Bcc);
  1198. X    putchar('\n');
  1199. X    }
  1200. X
  1201. X    /* If forwarding w/o editing, start a new file for each. */
  1202. X    if (ison(flags, FORWARD) && ison(flags, SEND_NOW)) {
  1203. X    char fwd[MAXMSGS_BITS];
  1204. X    register int i;
  1205. X    clear_msg_list(fwd);
  1206. X    for (i = 0; i < msg_cnt; i++)
  1207. X        if (msg_bit(list, i)) {
  1208. X        set_msg_bit(fwd, i);
  1209. X        if (start_file(fwd) < 0)
  1210. X            return -1;
  1211. X        turnon(msg[i].m_flags, FORWARD);
  1212. X        if (isoff(glob_flags, READ_ONLY))
  1213. X            turnon(glob_flags, DO_UPDATE);
  1214. X        clear_msg_list(fwd);
  1215. X        }
  1216. X    } else
  1217. X    return start_file(list);
  1218. X    return 0;
  1219. X}
  1220. X
  1221. Xstatic
  1222. Xstart_file(list)
  1223. Xchar *list;
  1224. X{
  1225. X    register char  *dir;
  1226. X    register int   i;
  1227. X    char         line[MAXPATHLEN];
  1228. X    int           had_hfile = FALSE;
  1229. X
  1230. X    /* getdir() uses the home directory if no tmpdir */
  1231. X    if (!(dir = getdir(do_set(set_options, "tmpdir"))))
  1232. Xalted:
  1233. X    dir = ALTERNATE_HOME;
  1234. X    (void) mktemp(sprintf(line, "%s/%s", dir, EDFILE));
  1235. X    strdup(edfile, line);
  1236. X    if (!(ed_fp = mask_fopen(edfile, "w+"))) {
  1237. X    if (strcmp(dir, ALTERNATE_HOME))
  1238. X        goto alted;
  1239. X    error("can't create %s", edfile);
  1240. X    return -1;
  1241. X    }
  1242. X    if (!istool) {
  1243. X    oldint = signal(SIGINT, rm_edfile);
  1244. X    oldquit = signal(SIGQUIT, rm_edfile);
  1245. X    oldterm = signal(SIGTERM, rm_edfile);
  1246. X    }
  1247. X
  1248. X    if (istool && isoff(flags, SEND_NOW) ||
  1249. X        (isoff(flags, FORWARD) || isoff(flags, SEND_NOW)) &&
  1250. X        (ison(flags, EDIT_HDRS) || do_set(set_options, "edit_hdrs"))) {
  1251. X    turnon(flags, EDIT_HDRS);
  1252. X    if (hfile)
  1253. X        had_hfile = TRUE;
  1254. X    if (add_headers(NULL_FILE, &ed_fp, 1, flags) == (long) -1)
  1255. X        return -1;
  1256. X    }
  1257. X    if (Hfile) {
  1258. X    (void) file_to_fp(Hfile, ed_fp, "r");
  1259. X    Hfile = NULL;
  1260. X    had_hfile = TRUE;
  1261. X    }
  1262. X    if (istool && isoff(flags, SEND_NOW))
  1263. X    strdup(hfile, edfile);
  1264. X
  1265. X    /* if flags call for it, include current message (with header?) */
  1266. X    if (ison(flags, INCLUDE|FORWARD|INCLUDE_H)) {
  1267. X    long copy_flgs = 0, is_forw = ison(flags, FORWARD);
  1268. X    char buf[sizeof(To)];
  1269. X    if (!is_forw) {
  1270. X        turnon(copy_flgs, INDENT);
  1271. X        if (ison(flags, INCLUDE_H) &&
  1272. X            !chk_option("alwaysignore", "include"))
  1273. X        turnon(copy_flgs, NO_IGNORE);
  1274. X        else if (ison(flags, INCLUDE))
  1275. X        turnon(copy_flgs, NO_HEADER);
  1276. X    } else if (ison(flags, SEND_NOW) ||
  1277. X        !chk_option("alwaysignore", "forward"))
  1278. X        turnon(copy_flgs, FORWARD);    /* FORWARD implies NO_IGNORE */
  1279. X#ifdef MSG_SEPARATOR
  1280. X    turnon(copy_flgs, NO_SEPARATOR);
  1281. X#endif /* MSG_SEPARATOR */
  1282. X    for (i = 0; i < msg_cnt; i++)
  1283. X        if (msg_bit(list, i)) {
  1284. X        if (is_forw && isoff(flags, SEND_NOW)) {
  1285. X            (void) reply_to(i, FALSE, buf);
  1286. X            (void) fprintf(ed_fp,"--- Forwarded mail from %s\n\n",buf);
  1287. X        }
  1288. X        wprint("%sing message %d ...",
  1289. X            is_forw? "forward" : "includ", i+1);
  1290. X        wprint("(%d lines)\n",
  1291. X            copy_msg(i, ed_fp, (u_long) copy_flgs, NULL));
  1292. X        set_isread(i); /* if we included it, we read it, right? */
  1293. X        if (is_forw && isoff(flags, SEND_NOW))
  1294. X            (void) fprintf(ed_fp,
  1295. X            "\n--- End of forwarded message from %s\n", buf);
  1296. X        if (!is_forw || isoff(flags, SEND_NOW))
  1297. X            (void) fputc('\n', ed_fp);
  1298. X        }
  1299. X    (void) fflush(ed_fp);
  1300. X    }
  1301. X    if (!istool && ison(glob_flags, WARNING)) {
  1302. X    if (escape && strncmp(escape, DEF_ESCAPE, 1))
  1303. X        print("(escape character is set to `%c')\n", *escape);
  1304. X    if (wrapcolumn && wrapcolumn < 20)
  1305. X        print("(warning: wrapping only %d columns from the left!)\n",
  1306. X            wrapcolumn);
  1307. X    }
  1308. X
  1309. X    /* do an "if" again in case editor not found and EDIT turned off */
  1310. X    if (!istool && ison(flags, EDIT)) {
  1311. X    char **argv, *edit;
  1312. X    int argc;
  1313. X    if ((!(edit = do_set(set_options, "visual")) || !*edit) &&
  1314. X        (!(edit = do_set(set_options, "editor")) || !*edit))
  1315. X        edit = DEF_EDITOR;
  1316. X    (void) sprintf(line, "%s %s", edit, edfile);
  1317. X    if ((argv = mk_argv(line, &argc, FALSE)) && argc > 0) {
  1318. X        print("Starting \"%s\"...\n", argv[0]);
  1319. X        (void) fclose(ed_fp);
  1320. X        ed_fp = NULL_FILE;
  1321. X        execute(argv);
  1322. X        free_vec(argv);
  1323. X        turnoff(flags, EDIT);
  1324. X        turnoff(flags, FORWARD); /* forwarded messages must be unedited */
  1325. X        /* upon exit of editor, user must now type eofc or "." to send */
  1326. X        if (!(ed_fp = fopen(edfile, "r+"))) {
  1327. X        error("can't reopen %s", edfile);
  1328. X        return -1;
  1329. X        }
  1330. X        (void) fseek(ed_fp, 0L, 2);
  1331. X    } else
  1332. X        print("Unable to start \"%s\"\n", edit);
  1333. X    wprint("(continue editing letter or ^%c to send)\n", eofc + '@');
  1334. X    } else if (ison(flags, SEND_NOW)) {
  1335. X    /* if finish_up_letter() was successful, file was successfully sent. */
  1336. X    if (!setjmp(cntrl_c_buf) && finish_up_letter() == 0) {
  1337. X        rm_edfile(0);
  1338. X        return 0;
  1339. X    }
  1340. X    } else if (had_hfile) {
  1341. X    /* it's not obvious what's going on -- enlighten user */
  1342. X    wprint("(continue editing or ^%c to send)\n", eofc + '@');
  1343. X    }
  1344. X
  1345. X#ifdef SUNTOOL
  1346. X    if (istool) {
  1347. X    /* toolmode doesn't care if SEND_NOW -- user continues to edit file.
  1348. X     * if SEND_NOW is not set, then the editor file has just been started,
  1349. X     * so again, just return so user can edit file.
  1350. X     */
  1351. X    if (ed_fp)
  1352. X        fclose(ed_fp), ed_fp = NULL_FILE;
  1353. X    turnon(glob_flags, IS_GETTING);
  1354. X    return 0;
  1355. X    }
  1356. X#endif /* SUNTOOL */
  1357. X    if (ison(flags, SEND_NOW)) {
  1358. X    /* editing couldn't have been on -- finish_up_letter() failed */
  1359. X    rm_edfile(0 - ison(flags, FORWARD));
  1360. X    return -1;
  1361. X    }
  1362. X
  1363. X    i = 0;
  1364. X    turnon(glob_flags, IS_GETTING);
  1365. X    do  {
  1366. X    /* If the user hits ^C in cbreak mode, mush will return to
  1367. X     * Getstr and not clear the buffer. whatever is typed next will
  1368. X     * be appended to the line.  jumping here will force the line to
  1369. X     * be cleared cuz it's a new call.
  1370. X     */
  1371. X    (void) setjmp(cntrl_c_buf);
  1372. X    while (Getstr(line, sizeof(line), 0) > -1) {
  1373. X        if (!istool) /* toolmode checks on a timer -- don't do it here */
  1374. X        (void) check_new_mail(); /* if new mail comes in, get it */
  1375. X        if ((i = add_to_letter(line)) <= 0)
  1376. X        break;
  1377. X    }
  1378. X    } while (i >= 0 && finish_up_letter() == -1);
  1379. X    turnoff(glob_flags, IS_GETTING);
  1380. X    return i; /* return -1 if ~x or ~q to terminate letter */
  1381. X}
  1382. X
  1383. Xchar *tilde_commands[] = {
  1384. X    "commands: [OPTIONAL argument]",
  1385. X    "t [list]\tChange list of recipients",
  1386. X    "s [subject]\tModify [set] subject header",
  1387. X    "c [cc list]\tModify [set] carbon copy recipients",
  1388. X    "b [bcc list]\tModify [set] blind carbon recipients",
  1389. X    "h\t\tModify all message headers",
  1390. X    "e [editor]\tEnter editor. Editor used: \"set editor\", env EDITOR, vi",
  1391. X    "v [editor]\tEnter visual editor. \"set visual\", env VISUAL, vi",
  1392. X    "u\t\tEdit previous (last) line in file.",
  1393. X    "p [pager]\tPage message; pager used: \"set pager\", env. PAGER, more",
  1394. X    "i [msg#'s]\tInclude current msg body [msg#'s] indented by \"indent_str\"",
  1395. X    "I [msg#'s]\tSame, but include the message headers from included messages",
  1396. X    "f [msg#'s]\tForward mail. Not indented, but marked as \"forwarded mail\"",
  1397. X    "S[!]\t\tInclude Signature file [suppress file]",
  1398. X    "F[!]\t\tAdd a fortune at end of letter [don't add]",
  1399. X    "w file\t\tWrite msg buffer to file name",
  1400. X    "a file\t\tAppend msg buffer to file name",
  1401. X    "r file\t\tRead filename into message buffer",
  1402. X    "q \t\tQuit message; save in dead.letter (unless \"nosave\" is set).",
  1403. X    "x \t\tQuit message; don't save in dead.letter.",
  1404. X    "$variable\tInsert the string value for \"variable\" into message.",
  1405. X    ":cmd\t\tRun the mail command \"cmd\".",
  1406. X    "|cmd\t\tPipe the message through the unix command \"cmd\".",
  1407. X    "E[!]\t\tClear contents of letter after saving to dead.letter [unless !].",
  1408. X    0
  1409. X};
  1410. X
  1411. X/*
  1412. X * TC_EDIT(tc) returns TRUE if tilde_command[tc] involves message
  1413. X * editing operations.  Used when EDIT_HDRS is active.
  1414. X */
  1415. X#define TC_EDIT(tc) ((tc) && ((tc) < 6 || !tilde_commands[(tc)+1]))
  1416. X
  1417. X/*
  1418. X * Add the line (char *) parameter to the letter.  Determine tilde
  1419. X * escapes and determine what to do.  This function returns 0 to
  1420. X * indicate user wants to end the letter, -1 if the letter cannot
  1421. X * be sent (~q, ~x no buffer after editor, etc...) or 1 to indicate
  1422. X * successful addition of the line to the letter.
  1423. X * This function may be called by toolmode just to change certain mush
  1424. X * internal variables via tilde escapes.  Thus, ed_fp might be null.
  1425. X */
  1426. Xadd_to_letter(line)
  1427. Xchar line[];
  1428. X{
  1429. X    register char *p;
  1430. X    char buf[HDRSIZ > MAXPATHLEN ? HDRSIZ : MAXPATHLEN];
  1431. X
  1432. X    killme = 0;
  1433. X    if (ed_fp) /* may be null if istool */
  1434. X    (void) fseek(ed_fp, 0L, 2);
  1435. X
  1436. X    if (!strcmp(line, ".") && do_set(set_options, "dot"))
  1437. X    return 0;
  1438. X    if (line[0] != *escape) {
  1439. X    (void) fputs(line, ed_fp);
  1440. X    (void) fputc('\n', ed_fp);
  1441. X    (void) fflush(ed_fp);
  1442. X    return 1;
  1443. X    }
  1444. X    /* all commands are "~c" (where 'c' is the command). set p = first
  1445. X     * character after 'c' and skip whitespace
  1446. X     */
  1447. X    p = &line[2];
  1448. X    skipspaces(0);
  1449. X    switch (line[1]) {
  1450. X    case 'v' : case 'p': case 'e' : case '|' : {
  1451. X        if (!*p || *p == 'i')
  1452. X        switch (line[1]) {
  1453. X            case 'p' :
  1454. X            if (!*p && !(p = do_set(set_options, "pager")))
  1455. X                p = DEF_PAGER;
  1456. X            if (!*p || !strcmp(p, "internal"))
  1457. X                p = NULL;
  1458. X            when 'v' :
  1459. X            if (*p && p[1] || (p = do_set(set_options, "visual")))
  1460. X                break;
  1461. X            /* else fall through */
  1462. X            default :
  1463. X            if (!(p = do_set(set_options, "editor")) || !*p)
  1464. X                p = DEF_EDITOR;
  1465. X            when '|' :
  1466. X            print("No command for pipe\n");
  1467. X            return 1;
  1468. X        }
  1469. X        if (line[1] == 'p' || line[1] == '|')
  1470. X        rewind(ed_fp);
  1471. X        if (line[1] == 'p') {
  1472. X        (void) do_pager(p, TRUE); /* start the pager "p" */
  1473. X        if (isoff(flags, EDIT_HDRS)) {
  1474. X            (void) do_pager(sprintf(buf, "To: %s\n", To), FALSE);
  1475. X            if (Subject[0])
  1476. X            (void) do_pager(sprintf(buf, "Subject: %s\n", Subject),
  1477. X                    FALSE);
  1478. X            if (Cc[0])
  1479. X            (void) do_pager(sprintf(buf, "Cc: %s\n", Cc), FALSE);
  1480. X            if (Bcc[0])
  1481. X            (void) do_pager(sprintf(buf, "Bcc: %s\n", Bcc), FALSE);
  1482. X            (void) do_pager(strcpy(buf,
  1483. X                        "--------\nMessage contains:\n"),
  1484. X            FALSE);
  1485. X        }
  1486. X        while (fgets(buf, sizeof(buf), ed_fp))
  1487. X            if (do_pager(buf, FALSE) == EOF)
  1488. X            break;
  1489. X        (void) do_pager(NULL, FALSE); /* end pager */
  1490. X        } else if (line[1] == '|') {
  1491. X        FILE *pipe_fp;
  1492. X        (void) sprintf(buf, "( %s ) > %s", p, edfile);
  1493. X        if (unlink(edfile) < 0) {
  1494. X            error("Can't unlink %s:", edfile);
  1495. X            break; /* Drop out of switch */
  1496. X        }
  1497. X        if ((pipe_fp = popen(buf, "w")) == NULL_FILE) {
  1498. X            error("Can't run \"%s\":", p);
  1499. X            (void) file_to_fp(edfile, ed_fp, "w");
  1500. X        } else {
  1501. X            while (fgets(buf, sizeof(buf), ed_fp))
  1502. X            if (fputs(buf, pipe_fp) == EOF) {
  1503. X                print("Broken pipe\n");
  1504. X                break;
  1505. X            }
  1506. X            (void) pclose(pipe_fp);
  1507. X        }
  1508. X        pipe_fp = ed_fp; /* save ed_fp until we can reopen it */
  1509. X        if (!(ed_fp = fopen(edfile, "r+"))) {
  1510. X            error("can't reopen %s", edfile);
  1511. X            (void) rewind(pipe_fp);
  1512. X            if (file_to_fp(edfile, pipe_fp, "w") < 0 ||
  1513. X                !(ed_fp = fopen(edfile, "r+"))) {
  1514. X            error("can't restore old contents of %s", edfile);
  1515. X            ed_fp = pipe_fp;
  1516. X            dead_letter(0);
  1517. X            return -1;
  1518. X            }
  1519. X        }
  1520. X        (void) fclose(pipe_fp);
  1521. X        } else {
  1522. X        char **argv;
  1523. X        int argc;
  1524. X        (void) sprintf(buf, "%s %s", p, edfile);
  1525. X        if ((argv = mk_argv(buf, &argc, FALSE)) && argc > 0) {
  1526. X            (void) fclose(ed_fp);
  1527. X            ed_fp = NULL_FILE;
  1528. X            execute(argv);
  1529. X            free_vec(argv);
  1530. X            /* tool will return even tho editor isn't done */
  1531. X            if (!(ed_fp = fopen(edfile, "r+"))) {
  1532. X            error("can't reopen %s", edfile);
  1533. X            return -1;
  1534. X            }
  1535. X        } else
  1536. X            print("Unable to start \"%s\"\n", p);
  1537. X        }
  1538. X    }
  1539. X    when '$': {
  1540. X        register char *p2;
  1541. X        if (!(p2 = do_set(set_options, p)))
  1542. X        print("(%s isn't set)\n", p);
  1543. X        else
  1544. X        putstring(p2, ed_fp);
  1545. X    }
  1546. X    when ':': {
  1547. X        char new[MAXMSGS_BITS];
  1548. X        u_long save_flags = glob_flags;
  1549. X
  1550. X        turnon(glob_flags, IGN_SIGS);
  1551. X        turnoff(glob_flags, DO_PIPE);
  1552. X        turnoff(glob_flags, IS_PIPE);
  1553. X        (void) cmd_line(p, new);
  1554. X        glob_flags = save_flags;
  1555. X    }
  1556. X    when 'i': case 'f': case 'I': case 'm': {
  1557. X        int  n;
  1558. X        u_long copy_flgs = 0;
  1559. X        char list[MAXMSGS_BITS];
  1560. X
  1561. X        if (!msg_cnt) {
  1562. X        wprint("No messages.\n");
  1563. X        break;
  1564. X        }
  1565. X        clear_msg_list(list);
  1566. X        if (line[1] != 'f') {
  1567. X        turnon(copy_flgs, INDENT);
  1568. X        if (line[1] == 'i')
  1569. X            turnon(copy_flgs, NO_HEADER);
  1570. X        else if (!chk_option("alwaysignore", "include"))
  1571. X            turnon(copy_flgs, NO_IGNORE);
  1572. X         } else if (!chk_option("alwaysignore", "forward"))
  1573. X        turnon(copy_flgs, NO_IGNORE);
  1574. X#ifdef MSG_SEPARATOR
  1575. X        turnon(copy_flgs, NO_SEPARATOR);
  1576. X#endif /* MSG_SEPARATOR */
  1577. X        if (!*p)
  1578. X        set_msg_bit(list, current_msg);
  1579. X        else if (!do_range(p, list))
  1580. X        return 1;
  1581. X        for (n = 0; n < msg_cnt; n++)
  1582. X        if (msg_bit(list, n)) {
  1583. X            if (line[1] == 'f') {
  1584. X            (void) reply_to(n, FALSE, buf);
  1585. X            (void) fprintf(ed_fp,
  1586. X                    "--- Forwarded mail from %s\n\n", buf);
  1587. X            }
  1588. X            wprint("Including message %d ... ", n+1);
  1589. X            wprint("(%d lines)\n", copy_msg(n, ed_fp, copy_flgs, NULL));
  1590. X            set_isread(n);
  1591. X            if (line[1] == 'f')
  1592. X            (void) fprintf(ed_fp,
  1593. X                "\n--- End of forwarded message from %s\n\n", buf);
  1594. X            else
  1595. X            (void) fputc('\n', ed_fp);
  1596. X        }
  1597. X    }
  1598. X    /* To: Cc: and Bcc: headers */
  1599. X    when 'b':
  1600. X    case 't':
  1601. X    case 'c': {
  1602. X        char *h = (line[1] == 't')? To : (line[1] == 'c')? Cc : Bcc;
  1603. X        char *Prompt = line[1] == 't'? "To: " :
  1604. X               line[1] == 'c'? "Cc: " : "Bcc: ";
  1605. X        if (ison(flags, EDIT_HDRS)) {
  1606. X        print("You must use an editor to change your headers.\n");
  1607. X        break;
  1608. X        }
  1609. X
  1610. X        if (*p) {
  1611. X        fix_up_addr(p);
  1612. X        if (*h)
  1613. X            (void) sprintf(h+strlen(h), ", %s", p);
  1614. X        else
  1615. X            (void) strcpy(h, p);
  1616. X        } else if (!(p = set_header(Prompt, h, TRUE)) || !*p)
  1617. X        *h = 0;
  1618. X        else {
  1619. X        fix_up_addr(p);
  1620. X        (void) strcpy(h, p);
  1621. X        }
  1622. X    }
  1623. X    when 's':
  1624. X        if (ison(flags, EDIT_HDRS)) {
  1625. X        print("You must use an editor to change your headers.\n");
  1626. X        break;
  1627. X        }
  1628. X        if (*p || (p = set_header("Subject: ", Subject, 1)))
  1629. X        if (!*p)
  1630. X            Subject[0] = 0;
  1631. X        else
  1632. X            (void) strcpy(Subject, p);
  1633. X    when 'h':
  1634. X        if (ison(flags, EDIT_HDRS)) {
  1635. X        print("You must use an editor to change your headers.\n");
  1636. X        break;
  1637. X        }
  1638. X        while ((p = set_header("To: ", To, 1)) && !*p)
  1639. X        print("(There must be a recipient.)\n");
  1640. X        (void) strcpy(To, p);
  1641. X        if (p = set_header("Subject: ", Subject, 1))
  1642. X        if (!*p)
  1643. X            Subject[0] = 0;
  1644. X        else
  1645. X            (void) strcpy(Subject, p);
  1646. X        if (p = set_header("Cc: ", Cc, 1))
  1647. X        if (!*p)
  1648. X            Cc[0] = 0;
  1649. X        else {
  1650. X            fix_up_addr(p);
  1651. X            (void) strcpy(Cc, p);
  1652. X        }
  1653. X        if (p = set_header("Bcc: ", Bcc, 1))
  1654. X        if (!*p)
  1655. X            Bcc[0] = 0;
  1656. X        else {
  1657. X            fix_up_addr(p);
  1658. X            (void) strcpy(Bcc, p);
  1659. X        }
  1660. X    when 'F': case 'S' : {
  1661. X        if (*p == '!')
  1662. X        turnoff(flags, line[1] == 'F'? DO_FORTUNE : SIGN);
  1663. X        else
  1664. X        turnon(flags, line[1] == 'F'? DO_FORTUNE : SIGN);
  1665. X        wprint("%sadding %s at end of message.\n", *p == '!'? "not " : "",
  1666. X        line[1] == 'F'? "fortune" : "signature");
  1667. X    }
  1668. X    when 'w': case 'a': case 'r':
  1669. X        if (!*p) {
  1670. X        print("(you must specify a filename)\n");
  1671. X        return 1;
  1672. X        }
  1673. X        (void) fseek(ed_fp, 0L, 2); /* append */
  1674. X        (void) file_to_fp(p, ed_fp, (line[1] == 'r')? "r":
  1675. X                  (line[1] == 'w')? "w": "a");
  1676. X    /* go up one line in the message file and allow the user to edit it */
  1677. X    when 'u': {
  1678. X        long newpos, pos = ftell(ed_fp);
  1679. X        char oldline[256];
  1680. X        if (pos <= 0L) { /* pos could be -1 if ftell() failed */
  1681. X        print("(No previous line in file.)\n");
  1682. X        return 1;
  1683. X        }
  1684. X        /* get the last 256 bytes written and read backwards from the
  1685. X         * current place until '\n' is found. Start by moving past the
  1686. X         * first \n which is at the end of the line we want to edit
  1687. X         */
  1688. X        newpos = max(0, pos - 256L);
  1689. X        (void) fseek(ed_fp, newpos, L_SET);
  1690. X        /* don't fgets -- it'll stop at a \n */
  1691. X        (void) fread(line, sizeof(char), (int)(pos-newpos), ed_fp);
  1692. X        pos--;
  1693. X        /* the last char in line should be a \n cuz it was last input */
  1694. X        if (line[(int)(pos-newpos)] != '\n')
  1695. X        print("I don't know how, but your last line ended with %c.\n",
  1696. X            line[(int)(pos-newpos)]);
  1697. X        else
  1698. X        line[(int)(pos-newpos)] = 0; /* null terminate \n for ^H-ing */
  1699. X        for (pos--; pos > newpos && line[(int)(pos-newpos)] != '\n'; pos--)
  1700. X        ;
  1701. X        /* we've gone back to the end of the second previous line. Check
  1702. X         * to see if the char we're pointing to is a \n.  It should be, but
  1703. X         * if it's not, we moved back to the first line of the file.
  1704. X         */
  1705. X        if (line[(int)(pos-newpos)] == '\n')
  1706. X        ++pos;
  1707. X        /* save the old line that's there in case the user boo-boos */
  1708. X        (void) strcpy(oldline, &line[(int)(pos-newpos)]);
  1709. X        /* let set header print out the line and get the input */
  1710. X        if (!(p = set_header("", &line[(int)(pos-newpos)], TRUE))) {
  1711. X        print("Something bad happened and I don't know what it is.\n");
  1712. X        p = oldline;
  1713. X        } else if (*p == *escape)
  1714. X        print("(Warning: %c escapes ignored on %cu lines.)\n",
  1715. X                *escape, *escape);
  1716. X        /* seek to to the position where the new line will go */
  1717. X        (void) fseek(ed_fp, pos, L_SET);
  1718. X        /* put the newly typed line */
  1719. X        (void) fputs(p, ed_fp); /* don't add \n. padding may be necessary */
  1720. X        /* if the new line is less than the old line, we're going to do
  1721. X         * one of two things.  The best thing to do is to truncate the
  1722. X         * file to the end of the new line.  Sys-v can't do that, so we
  1723. X         * pad the line with blanks.  May be messy in some cases, but...
  1724. X         */
  1725. X        if ((pos = strlen(p) - strlen(oldline)) < 0) {
  1726. X#ifndef SYSV
  1727. X        /* add the \n, flush the file, truncate to the current pos */
  1728. X        (void) fputc('\n', ed_fp);
  1729. X        (void) fflush(ed_fp);
  1730. X        (void) ftruncate(fileno(ed_fp), (off_t) ftell(ed_fp));
  1731. X#else /* SYSV */
  1732. X        /* pad with blanks to the length of the old line. add \n */
  1733. X        while (pos++ < 0)
  1734. X            (void) fputc(' ', ed_fp);
  1735. X        (void) fputc('\n', ed_fp), (void) fflush(ed_fp);
  1736. X#endif /* SYSV */
  1737. X        } else {
  1738. X        /* the new line is >= the old line, add \n -- no trunc req. */
  1739. X            (void) fputc('\n', ed_fp);
  1740. X        (void) fflush(ed_fp);
  1741. X        }
  1742. X        return 1;
  1743. X     }
  1744. X    /* break;  not here cuz of "return" (lint). */
  1745. X    case 'E':
  1746. X        if (ison(flags, EDIT_HDRS)) {
  1747. X        print("You must use an editor to empty the message buffer.\n");
  1748. X        break;
  1749. X        }
  1750. X        if (*p != '!' && !do_set(set_options, "nosave"))
  1751. X        dead_letter(0);
  1752. X        if (emptyfile(&ed_fp, edfile) == -1)
  1753. X        error(edfile);
  1754. X        else
  1755. X        print("Message buffer empty\n");
  1756. X    when 'q':
  1757. X        /* save in dead.letter if nosave not set -- rm_edfile(-2). */
  1758. X        rm_edfile(-2); /* doesn't return out of tool mode */
  1759. X        return -1;
  1760. X        /* break; not stated cuz of "return" (lint) */
  1761. X    case 'x':
  1762. X        /* don't save dead.letter -- simulate normal rm_edfile() call */
  1763. X        rm_edfile(0);
  1764. X        return -1;
  1765. X        /* break; (not specified for lint) */
  1766. X    default:
  1767. X        if (line[1] == *escape) {
  1768. X        (void) fputs(&line[1], ed_fp);
  1769. X        (void) fputc('\n', ed_fp);
  1770. X        (void) fflush(ed_fp);
  1771. X        return 1;
  1772. X        } else if (line[1] == '?') {
  1773. X        register int x;
  1774. X        (void) do_pager(NULL, TRUE); /* start pager */
  1775. X        for (x = 0; tilde_commands[x]; x++) {
  1776. X            if (ison(flags, EDIT_HDRS) && TC_EDIT(x))
  1777. X            continue;
  1778. X            (void) sprintf(buf, "%s%s\n", escape, tilde_commands[x]);
  1779. X            if (do_pager(buf, FALSE) == EOF)
  1780. X            break;
  1781. X        }
  1782. X        if (tilde_commands[x] == NULL) {
  1783. X            (void) sprintf(buf,
  1784. X            "%s%s\t\tBegin a line with a single %s\n",
  1785. X            escape, escape, escape);
  1786. X            (void) do_pager(buf, FALSE);
  1787. X        }
  1788. X        (void) do_pager(NULL, FALSE); /* end pager */
  1789. X        } else
  1790. X        print("`%c': unknown %c escape. Use %c? for help.\n",
  1791. X            line[1], *escape, *escape);
  1792. X        return 1;
  1793. X    }
  1794. X    if (ed_fp)
  1795. X    (void) fseek(ed_fp, 0L, 2);
  1796. X    if (!istool)
  1797. X    wprint("(continue editing letter)\n");
  1798. X    return 1;
  1799. X}
  1800. X
  1801. X/*
  1802. X * finish up the letter. ask for the cc line, if verify is set, ask to
  1803. X * verify sending, continue editing, or to dump the whole idea.
  1804. X * Then check for signature and fortune.  Finally, pass it to send_it()
  1805. X * to actually send it off.
  1806. X * Return 0 on success, -1 on failure.
  1807. X */
  1808. Xstatic int
  1809. Xfinish_up_letter()
  1810. X{
  1811. X    register char *p;
  1812. X    int c;
  1813. X    char buf[MAXPATHLEN];
  1814. X
  1815. X    /* forwarded mail has no additional personalized text */
  1816. X    if (ison(flags, FORWARD)) {
  1817. X    if (send_it() == -1) {
  1818. X        wprint("Message not sent!\n");
  1819. X        return -1;
  1820. X    }
  1821. X    turnoff(glob_flags, IS_GETTING);
  1822. X    return 0;
  1823. X    }
  1824. X
  1825. X    /* REDIRECT should never be on here, but just in case */
  1826. X    if (isoff(glob_flags, REDIRECT)) {
  1827. X    if (!istool) {
  1828. X        if (isoff(flags, EDIT_HDRS) && do_set(set_options, "askcc")) {
  1829. X        if (p = set_header("Cc: ", Cc, 1))
  1830. X            (void) strcpy(Cc, p);
  1831. X        }
  1832. X    }
  1833. X    /* ~v on the Cc line asks for verification, first initialize p! */
  1834. X    p = NULL;
  1835. X    if (!strncmp(Cc, "~v", 2) || (p = do_set(set_options, "verify"))) {
  1836. X        if (!p) /* so we don't Cc to ~v! */
  1837. X        *Cc = 0;
  1838. X        for (;;) {
  1839. X#ifdef SUNTOOL
  1840. X        if (istool)
  1841. X            c = (ask("Send Message?") == TRUE)? 's' : 'c';
  1842. X        else
  1843. X#endif /* SUNTOOL */
  1844. X        {
  1845. X            print("send, continue editing, discard [s,c,d]? ");
  1846. X            c = Getstr(buf, sizeof(buf), 0);
  1847. X            if (c < 0)
  1848. X            putchar('\n');
  1849. X            else if (!istool)
  1850. X            c = lower(*buf);
  1851. END_OF_FILE
  1852. if test 30778 -ne `wc -c <'mush/mail.c.a'`; then
  1853.     echo shar: \"'mush/mail.c.a'\" unpacked with wrong size!
  1854. fi
  1855. # end of 'mush/mail.c.a'
  1856. fi
  1857. echo shar: End of archive 9 \(of 19\).
  1858. cp /dev/null ark9isdone
  1859. MISSING=""
  1860. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1861.     if test ! -f ark${I}isdone ; then
  1862.     MISSING="${MISSING} ${I}"
  1863.     fi
  1864. done
  1865. if test "${MISSING}" = "" ; then
  1866.     echo You have unpacked all 19 archives.
  1867.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1868. else
  1869.     echo You still need to unpack the following archives:
  1870.     echo "        " ${MISSING}
  1871. fi
  1872. ##  End of shell archive.
  1873. exit 0
  1874.  
  1875.