home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume14 / mush6.0 / part14 / mail.c
Encoding:
C/C++ Source or Header  |  1988-04-12  |  43.0 KB  |  1,471 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],in_reply_to[256];
  32. static int killme;
  33. static u_long flags;
  34. static int (*oldterm)(), (*oldint)(), (*oldquit)();
  35. static void send_it();
  36. static jmp_buf cntrl_c_buf;
  37. FILE *ed_fp;
  38. char *edfile;
  39.  
  40. /* argc, and argv could be null if coming from compose */
  41. do_mail(n, argv, list)
  42. register int n;   /* no need for "argc", so use the space for a variable */
  43. register char **argv, *list;
  44. {
  45.     char firstchar = (argv)? **argv: 'm';
  46.     register char *to = NULL, *cc = NULL, *subj = NULL;
  47.     u_long flgs = 0;
  48.  
  49.     if (ison(glob_flags, IS_GETTING)) {
  50.     print("You must finish the letter you are editing first.\n");
  51.     return -1;
  52.     }
  53.     if (ison(glob_flags, DO_PIPE)) {
  54.     print("You can't pipe through the mail command.\n");
  55.     return -1;
  56.     }
  57.     turnon(flgs, NO_IGNORE); /* if we include a message, include all hdrs */
  58.  
  59.     if (do_set(set_options, "autoedit"))
  60.     turnon(flgs, EDIT);
  61. #ifdef VERBOSE_ARG
  62.     if (do_set(set_options, "verbose"))
  63.     turnon(flgs, VERBOSE);
  64. #endif /* VERBOSE_ARG */
  65.     if (do_set(set_options, "autosign"))
  66.     turnon(flgs, SIGN);
  67.     /* If piped to mail, include the messages piped */
  68.     if (ison(glob_flags, IS_PIPE))
  69.     turnon(flgs, INCLUDE);
  70.     else if (lower(firstchar) == 'r' && do_set(set_options, "autoinclude"))
  71.     turnon(flgs, INCLUDE), set_msg_bit(list, current_msg);
  72.     while (argv && *argv && *++argv && **argv == '-') {
  73.     n = 1;
  74.     while (n && argv[0][n])
  75.         switch (argv[0][n]) {
  76. #ifdef VERBOSE_ARG
  77.         case 'v': turnon(flgs, VERBOSE); n++; break;
  78. #endif /* VERBOSE_ARG */
  79.         case 'e': turnon(flgs, EDIT); n++;
  80.         when 'F': turnon(flgs, DO_FORTUNE); n++;
  81.         when 's':
  82.             if (argv[1])
  83.             n = 0, subj = *++argv;
  84.             else
  85.             n++, turnon(flgs, NEW_SUBJECT);
  86.         when 'i': case 'h': case 'f': {
  87.             int m;
  88.             if (!msg_cnt) {
  89.             print("No message to include!\n");
  90.             return -1;
  91.             }
  92.             if (argv[0][n] == 'i') {
  93.             turnon(flgs, INCLUDE);
  94.             turnoff(flgs, INCLUDE_H);
  95.             turnoff(flgs, FORWARD);
  96.             } else if (argv[0][n] == 'h') {
  97.             turnon(flgs, INCLUDE_H);
  98.             turnoff(flgs, INCLUDE);
  99.             turnoff(flgs, FORWARD);
  100.             } else if (argv[0][n] == 'f') {
  101.             turnon(flgs, FORWARD);
  102.             turnoff(flgs, INCLUDE_H);
  103.             turnoff(flgs, INCLUDE);
  104.             }
  105.             /* "-i 3-5" or "-i3-5"  Consider the latter case first */
  106.             if (!argv[0][++n])
  107.             argv++, n = 0;
  108.             (*argv) += n;
  109.             m = get_msg_list(argv, list);
  110.             (*argv) -= n;
  111.             if (m == -1)
  112.             return -1;
  113.             /* if there were args, then go back to the first char
  114.              * in the next argv
  115.              */
  116.             if (m)
  117.             n = 0;
  118.             if (!n) /* n may be 0 from above! */
  119.             argv += (m-1);
  120.         }
  121.         otherwise:
  122.             if (argv[0][n] != '?')
  123.             wprint("%c: unknown option\n", argv[0][n]);
  124.             wprint("available options\n");
  125. #ifdef VERBOSE_ARG
  126.             wprint("v      verbose (passed to mail delivery system)\n");
  127. #endif /* VERBOSE_ARG */
  128.             wprint("e      immediately enter editor (autoedit)\n");
  129.             wprint("F      add fortune to the end of message.\n");
  130.             wprint("s [subject]  prompt for or set subject.\n");
  131.             wprint("i [msg#'s]   include msg_list into letter.\n");
  132.             wprint("h [msg#'s]   include msg_list with headers.\n");
  133.             wprint("f [msg#'s]   forward msg_list (not indented).\n");
  134.             return -1;
  135.         }
  136.     }
  137.     *in_reply_to = *To = *Subject = *Cc = *Bcc = 0;
  138.     if (lower(firstchar) == 'r') {
  139.     char *old_fmt = hdr_format;
  140.     to = reply_to(current_msg, (firstchar == 'R'), To);
  141.     if (firstchar == 'R')
  142.         cc = cc_to(current_msg, Cc);
  143.     if (do_set(set_options, "auto_route"))
  144.         fix_addresses(To, Cc);
  145.     if (hdr_format = do_set(set_options, "in_reply_to"))
  146.         (void) strcpy(in_reply_to, compose_hdr(current_msg)+9); /* magic# */
  147.     hdr_format = old_fmt;
  148.     }
  149.     if (ison(flgs, FORWARD) ||
  150.         lower(firstchar) == 'r' && isoff(flgs, NEW_SUBJECT)) {
  151.     char buf[sizeof(Subject)];
  152.     if (ison(flgs, NEW_SUBJECT))
  153.         print("Forwarded mail can't have subject changed.\n");
  154.     turnoff(flgs, NEW_SUBJECT);
  155.     if (subj = subject_to(current_msg, buf))
  156.         subj = strcpy(Subject, buf + 4*(lower(firstchar) != 'r'));
  157.     } else if (isoff(flgs, NEW_SUBJECT) && do_set(set_options, "ask"))
  158.     turnon(flgs, NEW_SUBJECT);
  159.     if (argv && *argv) {
  160.     char buf[BUFSIZ];
  161.     (void) argv_to_string(buf, argv);
  162.     fix_up_addr(buf);
  163.     to = &To[strlen(To)];
  164.     if (*To)
  165.         to += Strcpy(to-1, ", ") - 1;
  166.     (void) strcpy(to, buf);
  167.     to = To;
  168.     }
  169.     if (do_set(set_options, "fortune"))
  170.     turnon(flgs, DO_FORTUNE);
  171. #ifdef SUNTOOL
  172.     if (istool) {
  173.     do_clear();
  174.     panel_set(abort_item,   PANEL_SHOW_ITEM, TRUE,  0);
  175.     panel_set(comp_item,    PANEL_SHOW_ITEM, FALSE, 0);
  176.     panel_set(read_item,    PANEL_SHOW_ITEM, FALSE, 0);
  177.     panel_set(respond_item, PANEL_SHOW_ITEM, FALSE, 0);
  178.     }
  179. #endif /* SUNTOOL */
  180.     return mail_someone(to, subj, cc, flgs, list);
  181. }
  182.  
  183. #ifdef SUNTOOL
  184. /* panel item selection -- it's here because of local (static) variables */
  185. abort_mail(item, value)
  186. Panel_item item;
  187. {
  188.     get_hdr_field = 0;
  189.     if (item == abort_item && value != 2) {
  190.     print("Aborted letter.");
  191.     killme = 1, rm_edfile(SIGINT);
  192.     flags = 0;
  193.     }
  194.     panel_set(comp_item,    PANEL_SHOW_ITEM, TRUE,  0);
  195.     panel_set(send_item,    PANEL_SHOW_ITEM, FALSE, 0);
  196.     panel_set(edit_item,    PANEL_SHOW_ITEM, FALSE, 0);
  197.     panel_set(abort_item,   PANEL_SHOW_ITEM, FALSE, 0);
  198.     panel_set(read_item,    PANEL_SHOW_ITEM, TRUE,  0);
  199.     panel_set(respond_item, PANEL_SHOW_ITEM, TRUE,  0);
  200.     turnoff(glob_flags, IS_GETTING);
  201.     unlock_cursors();
  202. }
  203. #endif /* SUNTOOL */
  204.  
  205. mail_someone(to, subject, cc, flgs, list)
  206. register char *to, *subject, *cc, *list;
  207. u_long flgs;
  208. {
  209.     register char *p;
  210.  
  211.     flags = flgs;
  212. #ifdef SUNTOOL
  213.     if (istool)
  214.     rite(_tty.sg_kill), do_clear();
  215. #endif /* SUNTOOL */
  216.     if (to && *to) {
  217.     if (!*To)
  218.         (void) strncpy(To, to, sizeof(To));
  219.     if (istool)
  220.         wprint("To: %s\n", To);
  221.     } else
  222. #ifdef SUNTOOL
  223.     if (istool)
  224.         turnon(get_hdr_field, TO_FIELD);
  225.     else
  226. #endif /* SUNTOOL */
  227.         to = NO_STRING;
  228.     if (subject && *subject) {
  229.     if (!*Subject)
  230.         (void) strncpy(Subject, subject, sizeof(Subject));
  231.     if (istool)
  232.         wprint("Subject: %s\n", Subject);
  233.     } else
  234. #ifdef SUNTOOL
  235.     if (istool && !*Subject && ison(flags, NEW_SUBJECT))
  236.         turnon(get_hdr_field, SUBJECT);
  237.     else
  238. #endif /* SUNTOOL */
  239.         subject = NO_STRING;
  240.     if (cc && *cc) {
  241.     if (!*Cc)
  242.         (void) strncpy(Cc, cc, sizeof(Cc));
  243.     if (istool)
  244.         wprint("Cc: %s\n", Cc);
  245.     } else
  246. #ifdef SUNTOOL  /* get_hdr_field -- prevents prompting on reply and forward */
  247.     if (istool && get_hdr_field && do_set(set_options, "askcc"))
  248.         turnon(get_hdr_field, CC_FIELD);
  249.     else
  250. #endif /* SUNTOOL */
  251.         cc = NO_STRING;
  252.  
  253.     if (ison(glob_flags, REDIRECT)) {
  254.     send_it(); /* doesn't return */
  255.     return 0;
  256.     }
  257.     /* if (!*to) then prompting will be done */
  258.     if (!istool) {
  259.     if (!(p = set_header("To: ", to, !*to)) || !*p) {
  260.         puts("No recipients, can't mail.");
  261.         return -1;
  262.     }
  263.     if (!*to) /* if user typed To-line here, fix up the address line */
  264.         fix_up_addr(p);
  265.     (void) strcpy(To, p);
  266.     /* don't prompt for subject if forwarding mail */
  267.     if (p = set_header("Subject: ", subject,
  268.         !*subject && ison(flags, NEW_SUBJECT)))
  269.         (void) strcpy(Subject, p);
  270.     if (*Cc)
  271.         printf("Cc: %s\n", Cc);
  272.     putchar('\n');
  273.     }
  274. #ifdef SUNTOOL
  275.     else if (!get_hdr_field) {
  276.     panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  277.     panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  278.     }
  279. #endif /* SUNTOOL */
  280.     return start_file(list);
  281. }
  282.  
  283. start_file(list)
  284. char *list;
  285. {
  286.     register char  *home;
  287.     register int   i;
  288.     char         line[MAXPATHLEN];
  289.  
  290.     if (!(home = do_set(set_options, "home")) || !*home)
  291. alted:
  292.     home = ALTERNATE_HOME;
  293.     (void) mktemp(sprintf(line, "%s/%s", home, EDFILE));
  294.     strdup(edfile, line);
  295.     {
  296.     int omask = umask(077);
  297.     ed_fp = fopen(edfile, "w+");
  298.     (void) umask(omask);
  299.     if (!ed_fp) {
  300.         if (home != ALTERNATE_HOME)
  301.         goto alted;
  302. #ifdef SUNTOOL
  303.         if (istool)
  304.         abort_mail(NO_ITEM, 0);
  305. #endif /* SUNTOOL */
  306.         error("can't create %s", edfile);
  307.         return -1;
  308.     }
  309.     }
  310.     if (!istool) {
  311.     oldint = signal(SIGINT, rm_edfile);
  312.     oldquit = signal(SIGQUIT, rm_edfile);
  313.     oldterm = signal(SIGTERM, rm_edfile);
  314.     }
  315.  
  316.     /* if flags call for it, include current message (with header?) */
  317.     if (ison(flags, INCLUDE) || ison(flags,FORWARD) || ison(flags,INCLUDE_H)) {
  318.     long copy_flgs = 0, is_forw = ison(flags, FORWARD);
  319.     char buf[sizeof(To)];
  320.     if (!is_forw)
  321.         turnon(copy_flgs, INDENT);
  322.     if (ison(flags, INCLUDE))
  323.         turnon(copy_flgs, NO_HEADER);
  324.     if (ison(flags, INCLUDE) || ison(flags, FORWARD))
  325.         turnon(copy_flgs, NO_IGNORE);
  326. #ifdef SUNTOOL
  327.     if (istool)
  328.         lock_cursors();
  329. #endif /* SUNTOOL */
  330.     for (i = 0; i < msg_cnt; i++)
  331.         if (msg_bit(list, i)) {
  332.         if (is_forw && ison(flags, EDIT)) {
  333.             (void) reply_to(i, FALSE, buf);
  334.             fprintf(ed_fp, "--- Forwarded mail from %s\n\n", buf);
  335.         }
  336.         wprint("%sing message %d ...",
  337.             is_forw? "forward" : "includ", i+1);
  338.         wprint("(%d lines)\n", copy_msg(i, ed_fp, copy_flgs));
  339.         set_isread(i); /* if we included it, we read it, right? */
  340.         if (is_forw && ison(flags, EDIT))
  341.             fprintf(ed_fp,
  342.             "\n--- End of forwarded message from %s\n", buf);
  343.         }
  344.     fflush(ed_fp);
  345. #ifdef SUNTOOL
  346.     if (istool)
  347.         unlock_cursors();
  348. #endif /* SUNTOOL */
  349.     }
  350.     if (ison(glob_flags, WARNING)) {
  351.     if (escape && *escape != DEF_ESCAPE[0])
  352.         wprint("(escape character is set to `%c')\n", *escape);
  353.     }
  354.     turnon(glob_flags, IS_GETTING);
  355.     /* enter editor if autoedit and not toolmode */
  356.     if (
  357. #ifdef SUNTOOL
  358.         (!istool || !get_hdr_field) &&
  359. #endif /* SUNTOOL */
  360.     /* do an "if" again in case editor not found and EDIT turned off */
  361.                     ison(flags, EDIT)) {
  362.     char *argv[3];
  363.     if (!(argv[0] = do_set(set_options, "visual")) || !*argv[0])
  364.         argv[0] = DEF_EDITOR;
  365.     argv[1] = edfile;
  366.     argv[2] = NULL;
  367.     print("Starting \"%s\"...\n", argv[0]);
  368.     fclose(ed_fp);
  369.     ed_fp = NULL_FILE;
  370.     execute(argv);
  371.     turnoff(flags, EDIT);
  372.     turnoff(flags, FORWARD); /* forwarded messages must be unedited */
  373.     /* upon exit of editor, user must now type ^D or "." to send */
  374.     if (istool)
  375.         return 0;
  376.     if (!(ed_fp = fopen(edfile, "r+"))) {
  377.         error("can't reopen %s", edfile);
  378.         return -1;
  379.     }
  380.     (void) fseek(ed_fp, 0L, 2);
  381.     puts("continue editing letter or ^D to send");
  382.     } else if (ison(flags, FORWARD) &&
  383. #ifdef SUNTOOL
  384.            (!istool || !get_hdr_field) &&
  385. #endif /* SUNTOOL */
  386.            finish_up_letter())
  387.     return 0; /* if forwarding mail, check to see if tool requires To: */
  388. #ifdef SUNTOOL
  389.     if (istool) {
  390.     /* If toolmode, we're ready for IO. Give first prompt if not given */
  391.     if (ison(get_hdr_field, TO_FIELD))
  392.         wprint("To: ");
  393.     else if (ison(get_hdr_field, SUBJECT))
  394.         wprint("Subject: ");
  395.     else if (ison(get_hdr_field, CC_FIELD))
  396.         wprint("Cc: ");
  397.     type_cursor(PIX_SRC);
  398.     win_setcursor(msg_sw->ts_windowfd, &write_cursor);
  399.     return 0;
  400.     }
  401. #endif /* SUNTOOL */
  402.     i = 0;
  403.     do  {
  404.     /* If the user hits ^C in cbreak mode, mush will return to
  405.      * Getstr and not clear the buffer. whatever is typed next will
  406.      * be appended to the line.  jumping here will force the line to
  407.      * be cleared cuz it's a new call.
  408.      */
  409.     (void) setjmp(cntrl_c_buf);
  410.     while (Getstr(line, sizeof(line), 0) > -1)
  411.         if ((i = add_to_letter(line)) <= 0)
  412.         break;
  413.     } while (i >= 0 && !finish_up_letter());
  414.     return i; /* return -1 if ~x or ~q to terminate letter */
  415. }
  416.  
  417. char *tilde_commands[] = {
  418.     "commands: [OPTIONAL argument]",
  419.     "e [editor]\tEnter editor. Editor used: \"set editor\", env EDITOR, vi",
  420.     "v [editor]\tEnter visual editor. \"set visual\", env VISUAL, vi",
  421.     "p [pager]\tPage message; pager used: \"set pager\", env. PAGER, more",
  422.     "i [msg#'s]\tInclude current msg body [msg#'s] indented by \"indent_str\"",
  423.     "H [msg#'s]\tSame, but include the message headers from included messages",
  424.     "f [msg#'s]\tForward mail. Not indented, but marked as \"forwarded mail\"",
  425.     "t [list]\tChange list of recipients",
  426.     "s [subject]\tModify [set] subject header",
  427.     "c [cc list]\tModify [set] carbon copy recipients",
  428.     "b [bcc list]\tModify [set] blind carbon recipients",
  429.     "h\t\tModify all message headers",
  430.     "S[!]\t\tInclude Signature file [suppress file]",
  431.     "F[!]\t\tAdd a fortune at end of letter [don't add]",
  432.     "w file\t\tWrite msg buffer to file name",
  433.     "a file\t\tAppend msg buffer to file name",
  434.     "r file\t\tRead filename into message buffer",
  435.     "q \t\tQuit message; save in dead.letter (unless \"nosave\" is set).",
  436.     "x \t\tQuit message; don't save in dead.letter.",
  437.     "$variable\tInsert the string value for \"variable\" into message.",
  438.     ":cmd\t\tRun the mail command \"cmd\".",
  439.     "u\t\tedit previous line in file.",
  440.     "E[!]\t\tClear contents of letter after saving to dead.letter [unless !].",
  441.     0
  442. };
  443.  
  444. /*
  445.  * Add the line (char *) parameter to the letter.  Determine tilde
  446.  * escapes and determine what to do.  This function returns 0 to
  447.  * indicate user wants to end the letter, -1 if the letter cannot
  448.  * be sent (~q, ~x no buffer after editor, etc...) or 1 to indicate
  449.  * successful addition of the line to the letter.
  450.  */
  451. add_to_letter(line)
  452. register char *line;
  453. {
  454.     register char *p;
  455.     char buf[BUFSIZ];
  456.  
  457.     killme = 0;
  458.     (void) fseek(ed_fp, 0L, 2);
  459. #ifdef SUNTOOL
  460.     if (get_hdr_field) {
  461.     /* These are received in order by design! */
  462.     if (ison(get_hdr_field, TO_FIELD)) {
  463.         if (!*line) {
  464.             wprint("There must be a recipient!\nTo: ");
  465.         return 1;
  466.         }
  467.         fix_up_addr(line);
  468.         (void) strcpy(To, line), turnoff(get_hdr_field, TO_FIELD);
  469.     } else if (ison(get_hdr_field, SUBJECT)) {
  470.         (void) strcpy(Subject, line);
  471.         turnoff(get_hdr_field, SUBJECT);
  472.     } else if (ison(get_hdr_field, CC_FIELD)) {
  473.         fix_up_addr(line);
  474.         (void) strcpy(Cc, line);
  475.         turnoff(get_hdr_field, CC_FIELD);
  476.     } else if (ison(get_hdr_field, BC_FIELD)) {
  477.         fix_up_addr(line);
  478.         (void) strcpy(Bcc, line);
  479.         turnoff(get_hdr_field, BC_FIELD);
  480.     }
  481.  
  482.         if (ison(get_hdr_field, SUBJECT))
  483.         (void) set_header("Subject: ", Subject, 1);
  484.         else if (ison(get_hdr_field, CC_FIELD))
  485.         (void) set_header("Cc: ", Cc, 1);
  486.         else if (ison(get_hdr_field, BC_FIELD))
  487.         (void) set_header("Bcc: ", Bcc, 1);
  488.     panel_set(send_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  489.     panel_set(edit_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  490.     if (!get_hdr_field) {
  491.         wprint("\n");
  492.         if (ison(flags, EDIT)) {
  493.         (void) add_to_letter(sprintf(line, "%cv", *escape));
  494.         turnoff(flags, EDIT);
  495.         }
  496.     }
  497.     return 1;
  498.     }
  499. #endif /* SUNTOOL */
  500.     if (!strcmp(line, ".") && (istool || do_set(set_options, "dot")))
  501.     return 0;
  502.     if (*line != *escape) {
  503.     fputs(line, ed_fp), fputc('\n', ed_fp), fflush(ed_fp);
  504.     return 1;
  505.     }
  506.     /* all commands are "~c" (where 'c' is the command). set p = first
  507.      * character after 'c' and skip whitespace
  508.      */
  509.     p = line+2;
  510.     skipspaces(0);
  511.     switch (line[1]) {
  512.     case 'v' : case 'p': case 'e': {
  513.         if (!*p || *p == 'i' && !p[1])
  514.         switch (line[1]) {
  515.             case 'p' :
  516.             if (!(p = do_set(set_options, "pager")))
  517.                 p = DEF_PAGER;
  518.             if (!*p || !strcmp(p, "internal"))
  519.                 p = NULL;
  520.             when 'v' :
  521.             if (p = do_set(set_options, "visual"))
  522.                 break;
  523.             default :
  524.             if (!(p = do_set(set_options, "editor")) || !*p)
  525.                 p = DEF_EDITOR;
  526.         }
  527.         if (line[1] == 'p') {
  528.         rewind(ed_fp);
  529.         (void) do_pager(p, TRUE); /* start the pager "p" */
  530.         do_pager(sprintf(buf, "To: %s\n", To), FALSE);
  531.         if (Subject[0])
  532.             do_pager(sprintf(buf, "Subject: %s\n", Subject), FALSE);
  533.         if (Cc[0])
  534.             do_pager(sprintf(buf, "Cc: %s\n", Cc), FALSE);
  535.         if (Bcc[0])
  536.             do_pager(sprintf(buf, "Bcc: %s\n", Bcc), FALSE);
  537.         do_pager(strcpy(buf, "--------\nMessage contains:\n"), FALSE);
  538.         while (fgets(buf, sizeof(buf), ed_fp))
  539.             if (do_pager(buf, FALSE) == EOF)
  540.             break;
  541.         (void) do_pager(NULL, FALSE); /* end pager */
  542.         } else {
  543.         char *argv[3];
  544.         argv[0] = p;
  545.         argv[1] = edfile;
  546.         argv[2] = NULL;
  547.         fclose(ed_fp);
  548.         ed_fp = NULL_FILE;
  549.         execute(argv); /* tool will return even tho editor isn't done */
  550.         if (istool)
  551.             return 1;
  552.         if (!(ed_fp = fopen(edfile, "r+"))) {
  553.             error("can't reopen %s", edfile);
  554.             return -1;
  555.         }
  556.         }
  557.     }
  558.     when '$': {
  559.         register char *p2;
  560.         if (!(p2 = do_set(set_options, p)))
  561.         wprint("(%s isn't set)\n", p);
  562.         else
  563.         fprintf(ed_fp, "%s\n", p2);
  564.     }
  565.     when ':': {
  566.         char new[MAXMSGS_BITS];
  567.         u_long save_flags = glob_flags;
  568.  
  569.         turnon(glob_flags, IGN_SIGS);
  570.         turnon(glob_flags, IGN_BANG);
  571.         turnoff(glob_flags, DO_PIPE);
  572.         turnoff(glob_flags, IS_PIPE);
  573.         (void) cmd_line(p, new);
  574.         glob_flags = save_flags;
  575. #ifdef SUNTOOL
  576.         if (istool && msg_pix) /* the command was to read a message */
  577.         return 1;
  578. #endif /* SUNTOOL */
  579.     }
  580.     when 'i': case 'f': case 'H': case 'm': {
  581.         int  n;
  582.         long copy_flgs = 0;
  583.         char list[MAXMSGS_BITS];
  584.  
  585.         if (!msg_cnt) {
  586.         print("No messages.\n");
  587.         break;
  588.         }
  589.         clear_msg_list(list);
  590.         if (line[1] != 'f')
  591.         turnon(copy_flgs, INDENT);
  592.         if (line[1] == 'i')
  593.         turnon(copy_flgs, NO_HEADER);
  594.         if (!*p)
  595.         set_msg_bit(list, current_msg);
  596.         else if (!do_range(p, list))
  597.         return 1;
  598. #ifdef SUNTOOL
  599.         if (istool)
  600.         lock_cursors();
  601. #endif /* SUNTOOL */
  602.         for (n = 0; n < msg_cnt; n++)
  603.         if (msg_bit(list, n)) {
  604.             if (line[1] == 'f') {
  605.             (void) reply_to(n, FALSE, buf);
  606.             fprintf(ed_fp, "--- Forwarded mail from %s\n\n", buf);
  607.             }
  608.             wprint("Including message %d ... ", n+1);
  609.             wprint("(%d lines)\n", copy_msg(n, ed_fp, copy_flgs));
  610.             set_isread(n);
  611.             if (line[1] == 'f')
  612.         fprintf(ed_fp,"\n--- End of forwarded message from %s\n\n",buf);
  613.         }
  614. #ifdef SUNTOOL
  615.         if (istool)
  616.         unlock_cursors();
  617. #endif /* SUNTOOL */
  618.     }
  619.     when 't':
  620. #ifdef SUNTOOL
  621.         if (!*p && istool) {
  622.         turnon(get_hdr_field, TO_FIELD);
  623.         (void) set_header("To: ", To, 1);
  624.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  625.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  626.         return 1;
  627.         }
  628. #endif /* SUNTOOL */
  629.         /* ~t address   is a special case ... append to address */
  630.         if (*p) {
  631.         fix_up_addr(p);
  632.         (void) sprintf(To+strlen(To), ", %s", p);
  633.         } else if (p = set_header("To: ", To, 1))
  634.         if (!*p) {
  635.             wprint("There must be a recipient!\n");
  636. #ifdef SUNTOOL
  637.             turnoff(get_hdr_field, TO_FIELD);
  638.             panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  639.             panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  640. #endif /* SUNTOOL */
  641.         } else {
  642.             fix_up_addr(p);
  643.             (void) strcpy(To, p);
  644.         }
  645.     when 's':
  646. #ifdef SUNTOOL
  647.         if (!*p && istool) {
  648.         turnon(get_hdr_field, SUBJECT);
  649.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  650.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  651.         (void) set_header("Subject: ", Subject, 1);
  652.         return 1;
  653.         }
  654. #endif /* SUNTOOL */
  655.         if (*p || (p = set_header("Subject: ", Subject, 1)))
  656.         if (!*p)
  657.             Subject[0] = 0;
  658.         else
  659.             (void) strcpy(Subject, p);
  660.     when 'c':
  661. #ifdef SUNTOOL
  662.         if (!*p && istool) {
  663.         turnon(get_hdr_field, CC_FIELD);
  664.         (void) set_header("Cc: ", Cc, 1);
  665.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  666.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  667.         return 1;
  668.         }
  669. #endif /* SUNTOOL */
  670.         if (*p || (p = set_header("Cc: ", Cc, 1)))
  671.         if (!*p)
  672.             Cc[0] = 0;
  673.         else {
  674.             fix_up_addr(p);
  675.             (void) strcpy(Cc, p);
  676.         }
  677.     when 'b':
  678. #ifdef SUNTOOL
  679.         if (!*p && istool) {
  680.         turnon(get_hdr_field, BC_FIELD);
  681.         (void) set_header("Bcc: ", Bcc, 1);
  682.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  683.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  684.         return 1;
  685.         }
  686. #endif /* SUNTOOL */
  687.         if (*p || (p = set_header("Bcc: ", Bcc, 1)))
  688.         if (!*p)
  689.             Bcc[0] = 0;
  690.         else {
  691.             fix_up_addr(p);
  692.             (void) strcpy(Bcc, p);
  693.         }
  694.     when 'h':
  695. #ifdef SUNTOOL
  696.         if (istool) {
  697.         turnon(get_hdr_field, TO_FIELD);
  698.         turnon(get_hdr_field, SUBJECT);
  699.         turnon(get_hdr_field, CC_FIELD);
  700.         turnon(get_hdr_field, BC_FIELD);
  701.         (void) set_header("To: ", To, 1);
  702.         panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  703.         panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  704.         return 1;
  705.         }
  706. #endif /* SUNTOOL */
  707.         while ((p = set_header("To: ", To, 1)) && !*p)
  708.         wprint("(There must be a recipient.)\n");
  709.         (void) strcpy(To, p);
  710.         if (p = set_header("Subject: ", Subject, 1))
  711.         if (!*p)
  712.             Subject[0] = 0;
  713.         else
  714.             (void) strcpy(Subject, p);
  715.         if (p = set_header("Cc: ", Cc, 1))
  716.         if (!*p)
  717.             Cc[0] = 0;
  718.         else {
  719.             fix_up_addr(p);
  720.             (void) strcpy(Cc, p);
  721.         }
  722.         if (p = set_header("Bcc: ", Bcc, 1))
  723.         if (!*p)
  724.             Bcc[0] = 0;
  725.         else {
  726.             fix_up_addr(p);
  727.             (void) strcpy(Bcc, p);
  728.         }
  729.     when 'S':
  730.         if (*p == '!')
  731.         turnoff(flags, SIGN), wprint("not ");
  732.         else
  733.         turnon(flags, SIGN);
  734.         wprint("adding signature file at end of message.\n");
  735.     when 'F':
  736.         if (*p == '!')
  737.         turnoff(flags, DO_FORTUNE), wprint("not ");
  738.         else
  739.         turnon(flags, DO_FORTUNE);
  740.         wprint("adding fortune at end of message.\n");
  741.     when 'w': case 'a': case 'r':
  742.         if (!*p) {
  743.         wprint("(you must specify a filename)\n");
  744.         return 1;
  745.         }
  746.         (void) fseek(ed_fp, 0L, 2); /* append */
  747.         file_to_fp(p, ed_fp, (line[1] == 'r')? "r":
  748.                   (line[1] == 'w')? "w": "a");
  749.     /* go up one line in the message file and allow the user to edit it */
  750.     when 'u': {
  751.         long newpos, pos = ftell(ed_fp);
  752.         char oldline[256];
  753.         if (istool) {
  754.         wprint("(Not available in tool mode.)\n");
  755.         return 1;
  756.         }
  757.         if (pos <= 0L) { /* pos could be -1 if ftell() failed */
  758.         wprint("(No previous line in file.)\n");
  759.         return 1;
  760.         }
  761.         /* get the last 256 bytes written and read backwards from the
  762.          * current place until '\n' is found. Start by moving past the
  763.          * first \n which is at the end of the line we want to edit
  764.          */
  765.         newpos = max(0, pos - 256L);
  766.         (void) fseek(ed_fp, newpos, L_SET);
  767.         /* don't fgets -- it'll stop at a \n */
  768.         (void) read(fileno(ed_fp), line, (int)(pos-newpos));
  769.         pos--;
  770.         /* the last char in line should be a \n cuz it was last input */
  771.         if (line[(int)(pos-newpos)] != '\n')
  772.         wprint("I don't know how, but your last line ended with %c.\n",
  773.             line[(int)(pos-newpos)]);
  774.         else
  775.         line[(int)(pos-newpos)] = 0; /* null terminate \n for ^H-ing */
  776.         for (pos--; pos > newpos && line[(int)(pos-newpos)] != '\n'; pos--)
  777.         ;
  778.         /* we've gone back to the end of the second previous line. Check
  779.          * to see if the char we're pointing to is a \n.  It should be, but
  780.          * if it's not, we moved back to the first line of the file.
  781.          */
  782.         if (line[(int)(pos-newpos)] == '\n')
  783.         ++pos;
  784.         /* save the old line that's there in case the user boo-boo's */
  785.         (void) strcpy(oldline, line+(int)(pos-newpos));
  786.         /* let set header print out the line and get the input */
  787.         if (!(p = set_header("", line+(int)(pos-newpos), TRUE))) {
  788.         wprint("Something bad happened and I don't know what it is.\n");
  789.         p = oldline;
  790.         } else if (*p == *escape && *++p != *escape) {
  791.         wprint("(No %c escapes on %cu lines. Line unchanged.)\n",
  792.                 *escape, *escape);
  793.         p = oldline;
  794.         }
  795.         /* seek to to the position where the new line will go */
  796.         (void) fseek(ed_fp, pos, L_SET);
  797.         /* put the newly typed line */
  798.         (void) fputs(p, ed_fp); /* don't add \n. padding may be necessary */
  799.         /* if the new line is less than the old line, we're going to do
  800.          * one of two things.  The best thing to do is to truncate the
  801.          * file to the end of the new line.  Sys-v can't do that, so we
  802.          * pad the line with blanks.  May be messy in some cases, but...
  803.          */
  804.         if ((pos = strlen(p) - strlen(oldline)) < 0) {
  805. #ifndef SYSV
  806.         /* add the \n, flush the file, truncate to the current pos */
  807.         fputc('\n', ed_fp), fflush(ed_fp);
  808.         (void) ftruncate(fileno(ed_fp), (int)ftell(ed_fp));
  809. #else
  810.         /* pad with blanks to the length of the old line. add \n */
  811.         while (pos++ < 0)
  812.             fputc(' ', ed_fp);
  813.         fputc('\n', ed_fp), fflush(ed_fp);
  814. #endif /* SYSV */
  815.         } else
  816.         /* the new line is >= the old line, add \n -- no trunc req. */
  817.             fputc('\n', ed_fp);
  818.         return 1;
  819.      }
  820.     /* break;  not here cuz of "return" (lint). */
  821.     case 'E':
  822.         if (*p != '!' && !do_set(set_options, "nosave"))
  823.         dead_letter();
  824.         if (emptyfile(&ed_fp, edfile) == -1)
  825.         error(edfile);
  826.         else
  827.         wprint("Message buffer empty\n");
  828.     when 'q':
  829.         /* save in dead.letter if nosave not set -- rm_edfile(-2). */
  830.         rm_edfile(-2); /* doesn't return out of tool mode */
  831.         return -1;
  832.         /* break; not stated cuz of "return" (lint) */
  833.     case 'x':
  834.         /* don't save dead.letter -- simulate normal rm_edfile() call */
  835.         rm_edfile(0);
  836. #ifdef SUNTOOL
  837.         if (istool) {
  838.         wprint("*Letter aborted*");
  839.         type_cursor(PIX_CLR);
  840.         }
  841. #endif /* SUNTOOL */
  842.         return -1;
  843.         /* break; (not specified for lint) */
  844.     default:
  845.         if (line[1] == *escape) {
  846.         fputs(line+1, ed_fp), fputc('\n', ed_fp), fflush(ed_fp);
  847.         return 1;
  848.         } else if (line[1] == '?') {
  849.         register int x;
  850.         for (x = 0; tilde_commands[x]; x++)
  851.             wprint("%s%s\n", escape, tilde_commands[x]);
  852.         wprint("%s%s\t\tbegin a line with a single %s\n",
  853.             escape, escape, escape);
  854. #ifdef SUNTOOL
  855.         if (istool)
  856.             (void) help(0, "compose", tool_help);
  857. #endif /* SUNTOOL */
  858.         } else
  859.         wprint("`%c': unknown %c escape. Use %c? for help.\n",
  860.             line[1], *escape, *escape);
  861.     }
  862.     (void) fseek(ed_fp, 0L, 2); /* seek to end of file in case there's more */
  863.     wprint("(continue editing letter)\n");
  864.     return 1;
  865. }
  866.  
  867. /*
  868.  * finish up the letter. ask for the cc line, if verify is set, ask to
  869.  * verify sending, continue editing, or to dump the whole idea.
  870.  * Then check for signature and fortune.  Finally, pass it to send_it()
  871.  * to actually send it off.
  872.  */
  873. finish_up_letter()
  874. {
  875.     register char *p;
  876.     int c;
  877.     char buf[MAXPATHLEN];
  878.  
  879.     /* forwarded mail has no additional peronalized text */
  880.     if (ison(flags, FORWARD)) {
  881.     send_it();
  882.     turnoff(glob_flags, IS_GETTING);
  883.     return 1;
  884.     }
  885.  
  886.     if (isoff(glob_flags, REDIRECT)) {
  887.     if (!istool &&
  888.         do_set(set_options, "askcc") && (p = set_header("Cc: ", Cc, 1)))
  889.         (void) strcpy(Cc, p);
  890.     /* ~v on the Cc line asks for verification, first initialize p! */
  891.     p = NULL;
  892.     if (!strncmp(Cc, "~v", 2) || (p = do_set(set_options, "verify"))) {
  893.         if (!p) /* so we don't Cc to ~v! */
  894.         *Cc = 0;
  895.         for (;;) {
  896. #ifdef SUNTOOL
  897.         if (istool) {
  898.             type_cursor(PIX_CLR);
  899.             print("Send, Continue, Discard [Left, Middle, Right]?");
  900.             c = confirm(msg_sw->ts_windowfd);
  901.             clr_bot_line(); /* really: clears print window */
  902.             if (isascii(c))
  903.             Lower(c);
  904.             else switch(c) {
  905.             when MS_LEFT : c = 's';
  906.             when MS_MIDDLE : c = 'c';
  907.             when MS_RIGHT : c = 'd';
  908.             otherwise: c = 0;
  909.             }
  910.         } else
  911. #endif /* SUNTOOL */
  912.         {
  913.             print("send, continue editing, discard [s,c,d]? ");
  914.             c = Getstr(buf, sizeof(buf), 0);
  915.         }
  916.         if (c < 0)
  917.             putchar('\n');
  918.         else if (!istool)
  919.             c = lower(*buf);
  920.         if (c == 'd') {
  921.             rm_edfile(-2);
  922.             return 1;
  923.         } else if (c == 'c') {
  924.             wprint("(continue editing letter)\n");
  925. #ifdef SUNTOOL
  926.             if (istool)
  927.             type_cursor(PIX_SRC);
  928. #endif /* SUNTOOL */
  929.             return 0;
  930.         } else if (c == 's')
  931.             break;
  932.         }
  933.     }
  934.     }
  935.  
  936. #ifdef SUNTOOL
  937.     if (istool)
  938.     lock_cursors();
  939. #endif /* SUNTOOL */
  940.     send_it();
  941.     turnoff(glob_flags, IS_GETTING);
  942.     return 1;
  943. }
  944.  
  945. /*
  946.  * actually send the letter.
  947.  * 1. reset all the signals because of fork.
  948.  * 2. determine recipients (users, address, files, programs)
  949.  * 3. determine mailer, fork and return (if not verbose).
  950.  * 4. popen mailer, $record, and other files specified in step 1.
  951.  * 5. make the headers; this includes To: line, and user set headers, etc...
  952.  * 6. copy the letter right into the array of file pointers (step 1).
  953.  * 7. close the mailer and other files (step 1) and remove the edit-file.
  954.  */
  955. static void
  956. send_it()
  957. {
  958.     register char *p, *b, *addr_list;
  959. #ifdef MAXFILES
  960.     register int size = MAXFILES - 1;
  961.     FILE *files[MAXFILES];
  962. #else
  963.     register int size = getdtablesize() - 1;
  964.     FILE *files[30];  /* 30 should be sufficiently large enough */
  965. #endif /* MAXFILES */
  966.     int next_file = 1; /* reserve files[0] for the mail delivery program */
  967.     char buf[3*BUFSIZ];
  968.     char expand = !do_set(set_options, "no_expand");
  969.  
  970.     if (!istool) {
  971.     (void) signal(SIGINT, oldint);
  972.     (void) signal(SIGQUIT, oldquit);
  973.     (void) signal(SIGTERM, oldterm);
  974.     }
  975.  
  976.     if (!(p = do_set(set_options, "sendmail")))
  977.     p = MAIL_DELIVERY;
  978.  
  979. #ifdef VERBOSE_ARG
  980.     if (ison(flags, VERBOSE) || do_set(set_options, "verbose"))
  981.     b = &buf[strlen(sprintf(buf, "%s %s", p, VERBOSE_ARG))];
  982.     else
  983. #endif /* VERBOSE_ARG */
  984.     b = buf + Strcpy(buf, p);
  985. #ifdef METOO_ARG
  986.     if (!strcmp(p, MAIL_DELIVERY) && do_set(set_options, "metoo"))
  987.     b += strlen(sprintf(b, " %s", METOO_ARG));
  988. #endif /* METOO_ARG */
  989.     *b++ = ' ', *b = 0; /* strcat(b, " "); */
  990.     addr_list = b; /* save this position to check for addresses later */
  991.  
  992.     /*
  993.      * Build the address lines to give to the mail transfer system.  This
  994.      * address line connot contain comment fields!  First, expand aliases
  995.      * since they may contain comment fields within addresses. Copy this
  996.      * result back into the Buffer since this will go into the header ...
  997.      * Next, remove all comments so the buffer contains ONLY valid addresses.
  998.      * Next, strip off any filenames/programs which might occur in the list.
  999.      * Finally, add this information to the command line buffer (buf).
  1000.      * Remove commas if necessary (see ifdef's).  In the event of errors,
  1001.      * force a dead letter by rm_edfile(-1). But, rm_edfile will exit with -1
  1002.      * arg, so kludge by turning on the VERBOSE bit in "flags".
  1003.      */
  1004.     if (!(p = alias_to_address(To))) {
  1005.     print("address expansion failed for To: line.\n");
  1006.     turnon(flags, VERBOSE);
  1007.     rm_edfile(-1);
  1008.     } else {
  1009.     next_file += find_files(p, files+next_file, size - next_file);
  1010.     if (expand)
  1011.         (void) strcpy(To, p);
  1012.     rm_cmts_in_addr(p);
  1013.     skipspaces(0);
  1014.     if (!*p) {
  1015.         print("There must be at least 1 legal recipient on the To line\n");
  1016.         while (--next_file > 1)
  1017.         fclose(files[next_file]);
  1018.         rm_edfile(-2);
  1019.         return;
  1020.     }
  1021.     b += Strcpy(b, p);
  1022.     }
  1023.     if (*Cc) {
  1024.     if (!(p = alias_to_address(Cc))) {
  1025.         print("address expansion failed for Cc: line.\n");
  1026.         turnon(flags, VERBOSE);
  1027.         while (--next_file > 1)
  1028.         fclose(files[next_file]);
  1029.         rm_edfile(-1);
  1030.     } else {
  1031.         next_file += find_files(p, files+next_file, size - next_file);
  1032.         if (expand)
  1033.         (void) strcpy(Cc, p);
  1034.         rm_cmts_in_addr(p);
  1035.         skipspaces(0);
  1036.         if (*p) {
  1037.         *b++ = ',', *b++ = ' ';
  1038.         b += Strcpy(b, p);
  1039.         }
  1040.     }
  1041.     }
  1042.  
  1043.     /* Sign the letter before adding the Bcc list since they aren't
  1044.      * considered when adding a signature.
  1045.      */
  1046.     if (ison(flags, SIGN) && isoff(glob_flags, REDIRECT))
  1047.     sign_letter(addr_list);
  1048.  
  1049.     if (*Bcc) {
  1050.     if (!(p = alias_to_address(Bcc))) {
  1051.         print("address expansion failed for Bcc: line.\n");
  1052.         turnon(flags, VERBOSE);
  1053.         while (--next_file > 1)
  1054.         fclose(files[next_file]);
  1055.         rm_edfile(-1);
  1056.     } else {
  1057.         next_file += find_files(p, files+next_file, size - next_file);
  1058.         (void) strcpy(Bcc, p);
  1059.         rm_cmts_in_addr(p);
  1060.         skipspaces(0);
  1061.         if (*p) {
  1062.         *b++ = ',', *b++ = ' ';
  1063.         b += Strcpy(b, p);
  1064.         }
  1065.     }
  1066.     }
  1067.  
  1068. #ifdef OLD_MAILER
  1069.     for (p = buf; p = index(p, ','); p++)
  1070.     *p = ' ';
  1071. #endif /* OLD_MAILER */
  1072.  
  1073.     Debug("mail command: %s\n", buf);
  1074.  
  1075. #ifdef SUNTOOL
  1076.     if (istool)
  1077.     abort_mail(NO_ITEM, 0);
  1078. #endif /* SUNTOOL */
  1079.  
  1080.     if (isoff(flags, VERBOSE) && debug < 3)
  1081.     switch (fork()) {
  1082.         case  0:  /* the child will send the letter. ignore signals */
  1083. #ifdef SYSV
  1084.         if (setpgrp() == -1)
  1085.             error("setpgrp");
  1086. #endif /* SYSV */
  1087.         (void) signal(SIGINT, SIG_IGN);
  1088.         (void) signal(SIGHUP, SIG_IGN);
  1089.         (void) signal(SIGQUIT, SIG_IGN);
  1090.         (void) signal(SIGTERM, SIG_IGN);
  1091. #ifdef SIGTTIN
  1092.         (void) signal(SIGTTOU, SIG_IGN);
  1093.         (void) signal(SIGTTIN, SIG_IGN);
  1094. #endif /* SIGTTIN */
  1095. #ifdef SIGCONT
  1096.         (void) signal(SIGCONT, SIG_IGN);
  1097.         (void) signal(SIGTSTP, SIG_IGN);
  1098. #endif /* SIGCONT */
  1099.         turnon(glob_flags, IGN_SIGS);
  1100.         break;
  1101.         case -1:
  1102.         error("fork failed trying to send mail");
  1103.         default:
  1104.         if (isoff(glob_flags, REDIRECT))
  1105.             fclose(ed_fp);
  1106. #ifdef SUNTOOL
  1107.                 if (istool) {
  1108.             wprint("Letter sent.");
  1109.             print("Letter sent.");
  1110.             type_cursor(PIX_CLR);
  1111.         }
  1112. #endif /* SUNTOOL */
  1113.         while (--next_file > 0)
  1114.             fclose(files[next_file]);
  1115.         return;
  1116.     }
  1117.  
  1118.     if (debug > 2)
  1119.     files[0] = stdout;
  1120.     else if (!(files[0] = open_file(buf, TRUE))) {
  1121.     rm_edfile(-1); /* force saving of undeliverable mail */
  1122.     return;
  1123.     }
  1124.  
  1125.     if (ison(flags, VERBOSE))
  1126.     wprint("Sending letter ... ");
  1127.  
  1128.     /* see if record is set.  If so, open that file for appending and add
  1129.      * the letter in a format such that mail can be read from it
  1130.      */
  1131.     if (p = do_set(set_options, "record")) {
  1132.     if (!*p)
  1133.         p = "~/record";
  1134.     (void) strcpy(buf, p);
  1135.     next_file += find_files(buf, files+next_file, size - next_file);
  1136.     }
  1137.  
  1138.     /* Make folders conform to RFC-822 by adding From: and Date: headers.
  1139.      * Some older mailers (binmail, execmail, delivermail), don't add
  1140.      * these headers to the MTA, so add them for OLD_MAIL systems.
  1141.      */
  1142.     for (size = 0; size < next_file; size++) {
  1143.     time_t t;
  1144. #ifndef OLD_MAIL
  1145.     if (size == 0)
  1146.         continue;
  1147. #endif /* OLD_MAIL */
  1148.     (void) time(&t);
  1149.     if (size > 0) {
  1150. #ifndef MSG_SEPARATOR
  1151.         fprintf(files[size], "From %s %s", login, ctime(&t));
  1152. #else /* MSG_SEPARATOR */
  1153.         fprintf(files[size], "%s\n", MSG_SEPARATOR);
  1154. #endif /* MSG_SEPARATOR */
  1155.     }
  1156.     fprintf(files[size], "From: %s\n", login);
  1157.     fprintf(files[size], "Date: %s", ctime(&t));
  1158.     }
  1159.  
  1160.     /* first print users own message headers */
  1161.     if (own_hdrs && !do_set(set_options, "no_hdrs")) {
  1162.     struct options *opts;
  1163.     for (opts = own_hdrs; opts; opts = opts->next)
  1164.         for (size = 0; size < next_file; size++)
  1165.         fprintf(files[size], "%s %s\n", opts->option, opts->value);
  1166.     }
  1167.  
  1168.     /* send the header stuff to sendmail and end header with a blank line */
  1169.     for (size = 0; size < next_file; size++) {
  1170.     if (*in_reply_to)
  1171.         fprintf(files[size], "In-Reply-To: %s\n", in_reply_to);
  1172.     fprintf(files[size], "X-Mailer: %s\n", VERSION);
  1173.     fprintf(files[size], "%sTo: %s\n",
  1174.         ison(flags, FORWARD) ? "Resent-" : "", To);
  1175.     if (*Subject)
  1176.         fprintf(files[size], "Subject: %s\n", Subject);
  1177.     if (*Cc)
  1178.         fprintf(files[size], "%sCc: %s\n",
  1179.         ison(flags, FORWARD) ? "Resent-" : "", Cc);
  1180.     if (size > 0) {
  1181.         /* Do not send these to mail transfer agent */
  1182.         if (*Bcc)
  1183.         fprintf(files[size], "Bcc: %s\n", Bcc);
  1184.         fprintf(files[size], "Status: OR\n");
  1185.     }
  1186.     fputc('\n', files[size]);
  1187.     }
  1188.  
  1189.     /* if redirection, ed_fp = stdin, else rewind the file just made */
  1190.     if (isoff(glob_flags, REDIRECT))
  1191.     rewind(ed_fp);
  1192.     else
  1193.     ed_fp = stdin;
  1194.  
  1195.     /* read from stdin or the edfile till EOF and send it all to the mailer
  1196.      * and other open files/folders/programs. Check for "From " at the
  1197.      * beginnings of these lines to prevent creating new messages in folders.
  1198.      */
  1199.     while (fgets(buf, BUFSIZ, ed_fp))
  1200.     for (size = 0; size < next_file; size++) {
  1201.         if (!strncmp(buf, "From ", 5))
  1202.         fputc('>', files[size]);
  1203.         fputs(buf, files[size]);
  1204.     }
  1205.  
  1206.     /* loop thru the open files (except for the first: the mail delivery agent)
  1207.      * and append a blank line so that ucb-mail can read these folders.
  1208.      * Then close the files.  If the file was a popened program, the sigchld
  1209.      * that the program generates will close the file.
  1210.      */
  1211.     for (size = 1; size < next_file; size++)
  1212.     if (files[size]) {
  1213.         fputc('\n', files[size]);
  1214.         fclose(files[size]);
  1215.     }
  1216.  
  1217.     rm_edfile(0);
  1218.     if (debug < 3)
  1219.     (void) pclose(files[0]);
  1220.  
  1221.     if ((ison(flags, VERBOSE) || debug > 2) && isoff(glob_flags, REDIRECT))
  1222.     wprint("sent.\n");
  1223.     else
  1224.     exit(0); /* not a user exit -- a child exit */
  1225. }
  1226.  
  1227. /* ARGSUSED */
  1228. rm_edfile(sig)
  1229. {
  1230.     if (sig > 0 && !killme) {
  1231.     if (!istool)
  1232.         (void) signal(sig, rm_edfile);
  1233.     killme = 1;
  1234.     wprint("\n** interrupt -- one more to kill letter **\n");
  1235. #ifdef SUNTOOL
  1236.     if (istool) {
  1237.         type_cursor(PIX_SRC);
  1238.         return;
  1239.     }
  1240. #endif /* SUNTOOL */
  1241.     longjmp(cntrl_c_buf, 1);
  1242.     }
  1243.     killme = 0;
  1244.     /* if sig == -1, force a save into dead.letter.
  1245.      * else, check for nosave not being set and save anyway if it's not set
  1246.      * sig == 0 indicates normal exit (or ~x), so don't save a dead letter.
  1247.      */
  1248.     if (sig == -1 || sig != 0 && !do_set(set_options, "nosave"))
  1249.     dead_letter();
  1250.     if (isoff(glob_flags, REDIRECT))
  1251.     fclose(ed_fp);
  1252.     (void) unlink(edfile);
  1253.  
  1254.     if (sig == -1 && isoff(flags, VERBOSE) && debug < 3)
  1255.     exit(-1);
  1256.  
  1257.     turnoff(glob_flags, IS_GETTING);
  1258. #ifdef SUNTOOL
  1259.     if (sig && istool > 1) {
  1260.     wprint("*Letter aborted*");
  1261.     abort_mail(abort_item, 2);
  1262.     }
  1263. #endif /* SUNTOOL */
  1264.  
  1265.     if (sig == SIGHUP)
  1266.     cleanup(0);
  1267.     if (!istool) {
  1268.     (void) signal(SIGINT, oldint);
  1269.     (void) signal(SIGQUIT, oldquit);
  1270.     (void) signal(SIGTERM, oldterm);
  1271.     }
  1272.  
  1273.     if (sig == 0)
  1274.     return;
  1275.     if (istool || sig == -2) /* make sure sigchld is reset first */
  1276.     return;
  1277.  
  1278.     if (isoff(glob_flags, DO_SHELL)) {  /* If we're not in a shell, exit */
  1279.     puts("exiting");
  1280.     echo_on();
  1281.     exit(1);
  1282.     }
  1283.     longjmp(jmpbuf, 1);
  1284. }
  1285.  
  1286. /* save letter into dead letter */
  1287. dead_letter()
  1288. {
  1289.     char     *p, buf[BUFSIZ];
  1290.     long     t;
  1291.     FILE     *dead;
  1292.  
  1293.     if (ison(glob_flags, REDIRECT)) {
  1294.     print("input redirected -- can't save dead letter.\n");
  1295.     return;
  1296.     }
  1297.     /* If the file doesn't exist, get outta here. File may not exist if
  1298.      * user generated a ^C from a promptable header and catch sent us here.
  1299.      */
  1300.     if (Access(edfile, R_OK))
  1301.     return;
  1302.     /* User may have killed mush via a signal while he was in an editor.
  1303.      * ed_fp will be NULL in this case.  Since the file does exist (above),
  1304.      * open it so we can copy it to dead letter.
  1305.      */
  1306.     if (!ed_fp && !(ed_fp = fopen(edfile, "r"))) {
  1307.     error("can't save dead letter from %s", edfile);
  1308.     return;
  1309.     }
  1310.     /* don't save a dead letter if there's nothing to save. */
  1311.     if (fseek(ed_fp, 0L, 2) || ftell(ed_fp) == 0L)
  1312.     return;
  1313.     if (!(p = do_set(set_options, "dead")))
  1314.     p = "~/dead.letter";
  1315.     if (!(dead = open_file(p, FALSE)))
  1316.     return;
  1317.     (void) time (&t);
  1318.     fflush(ed_fp);
  1319.     rewind(ed_fp);
  1320.     fprintf(dead, "Unfinished letter from %s", ctime(&t));
  1321.     fprintf(dead, "To: %s\nSubject: %s\n", To, Subject);
  1322.     if (*Cc)
  1323.     fprintf(dead, "Cc: %s\n", Cc);
  1324.     while(fgets(buf, sizeof(buf), ed_fp))
  1325.     (void) fputs(buf, dead);
  1326.     (void) fputc('\n', dead);
  1327.     (void) fclose(dead);
  1328.     print("Saved unfinished letter in %s.\n", p);
  1329. }
  1330.  
  1331. /*
  1332.  * Your "signature" is of the type:
  1333.  *    file_or_path
  1334.  *    $varaible
  1335.  *    \ literal string preceded by a backslash.
  1336.  * The variable will be expanded into its string value.
  1337.  * To sign the letter, the list of addresses is passed to this routine
  1338.  * (separated by spaces and/or commas).  If "autosign2" is set,
  1339.  * then it must be of the form.
  1340.  * autosign2 = "user@foo user@bar address...: <signature>"
  1341.  * Spaces or tabs separate tokens.  If everyone on the list exists in
  1342.  * the autosign2 list, the alternate signature is used. In case of
  1343.  * syntax error, the alternate signature is used without checks (e.g. if
  1344.  * the : is missing).  The alternate signature == null is the same as
  1345.  * not signing the letter. An empty list forces signature2.
  1346.  *
  1347.  * If autosign2 is not set at all, then autosign is checked and used.
  1348.  * autosign = <signature>
  1349.  */
  1350. sign_letter(list)
  1351. register char *list; /* list of addresses -- no comment fields */
  1352. {
  1353.     char buf[BUFSIZ];
  1354.     register char *p, *p2, *signature, *addr;
  1355.     FILE     *pp2;
  1356.     int     lines = 0;
  1357.  
  1358.     buf[0] = 0;
  1359.     while (isspace(*list))
  1360.     list++;
  1361.     if (p = do_set(set_options, "autosign2")) {
  1362.     if (!(signature = index(p, ':')))
  1363.         wprint("\"autosign2\" incorrectly set (missing `:').\n");
  1364.     else {
  1365.         int ret_val = 0;
  1366.         *signature = 0;
  1367.         /* p now points to a list of addresses and p2 points to the
  1368.          * signature format to use. Check that each address contains
  1369.          * the stuff in alternate sign.
  1370.          */
  1371.         skipspaces(0);
  1372.         if (!*p)
  1373.         /* autosign2 = " : <signature>"  send to all recipients */
  1374.         ret_val = 1;
  1375.         else if (p = alias_to_address(p)) {
  1376.         rm_cmts_in_addr(p);
  1377.         for (addr = list;;) {
  1378.             char c;
  1379.             if (p2 = any(addr, ", ")) {
  1380.             c = *p2;
  1381.             *p2 = 0;
  1382.             }
  1383.             ret_val = chk_two_lists(addr, p, ", ");
  1384.             if (p2)
  1385.             for (*p2++ = c; isspace(*p2) || *p2 == ','; p2++)
  1386.                 ;
  1387.             if (!ret_val || !(addr = p2))
  1388.             break;
  1389.         }
  1390.         }
  1391.         *signature++ = ':'; /* must reset first! */
  1392.         if (ret_val) {
  1393.         while (isspace(*signature))
  1394.             signature++;
  1395.         if (!*strcpy(buf, signature))
  1396.             return;
  1397.         }
  1398.     }
  1399.     }
  1400.     if (!buf[0]) {
  1401.     if (!(p = do_set(set_options, "autosign")) || !*p) {
  1402.         char *home;
  1403.         if (!(home = do_set(set_options, "home")) || !*home)
  1404.         home = ALTERNATE_HOME;
  1405.         (void) sprintf(buf, "%s/%s", home, SIGNATURE);
  1406.     } else
  1407.         (void) strcpy(buf, p);
  1408.     wprint("Signing letter... ");
  1409.     } else
  1410.     wprint("Using alternate signature... ");
  1411.     fputc('\n', ed_fp), fflush(ed_fp);
  1412.     (void) fseek(ed_fp, 0L, 2); /* guarantee position at end of file */
  1413.     if (*buf == '$')
  1414.     if (!(p = do_set(set_options, buf)))
  1415.         wprint("(%s isn't set -- letter not signed)\n", buf);
  1416.     else
  1417.         fprintf(ed_fp, "%s\n", p), wprint("\n"), fflush(ed_fp);
  1418.     else if (*buf == '\\')
  1419.     fprintf(ed_fp, "%s\n", buf+1), wprint("\n"), fflush(ed_fp);
  1420.     else
  1421.     file_to_fp(buf, ed_fp, "r");
  1422.  
  1423.     /* if fortune is set, check to see if fortunates is set. If so,
  1424.      * check to see if all the recipient are on the fortunates list.
  1425.      */
  1426.     if (ison(flags, DO_FORTUNE)) {
  1427.     if (p = do_set(set_options, "fortunates")) {
  1428.         int ret_val;
  1429.         if (!(p = alias_to_address(p)))
  1430.         return; /* no reason to hang around */
  1431.         rm_cmts_in_addr(p);
  1432.         for (addr = list;;) {
  1433.         char c;
  1434.         if (p2 = any(addr, ", ")) {
  1435.             c = *p2;
  1436.             *p2 = 0;
  1437.         }
  1438.         if (!(ret_val = chk_two_lists(addr, p, ", ")))
  1439.             (void) strcpy(buf, addr);
  1440.         if (p2)
  1441.             for (*p2++ = c; isspace(*p2) || *p2 == ','; p2++)
  1442.             ;
  1443.         if (!ret_val || !(addr = p2))
  1444.             break;
  1445.         }
  1446.         if (!ret_val) {
  1447.         wprint("\"fortunates\" does not contain \"%s\".\n", buf);
  1448.         wprint("No fortune added.\n");
  1449.         return;
  1450.         }
  1451.     }
  1452.     wprint("You may be fortunate... ");
  1453.     if ((p = do_set(set_options, "fortune")) && *p == '/')
  1454.         (void) strcpy(buf, p);
  1455.     else
  1456.         (void) sprintf(buf, "%s %s", FORTUNE, (p && *p == '-')? p: "-s");
  1457.     if (!(pp2 = popen(buf, "r")))
  1458.         error(buf);
  1459.     else {
  1460.         turnon(glob_flags, IGN_SIGS);
  1461.         (void) fseek(ed_fp, 0L, 2); /* go to end of file */
  1462.         while (fgets(buf, sizeof(buf), pp2))
  1463.         fputs(buf, ed_fp), lines++;
  1464.         (void) pclose(pp2);
  1465.         turnoff(glob_flags, IGN_SIGS);
  1466.         fflush(ed_fp);
  1467.         wprint("added %d line%s\n", lines, lines == 1? "" : "s");
  1468.     }
  1469.     }
  1470. }
  1471.