home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mush.lzh / mush.9 < prev    next >
Encoding:
Text File  |  1990-05-06  |  54.9 KB  |  1,868 lines

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