home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume11 / mush5.7 / part10 / mail.c
Encoding:
C/C++ Source or Header  |  1987-09-19  |  34.8 KB  |  1,182 lines

  1. /* @(#)mail.c     (c) copyright 1986 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4.  
  5. /*
  6.  * mail.c --
  7.  *    do_mail()     invoked from within mail.  see function for description.
  8.  *    abort_mail()    suntools specific: resets panel items and so forth.
  9.  *    start_file()      creates the editing file and reset signal catching.
  10.  *    mail_someone()    called from do_mail() or from the shell.
  11.  *    add_to_letter()    adds the next line to letter --determine ~ escapes.
  12.  *    finish_up_letter()  prompts for Cc:, verifies user really wants to send
  13.  *    send_it()        invokes mailer, sends to record file, adds signature,
  14.  *            fortune, expands aliases, adds own_hdrs.
  15.  *    rm_edfile()    signals are directed here. remove letter, longjmp
  16.  *
  17.  * The flow of control in this file is NOT obvious to allow for both text
  18.  * and suntools _event driven_ attributes.  In text, the flow is far more
  19.  * obvious because it is sequential. In suntools, each function is called
  20.  * from outside this modual.  Keystrokes are interpreted individually and
  21.  * queued up in "rite.c".  select.c calls add_to_letter when a \n is entered
  22.  * passing the string stored in rite.c.  If you're trying to follow the flow
  23.  * of control for suntools, keep the event drivers in mind and follow select.c
  24.  * and rite.c
  25.  */
  26. #define TO_FIELD    1
  27. #define SUBJECT        2
  28. #define CC_FIELD    3
  29. #define BC_FIELD    4
  30.  
  31. static char Subject[BUFSIZ], To[BUFSIZ], Cc[BUFSIZ], Bcc[BUFSIZ];
  32. static char edfile[MAXPATHLEN], in_reply_to[256];
  33. static int killme, in_editor;
  34. static long flags;
  35. static int (*oldhup)(), (*oldterm)(), (*oldint)(), (*oldquit)();
  36. static void send_it();
  37. static FILE *fp;
  38. static jmp_buf cntrl_c_buf;
  39.  
  40. /* argc, and argv could be null if coming from compose */
  41. do_mail(n, argv)
  42. register int n;   /* no need for "argc", so use the space for a variable */
  43. register char **argv;
  44. {
  45.     char firstchar = (argv)? **argv: 'm';
  46.     char list[MAXMSGS_BITS];
  47.     register char *to = NULL, *cc = NULL, *subj = NULL;
  48.     register int flgs = 0;
  49.  
  50.     if (ison(glob_flags, IS_GETTING)) {
  51.     print("You must finish the letter you are editing first.\n");
  52.     return -1;
  53.     }
  54.     turnon(flgs, NO_IGNORE); /* if we include a message, include all hdrs */
  55.  
  56.     clear_msg_list(list);
  57.     if (do_set(set_options, "autoedit"))
  58.     turnon(flgs, EDIT);
  59. #ifdef VERBOSE_ARG
  60.     if (do_set(set_options, "verbose"))
  61.     turnon(flgs, VERBOSE);
  62. #endif VERBOSE_ARG
  63.     if (do_set(set_options, "autosign"))
  64.     turnon(flgs, SIGN);
  65.     if (lower(firstchar) == 'r' && do_set(set_options, "autoinclude"))
  66.     turnon(flgs, INCLUDE), set_msg_bit(list, current_msg);
  67.     while (argv && *argv && *++argv && **argv == '-') {
  68.     n = 1;
  69.     while (n && argv[0][n])
  70.         switch (argv[0][n]) {
  71. #ifdef VERBOSE_ARG
  72.         case 'v': turnon(flgs, VERBOSE); n++; break;
  73. #endif VERBOSE_ARG
  74.         case 'e': turnon(flgs, EDIT); n++;
  75.         when 'F': turnon(flgs, DO_FORTUNE); n++;
  76.         when 'i': case 'h': case 'f': {
  77.             int m;
  78.             if (!msg_cnt) {
  79.             print("No message to include!\n");
  80.             return -1;
  81.             }
  82.             if (argv[0][n] == 'i')
  83.             turnon(flgs, INCLUDE);
  84.             else if (argv[0][n] == 'h')
  85.             turnon(flgs, INCLUDE_H);
  86.             else if (argv[0][n] == 'f')
  87.             turnon(flgs, FORWARD);
  88.             /* "-i 3-5" or "-i3-5"  Consider the latter case first */
  89.             if (!argv[0][++n])
  90.             argv++, n = 0;
  91.             (*argv) += n;
  92.             m = get_msg_list(argv, list);
  93.             (*argv) -= n;
  94.             if (m == -1)
  95.             return -1;
  96.             /* if there were args, then go back to the first char
  97.              * in the next argv
  98.              */
  99.             if (m)
  100.             n = 0;
  101.             if (!n) /* n may be 0 from above! */
  102.             argv += (m-1);
  103.         }
  104.         otherwise:
  105.             if (argv[0][n] != '?')
  106.             wprint("%c: unknown option\n", argv[0][n]);
  107.             wprint("available options\n");
  108. #ifdef VERBOSE_ARG
  109.             wprint("v      verbose (passed to mail delivery system)\n");
  110. #endif VERBOSE_ARG
  111.             wprint("e      immediately enter editor (autoedit)\n");
  112.             wprint("F      add fortune to the end of message.\n");
  113.             wprint("i [msg#'s]   include msg_list into letter.\n");
  114.             wprint("h [msg#'s]   include msg_list with headers.\n");
  115.             wprint("f [msg#'s]   forward msg_list (not indented).\n");
  116.             return -1;
  117.         }
  118.     }
  119.     *in_reply_to = *To = *Subject = *Cc = *Bcc = 0;
  120.     if (lower(firstchar) == 'r') {
  121.     char buf[BUFSIZ], *p;
  122.     to = reply_to(current_msg, (firstchar == 'R'), To);
  123.     if (firstchar == 'R') {
  124.         cc = cc_to(current_msg, Cc);
  125.         if (do_set(set_options, "fixaddr"))
  126.         fix_addresses(To, Cc);
  127.     }
  128.     subj = subject_to(current_msg, Subject);
  129.     if (do_set(set_options, "in_reply_to")) {
  130.         (void) reply_to(current_msg, FALSE, buf);
  131.         (void) sprintf(in_reply_to, "Message from %s", buf);
  132.         if (p = header_field(current_msg, "date"))
  133.         (void) strcat(in_reply_to, p);
  134.     }
  135.     }
  136.     if (argv && *argv) {
  137.     char buf[BUFSIZ];
  138.     (void) argv_to_string(buf, argv);
  139.     to = strcat(To, buf);
  140.     }
  141.     if (do_set(set_options, "auto_route"))
  142.     improve_uucp_paths(To), improve_uucp_paths(Cc);
  143.     /* if fortune is set, check to see if fortunates is set. If so,
  144.      * check to see if the recipient is on the fortunates list.
  145.      */
  146.     if (do_set(set_options, "fortune")) {
  147.     register char *p2 = do_set(set_options, "fortunates");
  148.     if (!to || !p2 || *p2 && (chk_two_lists(to, p2, " \t,") ||
  149.              (firstchar == 'r' && cc && chk_two_lists(cc, p2, " \t,"))))
  150.         turnon(flgs, DO_FORTUNE);
  151.     }
  152. #ifdef SUNTOOL
  153.     if (istool) {
  154.     do_clear();
  155.     panel_set(abort_item,   PANEL_SHOW_ITEM, TRUE,  0);
  156.     panel_set(comp_item,    PANEL_SHOW_ITEM, FALSE, 0);
  157.     panel_set(read_item,    PANEL_SHOW_ITEM, FALSE, 0);
  158.     panel_set(respond_item, PANEL_SHOW_ITEM, FALSE, 0);
  159.     }
  160. #endif SUNTOOL
  161.     return mail_someone(to, subj, cc, flgs, list);
  162. }
  163.  
  164. #ifdef SUNTOOL
  165. /* panel item selection -- it's here because of local (static) variables */
  166. abort_mail(item, value)
  167. Panel_item item;
  168. {
  169.     get_hdr_field = 0;
  170.     if (item == abort_item && value != 2) {
  171.     print("Aborted letter.");
  172.     killme = 1, rm_edfile(SIGINT);
  173.     flags = 0;
  174.     }
  175.     panel_set(comp_item,    PANEL_SHOW_ITEM, TRUE,  0);
  176.     panel_set(send_item,    PANEL_SHOW_ITEM, FALSE, 0);
  177.     panel_set(edit_item,    PANEL_SHOW_ITEM, FALSE, 0);
  178.     panel_set(abort_item,   PANEL_SHOW_ITEM, FALSE, 0);
  179.     panel_set(read_item,    PANEL_SHOW_ITEM, TRUE,  0);
  180.     panel_set(respond_item, PANEL_SHOW_ITEM, TRUE,  0);
  181.     unlock_cursors();
  182. }
  183. #endif SUNTOOL
  184.  
  185. mail_someone(to, subject, cc, flgs, list)
  186. register char *to, *subject, *cc, *list;
  187. {
  188.     register char *p;
  189.  
  190.     flags = flgs;
  191. #ifdef SUNTOOL
  192.     if (istool)
  193.     rite(_tty.sg_kill), do_clear(), wprint("To: ");
  194. #endif SUNTOOL
  195.     if (to && *to) {
  196.     if (!*To)
  197.         (void) strcpy(To, to);
  198.     if (istool)
  199.         wprint("%s\n", To);
  200.     } else
  201. #ifdef SUNTOOL
  202.     if (istool)
  203.         turnon(get_hdr_field, TO_FIELD);
  204.     else
  205. #endif SUNTOOL
  206.         to = NO_STRING;
  207.     if (subject && *subject) {
  208.     if (!*Subject)
  209.         (void) strcpy(Subject, subject);
  210.     if (istool)
  211.         wprint("Subject: %s\n", Subject);
  212.     } else
  213. #ifdef SUNTOOL
  214.     if (istool && !*Subject)
  215.         turnon(get_hdr_field, SUBJECT);
  216.     else
  217. #endif SUNTOOL
  218.         subject = NO_STRING;
  219.     if (cc && *cc) {
  220.     if (!*Cc)
  221.         (void) strcpy(Cc, cc);
  222.     if (istool)
  223.         wprint("Cc: %s\n", Cc);
  224.     } else
  225. #ifdef SUNTOOL        /* get_hdr_field -- prevents prompting on replies */
  226.     if (istool && get_hdr_field && do_set(set_options, "askcc"))
  227.         turnon(get_hdr_field, CC_FIELD);
  228.     else
  229. #endif SUNTOOL
  230.         cc = NO_STRING;
  231.  
  232.     if (ison(glob_flags, REDIRECT)) {
  233.     send_it(); /* doesn't return */
  234.     return 0;
  235.     }
  236.     /* if (!*to) then prompting will be done */
  237.     if (!istool) {
  238.     if (!(p = set_header("To: ", to, !*to)) || !*p) {
  239.         puts("No recipients, can't mail.");
  240.         return -1;
  241.     }
  242.     (void) strcpy(To, p);
  243.     if (p = set_header("Subject: ", subject, !*subject))
  244.         (void) strcpy(Subject, p);
  245.     if (*Cc)
  246.         printf("Cc: %s\n", Cc);
  247.     putchar('\n');
  248.     }
  249. #ifdef SUNTOOL
  250.       else if (!get_hdr_field) {
  251.     panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  252.     panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  253.     }
  254. #endif SUNTOOL
  255.     return start_file(list);
  256. }
  257.  
  258. start_file(list)
  259. char *list;
  260. {
  261.     register char  *home;
  262.     register int   i;
  263.     char         line[256];
  264.  
  265.     if (!(home = do_set(set_options, "home")) || !*home)
  266.     home = ALTERNATE_HOME;
  267.     (void) mktemp(sprintf(edfile, "%s/%s", home, EDFILE));
  268.     {
  269.     int omask = umask(077);
  270.     fp = fopen(edfile, "w+");
  271.     (void) umask(omask);
  272.     if (!fp) {
  273. #ifdef SUNTOOL
  274.         if (istool)
  275.         abort_mail(NO_ITEM, 0);
  276. #endif SUNTOOL
  277.         error("can't create %s", edfile);
  278.         return -1;
  279.     }
  280.     }
  281.     if (!istool) {
  282.     oldint = signal(SIGINT, rm_edfile);
  283.     oldquit = signal(SIGQUIT, rm_edfile);
  284.     oldterm = signal(SIGTERM, rm_edfile);
  285.     }
  286.     oldhup = signal(SIGHUP, rm_edfile);
  287.  
  288.     /* if flags call for it, include current message (with header?) */
  289.     if (ison(flags, INCLUDE) || ison(flags,FORWARD) || ison(flags,INCLUDE_H)) {
  290.     long copy_flgs = 0, is_forw = ison(flags, FORWARD);
  291.     char buf[256];
  292.     if (!is_forw)
  293.         turnon(copy_flgs, INDENT);
  294.     if (ison(flags, INCLUDE))
  295.         turnon(copy_flgs, NO_HEADER);
  296.     if (ison(flags, INCLUDE) || ison(flags, FORWARD))
  297.         turnon(copy_flgs, NO_IGNORE);
  298. #ifdef SUNTOOL
  299.         if (istool)
  300.             lock_cursors();
  301. #endif SUNTOOL
  302.     for (i = 0; i < msg_cnt; i++)
  303.         if (msg_bit(list, i)) {
  304.         if (is_forw) {
  305.             (void) reply_to(i, FALSE, buf);
  306.             fprintf(fp, "--- Forwarded mail from %s\n\n", buf);
  307.         }
  308.         wprint("%sing message %d ...",
  309.             is_forw? "forward" : "includ", i+1);
  310.         wprint("(%d lines)\n", copy_msg(i, fp, copy_flgs));
  311.         set_isread(i); /* if we included it, we read it, right? */
  312.         if (is_forw)
  313.             fprintf(fp,"\n--- End of forwarded message from %s.\n",buf);
  314.         }
  315.     fflush(fp);
  316. #ifdef SUNTOOL
  317.     if (istool)
  318.         unlock_cursors();
  319. #endif SUNTOOL
  320.     }
  321.     if (ison(glob_flags, WARNING)) {
  322.     if (escape && *escape != DEF_ESCAPE[0])
  323.         wprint("(escape character is set to `%c')\n", *escape);
  324.     }
  325.     turnon(glob_flags, IS_GETTING);
  326. #ifdef SUNTOOL
  327.     /* enter editor if autoedit and replying to mail */
  328.     if (istool && get_hdr_field)
  329.     turnoff(flags, EDIT);
  330. #endif SUNTOOL
  331.     /* do an "if" again in case editor not found and EDIT turned off */
  332.     if (ison(flags, EDIT)) {
  333.     char *argv[3];
  334.     argv[0] = (visual)? visual : editor;
  335.     argv[1] = edfile;
  336.     argv[2] = NULL;
  337.     print("Starting \"%s\"...\n", argv[0]);
  338.     in_editor = 1;
  339.     execute(argv);
  340.     in_editor = 0;
  341.     turnoff(flags, EDIT);
  342.     /* upon exit of editor, user must now type ^D or "." to send */
  343.     if (istool)
  344.         return 0;
  345.     fflush(fp), (void) fseek(fp, 0L, 2);
  346.     puts("continue editing letter or ^D to send");
  347.     }
  348. #ifdef SUNTOOL
  349.     if (istool) {
  350.     pw_char(msg_win, txt.x,txt.y, PIX_SRC^PIX_DST, fonts[curfont], '_');
  351.     win_setcursor(msg_sw->ts_windowfd, &write_cursor);
  352.     return 0;
  353.     }
  354. #endif SUNTOOL
  355.     i = 0;
  356.     do  {
  357.     /* If the user hits ^C in cbreak mode, mush will return to
  358.      * Getstr and not clear the buffer. whatever is typed next will
  359.      * be appended to the line.  jumping here will force the line to
  360.      * be cleared cuz it's a new call.
  361.      */
  362.     (void) setjmp(cntrl_c_buf);
  363.     while (Getstr(line, 256, 0) > -1)
  364.         if ((i = add_to_letter(line)) <= 0)
  365.         break;
  366.     } while (i >= 0 && !finish_up_letter());
  367.     return 0;
  368. }
  369.  
  370. char *tilde_commands[] = {
  371.     "commands: [OPTIONAL argument]",
  372.     "e [editor]\tEnter editor. Editor used: \"set editor\", env EDITOR, vi",
  373.     "v [editor]\tEnter visual editor. \"set visual\", env VISUAL, vi",
  374.     "p [pager]\tPage message; pager used: \"set pager\", env. PAGER, more",
  375.     "i [msg#'s]\tInclude current msg body [msg#'s] indented by \"indent_str\"",
  376.     "H [msg#'s]\tSame, but include the message headers from included messages",
  377.     "f [msg#'s]\tForward mail. Not indented, but marked as \"forwarded mail\"",
  378.     "t [list]\tChange list of recipients",
  379.     "s [subject]\tModify [set] subject header",
  380.     "c [cc list]\tModify [set] carbon copy recipients",
  381.     "b [bcc list]\tModify [set] blind carbon recipients",
  382.     "h\t\tModify all message headers",
  383.     "S[!]\t\tInclude Signature file [suppress file]",
  384.     "F[!]\t\tAdd a fortune at end of letter [don't add]",
  385.     "w file\t\tWrite msg buffer to file name",
  386.     "a file\t\tAppend msg buffer to file name",
  387.     "r file\t\tRead filename into message buffer",
  388.     "q \t\tQuit message; save in dead.letter (unless \"nosave\" is set).",
  389.     "x \t\tQuit message; don't save in dead.letter.",
  390.     "$variable\tInsert the string value for \"variable\" into message.",
  391.     ":cmd\t\tRun the mail command \"cmd\".",
  392.     "u\t\tedit previous line in file.",
  393.     "E\t\tErase message buffer; clear all contents of letter",
  394.     0
  395. };
  396.  
  397. add_to_letter(line)
  398. register char *line;
  399. {
  400.     register char *p;
  401.     char buf[256];
  402.  
  403.     killme = 0;
  404.     (void) fseek(fp, 0L, 2); /* seek to end in case more was added by editor */
  405. #ifdef SUNTOOL
  406.     if (get_hdr_field) {
  407.     /* These are received in order by design! */
  408.     if (ison(get_hdr_field, TO_FIELD)) {
  409.         if (!*line) {
  410.             wprint("There must be a recipient!\nTo: ");
  411.         return 1;
  412.         }
  413.         (void) strcpy(To, line), turnoff(get_hdr_field, TO_FIELD);
  414.     } else if (ison(get_hdr_field, SUBJECT)) {
  415.         (void) strcpy(Subject, line);
  416.         turnoff(get_hdr_field, SUBJECT);
  417.     } else if (ison(get_hdr_field, CC_FIELD)) {
  418.         (void) strcpy(Cc, line);
  419.         turnoff(get_hdr_field, CC_FIELD);
  420.     } else if (ison(get_hdr_field, BC_FIELD)) {
  421.         (void) strcpy(Bcc, line);
  422.         turnoff(get_hdr_field, BC_FIELD);
  423.     }
  424.  
  425.         if (ison(get_hdr_field, SUBJECT))
  426.         (void) set_header("Subject: ", Subject, 1);
  427.         else if (ison(get_hdr_field, CC_FIELD))
  428.         (void) set_header("Cc: ", Cc, 1);
  429.         else if (ison(get_hdr_field, BC_FIELD))
  430.         (void) set_header("Bcc: ", Bcc, 1);
  431.     panel_set(send_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  432.     panel_set(edit_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  433.     return 1;
  434.     }
  435. #endif SUNTOOL
  436.     if (!strcmp(line, ".") && (istool || do_set(set_options, "dot")))
  437.     return 0;
  438.     if (*line != *escape) {
  439.     fputs(line, fp), fputc('\n', fp), fflush(fp);
  440.     return 1;
  441.     }
  442.     /* all commands are "~c" (where 'c' is the command). set p = first
  443.      * character after 'c' and skip whitespace
  444.      */
  445.     p = line+2;
  446.     skipspaces(0);
  447.     switch (line[1]) {
  448.     case 'v' : case 'p': case 'e':
  449.         if (!*p || *p == 'i')
  450.         p = (line[1] == 'p')? pager:
  451.             (visual && line[1] == 'v')? visual: editor;
  452.         if (line[1] == 'p') {
  453.         wprint("To: %s\n", To);
  454.         if (Subject[0])
  455.             wprint("Subject: %s\n", Subject);
  456.         if (Cc[0])
  457.             wprint("Cc: %s\n", Cc);
  458.         if (Bcc[0])
  459.             wprint("Bcc: %s\n", Bcc);
  460.         wprint("-----------\nMessage contains:\n");
  461.         }
  462.         if (line[1] == 'p' && (istool || !istool && lines_in(fp, crt))) {
  463.         rewind(fp);
  464.         while (fgets(buf, BUFSIZ, fp))
  465. #ifdef SUNTOOL
  466.             if (istool)
  467.             Addstr(buf);
  468.             else
  469. #endif SUNTOOL
  470.             (void) fputs(buf, stdout);
  471.         } else {
  472.         char *argv[3];
  473.         argv[0] = p;
  474.         argv[1] = edfile;
  475.         argv[2] = NULL;
  476.         in_editor = 1;
  477.         execute(argv); /* page the message using pager */
  478.         in_editor = 0;
  479.         if (istool)
  480.             return 1;
  481.         }
  482.     when '$': {
  483.         register char *p2;
  484.         if (!(p2 = do_set(set_options, p)))
  485.         wprint("(%s isn't set)\n", p);
  486.         else
  487.         fprintf(fp, "%s\n", p2);
  488.     }
  489.     when ':': {
  490.         char new[MAXMSGS_BITS];
  491.         long save_flags = glob_flags;
  492.  
  493.         turnon(glob_flags, IGN_SIGS);
  494.         turnon(glob_flags, IGN_BANG);
  495.         turnoff(glob_flags, DO_PIPE);
  496.         turnoff(glob_flags, IS_PIPE);
  497.         (void) cmd_line(p, new);
  498.         glob_flags = save_flags;
  499. #ifdef SUNTOOL
  500.         if (istool && msg_pix) /* the command was to read a message */
  501.         return 1;
  502. #endif SUNTOOL
  503.     }
  504.     when 'i': case 'f': case 'H': case 'm': {
  505.         int  n;
  506.         long copy_flgs = 0;
  507.         char list[MAXMSGS_BITS];
  508.  
  509.         if (!msg_cnt) {
  510.         print("No messages.\n");
  511.         break;
  512.         }
  513.         clear_msg_list(list);
  514.         if (line[1] != 'f')
  515.         turnon(copy_flgs, INDENT);
  516.         if (line[1] == 'i')
  517.         turnon(copy_flgs, NO_HEADER);
  518.         if (!*p)
  519.         set_msg_bit(list, current_msg);
  520.         else if (!do_range(p, list))
  521.         return 1;
  522. #ifdef SUNTOOL
  523.         if (istool)
  524.         lock_cursors();
  525. #endif SUNTOOL
  526.         for (n = 0; n < msg_cnt; n++)
  527.         if (msg_bit(list, n)) {
  528.             if (line[1] == 'f') {
  529.             (void) reply_to(n, FALSE, buf);
  530.             fprintf(fp, "--- Forwarded mail from %s\n\n", buf);
  531.             }
  532.             wprint("Including message %d ... ", n+1);
  533.             wprint("(%d lines)\n", copy_msg(n, fp, copy_flgs));
  534.             set_isread(n);
  535.             if (line[1] == 'f')
  536.         fprintf(fp, "\n--- End of forwarded message from %s\n\n", buf);
  537.         }
  538. #ifdef SUNTOOL
  539.         if (istool)
  540.         unlock_cursors();
  541. #endif SUNTOOL
  542.     }
  543.     when 't':
  544. #ifdef SUNTOOL
  545.         if (!*p && istool) {
  546.         turnon(get_hdr_field, TO_FIELD);
  547.         (void) set_header("To: ", To, 1);
  548.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  549.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  550.         return 1;
  551.         }
  552. #endif SUNTOOL
  553.         /* ~t address   is a special case ... append to address */
  554.         if (*p)
  555.         (void) sprintf(To+strlen(To), " %s", p);
  556.         else if (p = set_header("To: ", To, 1))
  557.         if (!*p) {
  558.             wprint("There must be a recipient!\n");
  559. #ifdef SUNTOOL
  560.             turnoff(get_hdr_field, TO_FIELD);
  561.             panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  562.             panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  563. #endif SUNTOOL
  564.         } else
  565.             (void) strcpy(To, p);
  566.     when 's':
  567. #ifdef SUNTOOL
  568.         if (!*p && istool) {
  569.         turnon(get_hdr_field, SUBJECT);
  570.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  571.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  572.         (void) set_header("Subject: ", Subject, 1);
  573.         return 1;
  574.         }
  575. #endif SUNTOOL
  576.         if (*p || (p = set_header("Subject: ", Subject, 1)))
  577.         if (!*p)
  578.             Subject[0] = 0;
  579.         else
  580.             (void) strcpy(Subject, p);
  581.     when 'c':
  582. #ifdef SUNTOOL
  583.         if (!*p && istool) {
  584.         turnon(get_hdr_field, CC_FIELD);
  585.         (void) set_header("Cc: ", Cc, 1);
  586.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  587.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  588.         return 1;
  589.         }
  590. #endif SUNTOOL
  591.         if (*p || (p = set_header("Cc: ", Cc, 1)))
  592.         if (!*p)
  593.             Cc[0] = 0;
  594.         else
  595.             (void) strcpy(Cc, p);
  596.     when 'b':
  597. #ifdef SUNTOOL
  598.         if (!*p && istool) {
  599.         turnon(get_hdr_field, BC_FIELD);
  600.         (void) set_header("Bcc: ", Bcc, 1);
  601.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  602.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  603.         return 1;
  604.         }
  605. #endif SUNTOOL
  606.         if (*p || (p = set_header("Bcc: ", Bcc, 1)))
  607.         if (!*p)
  608.             Bcc[0] = 0;
  609.         else
  610.             (void) strcpy(Bcc, p);
  611.     when 'h':
  612. #ifdef SUNTOOL
  613.         if (istool) {
  614.         turnon(get_hdr_field, TO_FIELD);
  615.         turnon(get_hdr_field, SUBJECT);
  616.         turnon(get_hdr_field, CC_FIELD);
  617.         turnon(get_hdr_field, BC_FIELD);
  618.         (void) set_header("To: ", To, 1);
  619.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  620.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  621.         return 1;
  622.         }
  623. #endif SUNTOOL
  624.         while ((p = set_header("To: ", To, 1)) && !*p)
  625.         wprint("(There must be a recipient.)\n");
  626.         (void) strcpy(To, p);
  627.         if (p = set_header("Subject: ", Subject, 1))
  628.         if (!*p)
  629.             Subject[0] = 0;
  630.         else
  631.             (void) strcpy(Subject, p);
  632.         if (p = set_header("Cc: ", Cc, 1))
  633.         if (!*p)
  634.             Cc[0] = 0;
  635.         else
  636.             (void) strcpy(Cc, p);
  637.         if (p = set_header("Bcc: ", Bcc, 1))
  638.         if (!*p)
  639.             Bcc[0] = 0;
  640.         else
  641.             (void) strcpy(Bcc, p);
  642.     when 'S':
  643.         if (*p == '!')
  644.         turnoff(flags, SIGN), wprint("not ");
  645.         else
  646.         turnon(flags, SIGN);
  647.         wprint("adding signature file at end of message.\n");
  648.     when 'F':
  649.         if (*p == '!')
  650.         turnoff(flags, DO_FORTUNE), wprint("not ");
  651.         else
  652.         turnon(flags, DO_FORTUNE);
  653.         wprint("adding fortune at end of message.\n");
  654.     when 'w': case 'a': case 'r':
  655.         if (!*p) {
  656.         wprint("(you must specify a filename)\n");
  657.         return 1;
  658.         }
  659.         (void) fseek(fp, 0L, 2); /* append */
  660.         file_to_fp(p, fp, (line[1] == 'r')? "r":
  661.                   (line[1] == 'w')? "w": "a");
  662.     /* go up one line in the message file and allow the user to edit it */
  663.     when 'u': {
  664.         long newpos, pos = ftell(fp);
  665.         char oldline[256];
  666.         if (istool) {
  667.         wprint("(Not available in tool mode.)\n");
  668.         return 1;
  669.         }
  670.         if (pos <= 0L) { /* pos could be -1 if ftell() failed */
  671.         wprint("(No previous line in file.)\n");
  672.         return 1;
  673.         }
  674.         /* get the last 256 bytes written and read backwards from the
  675.          * current place until '\n' is found. Start by moving past the
  676.          * first \n which is at the end of the line we want to edit
  677.          */
  678.         newpos = max(0, pos - 256);
  679.         (void) fseek(fp, newpos, L_SET);
  680.         /* don't fgets -- it'll stop at a \n */
  681.         (void) read(fileno(fp), line, (int)(pos-newpos));
  682.         pos--;
  683.         /* the last char in line should be a \n cuz it was last input */
  684.         if (line[(int)(pos-newpos)] != '\n')
  685.         wprint("I don't know how, but your last line ended with %c.\n",
  686.             line[(int)(pos-newpos)]);
  687.         else
  688.         line[(int)(pos-newpos)] = 0; /* null terminate \n for ^H-ing */
  689.         for (pos--; pos > newpos && line[(int)(pos-newpos)] != '\n'; pos--)
  690.         ;
  691.         /* we've gone back to the end of the second previous line. Check
  692.          * to see if the char we're pointing to is a \n.  It should be, but
  693.          * if it's not, we moved back to the first line of the file.
  694.          */
  695.         if (line[(int)(pos-newpos)] == '\n')
  696.         ++pos;
  697.         /* save the old line that's there in case the user boo-boo's */
  698.         (void) strcpy(oldline, line+(int)(pos-newpos));
  699.         /* let set header print out the line and get the input */
  700.         if (!(p = set_header("", line+(int)(pos-newpos), TRUE))) {
  701.         wprint("Something bad happened and I don't know what it is.\n");
  702.         p = oldline;
  703.         } else if (*p == *escape && *++p != *escape) {
  704.         wprint("(No %c escapes on %cu lines. Line unchanged.)\n",
  705.                 *escape, *escape);
  706.         p = oldline;
  707.         }
  708.         /* seek to to the position where the new line will go */
  709.         (void) fseek(fp, pos, L_SET);
  710.         /* put the newly typed line */
  711.         (void) fputs(p, fp); /* don't add \n in case padding is necessary */
  712.         /* if the new line is less than the old line, we're going to do
  713.          * one of two things.  The best thing to do is to truncate the
  714.          * file to the end of the new line.  Sys-v can't do that, so we
  715.          * pad the line with blanks.  May be messy in some cases, but...
  716.          */
  717.         if ((pos = strlen(p) - strlen(oldline)) < 0) {
  718. #ifndef SYSV
  719.         /* add the \n, flush the file, truncate to the current pos */
  720.         fputc('\n', fp), fflush(fp);
  721.         (void) ftruncate(fileno(fp), (int)ftell(fp));
  722. #else
  723.         /* pad with blanks to the length of the old line. add \n */
  724.         while (pos++ < 0)
  725.             fputc(' ', fp);
  726.         fputc('\n', fp), fflush(fp);
  727. #endif SYSV
  728.         } else
  729.         /* the new line is >= the old line, add \n -- no trunc req. */
  730.             fputc('\n', fp);
  731.         return 1;
  732.      }
  733.     /* break;  not here cuz of "return" (lint). */
  734.     case 'E':
  735.         wprint("Message buffer empty\n");
  736.         if (emptyfile(&fp, edfile) == -1)
  737.         error(edfile);
  738.     when 'q':
  739.         /* save in dead.letter if nosave not set -- rm_edfile(-2). */
  740.         rm_edfile(-2); /* doesn't return out of tool mode */
  741.         return -1;
  742.         /* break; not stated cuz of "return" (lint) */
  743.     case 'x':
  744.         /* don't save dead.letter -- simulate normal rm_edfile() call */
  745.         rm_edfile(0);
  746. #ifdef SUNTOOL
  747.         if (istool) {
  748.         wprint("*Letter aborted*");
  749.         pw_char(msg_win, txt.x,txt.y, PIX_CLR, fonts[curfont], '_');
  750.         }
  751. #endif SUNTOOL
  752.         return -1;
  753.         /* break; (not specified for lint) */
  754.     default:
  755.         if (line[1] == *escape) {
  756.         fputs(line+1, fp), fputc('\n', fp), fflush(fp);
  757.         return 1;
  758.         } else {
  759.         register int x;
  760.         for (x = 0; tilde_commands[x]; x++)
  761.             wprint("%s%s\n", escape, tilde_commands[x]);
  762.         wprint("%s%s\t\tbegin a line with a single %s\n",
  763.             escape, escape, escape);
  764. #ifdef SUNTOOL
  765.         if (istool)
  766.             (void) help(0, "compose", tool_help);
  767. #endif SUNTOOL
  768.         }
  769.     }
  770.     (void) fseek(fp, 0L, 2); /* seek to end of file in case there's more */
  771.     wprint("(continue editing letter)\n");
  772. #ifdef SUNTOOL
  773.     if (istool)
  774.     pw_char(msg_win, txt.x,txt.y, PIX_SRC, fonts[curfont], '_');
  775. #endif SUNTOOL
  776.     return 1;
  777. }
  778.  
  779. /*
  780.  * finish up the letter. ask for the cc line, if verify is set, ask to
  781.  * verify sending, continue editing, or to dump the whole idea.
  782.  * Then check for signature and fortune.  Finally, pass it to send_it()
  783.  * to actually send it off.
  784.  */
  785. finish_up_letter()
  786. {
  787.     register char *p;
  788.     char buf[256];
  789.  
  790. #ifdef SUNTOOL
  791.     if (istool)
  792.     lock_cursors();
  793.     else
  794. #endif SUNTOOL
  795.     if (isoff(glob_flags, REDIRECT)) {
  796.     if (do_set(set_options, "askcc") && (p = set_header("Cc: ", Cc, 1)))
  797.         (void) strcpy(Cc, p);
  798.     /* ~v on the Cc line asks for verification, first initialize p! */
  799.     p = NULL;
  800.     if (!strncmp(Cc, "~v", 2) || (p = do_set(set_options, "verify"))) {
  801.         if (!p) /* so we don't Cc to ~v! */
  802.         *Cc = 0;
  803.         fprintf(stderr, "send, continue editing, discard [s,c,d]? ");
  804.         if (Getstr(buf, 256, 0) < 0 || lower(*buf) == 'd') {
  805.         rm_edfile(-2);
  806.         return 1;
  807.         } else if (lower(*buf) == 'c') {
  808.         puts("(continue editing letter)");
  809.         return 0;
  810.         }
  811.     }
  812.     }
  813.  
  814.     if (ison(flags, SIGN)) {
  815.     char *home = do_set(set_options, "home");
  816.     if (!home || !*home)
  817.         home = ALTERNATE_HOME;
  818.     if (!(p = do_set(set_options, "autosign")) || !*p)
  819.         (void) sprintf(buf, "%s/%s", home, SIGNATURE);
  820.     else
  821.         (void) strcpy(buf, p);
  822.     wprint("Signing letter... "), fflush(stdout);
  823.     fputc('\n', fp), fflush(fp);
  824.     (void) fseek(fp, 0L, 2); /* guarantee position at end of file */
  825.     if (*buf == '$')
  826.         if (!(p = do_set(set_options, buf)))
  827.         wprint("(%s isn't set -- letter not signed)\n", buf);
  828.         else
  829.         fprintf(fp, "%s\n", p), wprint("\n"), fflush(fp);
  830.     else if (*buf == '\\')
  831.         fprintf(fp, "%s\n", buf+1), wprint("\n"), fflush(fp);
  832.     else
  833.         file_to_fp(buf, fp, "r");
  834.     }
  835.  
  836.     if (ison(flags, DO_FORTUNE)) {
  837.     char     foo[256];
  838.     FILE     *pp2;
  839.     int     lines = 0;
  840.  
  841.     wprint("You may be fortunate... "), fflush(stdout);
  842.     if ((p = do_set(set_options, "fortune")) && *p == '/')
  843.         (void) strcpy(foo, p);
  844.     else
  845.         (void) sprintf(foo, "%s %s", FORTUNE, (p && *p == '-')? p: "-s");
  846.     if (!(pp2 = popen(foo, "r")))
  847.         error(foo);
  848.     else {
  849.         turnon(glob_flags, IGN_SIGS);
  850.         (void) fseek(fp, 0L, 2); /* go to end of file */
  851.         while (fgets(foo, 256, pp2))
  852.         fputs(foo, fp), lines++;
  853.         (void) pclose(pp2);
  854.         turnoff(glob_flags, IGN_SIGS);
  855.         fflush(fp);
  856.         wprint("added %d line%s\n", lines, lines == 1? "" : "s");
  857.     }
  858.     }
  859.     send_it();
  860.     turnoff(glob_flags, IS_GETTING);
  861.     return 1;
  862. }
  863.  
  864. /*
  865.  * actually send the letter.
  866.  * 1. Reset all the signals because of fork.
  867.  * 2. determine recipients (users, address, files, programs)
  868.  * 3. Determine mailer, fork and return (if not verbose).
  869.  * 4. popen mailer, $record, and other files specified in step 1.
  870.  * 5. make the headers; this includes To: line, and user set hedaers, etc...
  871.  * 6. copy the letter right into the array of file pointers (step 1).
  872.  * 7. close the mailer and other files (step 1) and remove the edit-file.
  873.  */
  874. static void
  875. send_it()
  876. {
  877.     register char *p;
  878. #ifdef MAXFILES
  879.     register int size = MAXFILES - 1;
  880.     FILE *files[MAXFILES];
  881. #else
  882.     register int size = getdtablesize() - 1;
  883.     FILE *files[30];  /* 30 should be sufficiently large enough */
  884. #endif /* MAXFILES */
  885.     int next_file = 1; /* reserve files[0] for the mail delivery program */
  886.     char buf[3*BUFSIZ];
  887.  
  888.     if (!istool) {
  889.     (void) signal(SIGINT, oldint);
  890.     (void) signal(SIGQUIT, oldquit);
  891.     (void) signal(SIGTERM, oldterm);
  892.     }
  893.     (void) signal(SIGHUP, oldhup);
  894.  
  895. #ifdef VERBOSE_ARG
  896.     if (ison(flags, VERBOSE) || do_set(set_options, "verbose"))
  897.     (void) sprintf(buf, "%s %s", MAIL_DELIVERY, VERBOSE_ARG);
  898.     else
  899. #endif VERBOSE_ARG
  900.     (void) strcpy(buf, MAIL_DELIVERY);
  901. #ifdef METOO_ARG
  902.     if (do_set(set_options, "metoo"))
  903.     (void) sprintf(buf+strlen(buf), " %s", METOO_ARG);
  904. #endif METOO_ARG
  905.  
  906.     /*
  907.      * For alias expansion on To, Cc and Bcc lines, first expand the recipients
  908.      * lists so that aliases are expanded.  Then detemine which items in the
  909.      * list are files or programs and remove those from the list. Finally,
  910.      * copy the resulting buffer back into the original To, Cc, and Bcc buffer.
  911.      * rm_edfile(-2) will save in dead letter (only if "nosave" set) and
  912.      * will long jump back to main loop if any alias expansions fail. Insure
  913.      * a forced dead letter by rm_edfile(-1). But, rm_edfile will exit with -1
  914.      * arg, so kludge by turning on the VERBOSE bit in "flags".
  915.      */
  916.     if (!(p = alias_to_address(To))) {
  917.     print("address expansion failed for To: line.\n");
  918.     turnon(flags, VERBOSE);
  919.     rm_edfile(-1);
  920.     } else {
  921.     next_file += find_files(p, files+next_file, size - next_file);
  922.     if (!*strcpy(To, p)) {
  923.         print("There must be at least 1 legal recipient on the To line\n");
  924.         while (--next_file > 1)
  925.         fclose(files[next_file]);
  926.         rm_edfile(-2);
  927.         return;
  928.     }
  929.     }
  930.     if (*Cc)
  931.     if (!(p = alias_to_address(Cc))) {
  932.         print("address expansion failed for Cc: line.\n");
  933.         turnon(flags, VERBOSE);
  934.         while (--next_file > 1)
  935.         fclose(files[next_file]);
  936.         rm_edfile(-1);
  937.     } else {
  938.         next_file += find_files(p, files+next_file, size - next_file);
  939.         (void) strcpy(Cc, p);
  940.     }
  941.     if (*Bcc)
  942.     if (!(p = alias_to_address(Bcc))) {
  943.         print("address expansion failed for Bcc: line.\n");
  944.         turnon(flags, VERBOSE);
  945.         while (--next_file > 1)
  946.         fclose(files[next_file]);
  947.         rm_edfile(-1);
  948.     } else {
  949.         next_file += find_files(p, files+next_file, size - next_file);
  950.         (void) strcpy(Bcc, p);
  951.     }
  952.  
  953.     /*
  954.      * build the mailer's "command line" -- we build our own headers later.
  955.      * the mailer will mail to everyone listed.  The headers will contain
  956.      * the to and cc lines  -- Bcc is never printed.
  957.      */
  958.     (void) sprintf(buf+strlen(buf), " %s %s %s", To, Cc, Bcc);
  959.  
  960. #ifdef SYSV
  961.     /*
  962.      * Sys-v does not recover from SIGCLD elegantly. That is, all system calls
  963.      * return -1 and does not complete whatever it was doing when the signal
  964.      * gets delievered -- we could be reading from stdin, a file, or feeding
  965.      * to a pager -- this isn't good.  I'm not good enough at SYSV to know how
  966.      * to recover from this correctly.  BSD systems recover elegantly and
  967.      * deliver the sigchld properly.
  968.      */
  969.     turnon(flags, VERBOSE);
  970. #endif SYSV
  971.  
  972.     Debug("mail command: %s\n", buf);
  973.  
  974. #ifdef SUNTOOL
  975.     if (istool)
  976.     abort_mail(NO_ITEM, 0);
  977. #endif SUNTOOL
  978.  
  979.     if (isoff(flags, VERBOSE) && debug < 3)
  980.     switch (fork()) {
  981.         case  0:  /* the child will send the letter. ignore signals */
  982.         (void) signal(SIGINT, SIG_IGN);
  983.         (void) signal(SIGHUP, SIG_IGN);
  984.         (void) signal(SIGQUIT, SIG_IGN);
  985.         (void) signal(SIGTERM, SIG_IGN);
  986. #ifdef SIGCONT
  987.         (void) signal(SIGCONT, SIG_IGN);
  988.         (void) signal(SIGTSTP, SIG_IGN);
  989. #endif SIGCONT
  990.         turnon(glob_flags, IGN_SIGS);
  991.         break;
  992.         case -1:
  993.         error("fork failed trying to send mail");
  994.         default:
  995.         if (isoff(glob_flags, REDIRECT))
  996.             fclose(fp);
  997. #ifdef SUNTOOL
  998.                 if (istool) {
  999.             wprint("Letter sent.");
  1000.             print("Letter sent.");
  1001.             pw_char(msg_win, txt.x,txt.y, PIX_CLR, fonts[curfont], '_');
  1002.         }
  1003. #endif SUNTOOL
  1004.         while (--next_file > 0)
  1005.             fclose(files[next_file]);
  1006.         return;
  1007.     }
  1008.  
  1009.     if (debug > 2)
  1010.     files[0] = stdout;
  1011.     else if (!(files[0] = open_file(buf, TRUE))) {
  1012.     rm_edfile(-1); /* force saving of undeliverable mail */
  1013.     return;
  1014.     }
  1015.  
  1016.     if (ison(flags, VERBOSE))
  1017.     wprint("Sending letter ... "), fflush(stdout);
  1018.  
  1019.     /* see if record is set.  If so, open that file for appending and add
  1020.      * the letter in a format such that mail can be read from it
  1021.      */
  1022.     if (p = do_set(set_options, "record")) {
  1023.     if (!*p)
  1024.         p = "~/record";
  1025.     (void) strcpy(buf, p);
  1026.     next_file += find_files(buf, files+next_file, size - next_file);
  1027.     }
  1028.  
  1029.     /* don't send this to Sendmail --make folders conform to RFC-822 */
  1030.     for (size = 1; size < next_file; size++)
  1031.     if (files[size]) {
  1032.         time_t t;
  1033.         (void) time(&t);
  1034.         fprintf(files[size], "From %s %s", login, ctime(&t));
  1035.         fprintf(files[size], "From: %s\n", login);
  1036.         fprintf(files[size], "Date: %s", ctime(&t));
  1037.         fprintf(files[size], "Status: OR\n");
  1038.     }
  1039.  
  1040.     /* first print users own message headers */
  1041.     if (own_hdrs && !do_set(set_options, "no_hdrs")) {
  1042.     struct options *opts;
  1043.     for (opts = own_hdrs; opts; opts = opts->next)
  1044.         for (size = 0; size < next_file; size++)
  1045.         fprintf(files[size], "%s %s\n", opts->option, opts->value);
  1046.     }
  1047.  
  1048.     /* send the header stuff to sendmail and end header with a blank line */
  1049.     if (*in_reply_to)
  1050.     for (size = 0; size < next_file; size++)
  1051.         fprintf(files[size], "In-Reply-To: %s\n", in_reply_to);
  1052.     for (size = 0; size < next_file; size++)
  1053.     fprintf(files[size], "X-Mailer: %s\n", VERSION);
  1054.     for (size = 0; size < next_file; size++)
  1055.     fprintf(files[size], "To: %s\n", To);
  1056.     if (*Subject)
  1057.     for (size = 0; size < next_file; size++)
  1058.         fprintf(files[size], "Subject: %s\n", Subject);
  1059.     if (*Cc)
  1060.     for (size = 0; size < next_file; size++)
  1061.         fprintf(files[size], "Cc: %s\n", Cc);
  1062.  
  1063.     for (size = 0; size < next_file; size++)
  1064.     fputc('\n', files[size]);
  1065.  
  1066.     /* if redirection, fp = stdin, else rewind the file just made */
  1067.     if (isoff(glob_flags, REDIRECT))
  1068.     rewind(fp);
  1069.     else
  1070.     fp = stdin;
  1071.  
  1072.     /* read from stdin or the edfile till EOF and send it all to the mailer */
  1073.     while (fgets(buf, BUFSIZ, fp))
  1074.     for (size = 0; size < next_file; size++) {
  1075.         if (!strncmp(buf, "From ", 5))
  1076.         fputc('>', files[size]);
  1077.         fputs(buf, files[size]);
  1078.     }
  1079.  
  1080.     for (size = 1; size < next_file; size++)
  1081.     if (files[size])
  1082.         fclose(files[size]); /* if it was popened, sigchld will close it */
  1083.  
  1084.     rm_edfile(0);
  1085.     if (debug < 3)
  1086.     (void) pclose(files[0]);
  1087.  
  1088.     if ((ison(flags, VERBOSE) || debug > 2) && isoff(glob_flags, REDIRECT))
  1089.     wprint("sent.\n");
  1090.     else
  1091.     exit(0); /* not a user exit -- a child exit */
  1092. }
  1093.  
  1094. /* ARGSUSED */
  1095. rm_edfile(sig)
  1096. {
  1097.     if (sig > 0 && !killme) {
  1098.     (void) signal(sig, rm_edfile);
  1099.     killme = 1;
  1100.     wprint("\n** interrupt -- one more to kill letter **\n");
  1101. #ifdef SUNTOOL
  1102.     if (istool) {
  1103.         pw_char(msg_win, txt.x,txt.y, PIX_SRC, fonts[curfont], '_');
  1104.         return;
  1105.     }
  1106. #endif SUNTOOL
  1107.     longjmp(cntrl_c_buf, 1);
  1108.     }
  1109.     in_editor = killme = 0;
  1110.     /* if sig == -1, force a save into dead.letter.
  1111.      * else, check for nosave not being set and save anyway if it's not set
  1112.      * sig == 0 indicates normal exit (or ~x), so don't save a dead letter.
  1113.      */
  1114.     if (sig == -1 || sig != 0 && !do_set(set_options, "nosave")) 
  1115.     dead_letter();
  1116.     if (isoff(glob_flags, REDIRECT))
  1117.     fclose(fp);
  1118.     (void) unlink(edfile);
  1119.  
  1120.     if (sig == -1 && isoff(flags, VERBOSE) && debug < 3)
  1121.     exit(-1);
  1122.  
  1123.     turnoff(glob_flags, IS_GETTING);
  1124. #ifdef SUNTOOL
  1125.     if (sig && istool > 1) {
  1126.     wprint("*Letter aborted*");
  1127.     abort_mail(abort_item, 2);
  1128.     }
  1129. #endif SUNTOOL
  1130.  
  1131.     if (sig == SIGHUP)
  1132.     cleanup(0);
  1133.     (void) signal(SIGHUP, oldhup);
  1134.     if (!istool) {
  1135.     (void) signal(SIGINT, oldint);
  1136.     (void) signal(SIGQUIT, oldquit);
  1137.     (void) signal(SIGTERM, oldterm);
  1138.     }
  1139.  
  1140.     if (sig == 0)
  1141.     return;
  1142.     if (istool || sig == -2) /* make sure sigchld is reset first */
  1143.     return;
  1144.  
  1145.     if (isoff(glob_flags, DO_SHELL)) {  /* If we're not in a shell, exit */
  1146.     puts("exiting");
  1147.     echo_on();
  1148.     exit(1);
  1149.     }
  1150.     longjmp(jmpbuf, 1);
  1151. }
  1152.  
  1153. /* save letter into dead letter */
  1154. dead_letter()
  1155. {
  1156.     char     *p, buf[BUFSIZ];
  1157.     long     t;
  1158.     FILE     *dead;
  1159.  
  1160.     if (ison(glob_flags, REDIRECT)) {
  1161.     print("input redirected -- can't save dead letter.\n");
  1162.     return;
  1163.     }
  1164.     /* don't save a dead letter if there's nothing to save. */
  1165.     if (fseek(fp, 0L, 2) || ftell(fp) == 0L)
  1166.     return;
  1167.     if (!(p = do_set(set_options, "dead")))
  1168.     p = "~/dead.letter";
  1169.     if (!(dead = open_file(p, FALSE)))
  1170.     return;
  1171.     (void) time (&t);
  1172.     fflush(fp);
  1173.     rewind(fp);
  1174.     fprintf(dead, "Unfinished letter from %s", ctime(&t));
  1175.     fprintf(dead, "To: %s\nSubject: %s\nCc: %s\n", To, Subject, Cc);
  1176.     while(fgets(buf, BUFSIZ, fp))
  1177.     (void) fputs(buf, dead);
  1178.     (void) fputc('\n', dead);
  1179.     (void) fclose(dead);
  1180.     print("Saved unfinished letter in %s.\n", p);
  1181. }
  1182.