home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / src / mailmsg2.c < prev    next >
C/C++ Source or Header  |  1996-08-30  |  34KB  |  1,144 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: mailmsg2.c,v 4.1.1.8 90/10/07 19:48:10 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1.1.8 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    mailmsg2.c,v $
  17.  * Revision 4.1.1.8  90/10/07  19:48:10  syd
  18.  * fix the bounce problem reported earlier when using MMDF submit as the MTA.
  19.  * From: Jim Clausing <jac%brahms.tinton.ccur.com@RELAY.CS.NET>
  20.  *
  21.  * Revision 4.1.1.7  90/08/15  22:02:36  syd
  22.  * deal with several of the problems that have come up trying to use the MMDF
  23.  * submit program directly rather than going through the sendmail stub
  24.  * included with MMDF.  This should take care of the problem of not being
  25.  * able to send mail to usernames beginning with "i" and with the
  26.  * 'No valid author specified' problem.
  27.  * From: jac%brahms.tinton.ccur.com@RELAY.CS.NET
  28.  *
  29.  * Revision 4.1.1.6  90/07/12  23:19:20  syd
  30.  * Make domain name checking case independent
  31.  * From: Syd, reported by Steven Baur
  32.  *
  33.  * Revision 4.1.1.5  90/07/12  22:52:42  syd
  34.  * When Elm is compiled with the NO_XHEADER symbol defined, it failed
  35.  * to put a blank line between the message header and message body.
  36.  * From: mca@medicus.medicus.com (Mark Adams)
  37.  *
  38.  * Revision 4.1.1.4  90/06/26  16:18:24  syd
  39.  * Make it encode lines that are [...] if not one of the reserved lines.
  40.  * It was messing up decoding
  41.  * From: Syd via report from Lenny Tropiano
  42.  *
  43.  * Revision 4.1.1.3  90/06/21  21:07:48  syd
  44.  * Fix XHEAD define
  45.  * From: Syd
  46.  *
  47.  * Revision 4.1.1.2  90/06/09  23:20:24  syd
  48.  * fix typo
  49.  *
  50.  * Revision 4.1.1.1  90/06/09  22:28:39  syd
  51.  * Allow use of submit with mmdf instead of sendmail stub
  52.  * From: martin <martin@hppcmart.grenoble.hp.com>
  53.  *
  54.  * Revision 4.1  90/04/28  22:43:28  syd
  55.  * checkin of Elm 2.3 as of Release PL0
  56.  *
  57.  *
  58.  ******************************************************************************/
  59.  
  60. /** Interface to allow mail to be sent to users.  Part of ELM  **/
  61.  
  62. #include "headers.h"
  63. #include <errno.h>
  64. #include <ctype.h>
  65.  
  66. #ifdef BSD
  67. #undef tolower
  68. #undef toupper
  69. #endif
  70.  
  71. #ifndef OS2
  72. extern int errno;
  73. #endif
  74. extern char version_buff[];
  75.  
  76. char *error_name(), *error_description(), *strip_parens();
  77. char *strcat(), *strcpy(), *index();
  78. char *format_long(), *strip_commas(), *tail_of_string();
  79.  
  80. unsigned long sleep();
  81.  
  82. #ifdef SITE_HIDING
  83.  char *get_ctime_date();
  84. #endif
  85. FILE *write_header_info();
  86.  
  87. /* these are all defined in the mailmsg1.c file! */
  88.  
  89. extern char subject[SLEN], in_reply_to[SLEN], expires[SLEN],
  90.             action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING],
  91.         cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING],
  92.         expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
  93.         bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
  94.  
  95.  
  96. int  gotten_key;
  97. char *bounce_off_remote();
  98.  
  99. mail(copy_msg, edit_message, form)
  100. int  copy_msg, edit_message, form;
  101. {
  102.     /** Given the addresses and various other miscellany (specifically,
  103.         'copy-msg' indicates whether a copy of the current message should
  104.         be included, 'edit_message' indicates whether the message should
  105.         be edited) this routine will invoke an editor for the user and
  106.         then actually mail off the message. 'form' can be YES, NO, or
  107.         MAYBE.  YES=add "Content-Type: mailform" header, MAYBE=add the
  108.         M)ake form option to last question, and NO=don't worry about it!
  109.         Also, if 'copy_msg' = FORM, then grab the form temp file and use
  110.         that...
  111.         Return TRUE if the main part of the screen has been changed
  112.         (useful for knowing whether a redraw is needed.
  113.     **/
  114.  
  115.     FILE *reply, *real_reply; /* second is post-input buffer */
  116.     char *whole_msg_file = NULL, *tempnam();
  117.     char filename[SLEN], fname[SLEN], copy_file[SLEN],
  118.              very_long_buffer[VERY_LONG_STRING], mailerflags[NLEN];
  119.     int ch, sys_status;
  120.     register int retransmit = FALSE;
  121.     int      already_has_text = FALSE;        /* we need an ADDRESS */
  122.     int     signature_done = FALSE;
  123.     int     need_redraw = 0;
  124.     int      resent = forwarding && !edit_message;
  125.  
  126.     static int cancelled_msg = 0;
  127.  
  128.     dprint(4, (debugfile, "\nMailing to \"%s\" (with%s editing)\n",
  129.           expanded_to, edit_message? "" : "out"));
  130.  
  131.     gotten_key = 0;        /* ignore previously gotten encryption key */
  132.  
  133.     /** first generate the temporary filename **/
  134.  
  135.     sprintf(filename,"%s%d%s", temp_dir, getpid(), temp_file);
  136.  
  137.     /** if possible, let's try to recall the last message? **/
  138.  
  139.     if (! batch_only && copy_msg != FORM && user_level != 0)
  140.       retransmit = recall_last_msg(filename, copy_msg, &cancelled_msg,
  141.                &already_has_text);
  142.  
  143.     /** if we're not retransmitting, create the file.. **/
  144.  
  145.     if (! retransmit)
  146.       if ((reply = fopen(filename,"w")) == NULL) {
  147.         dprint(1, (debugfile,
  148.                "Attempt to write to temp file %s failed with error %s (mail)\n",
  149.          filename, error_name(errno)));
  150.         if(batch_only)
  151.           printf("Could not create file %s (%s).\n",filename,
  152.          error_name(errno));
  153.         else
  154.           error2("Could not create file %s (%s).",filename,
  155.          error_name(errno));
  156.         return(need_redraw);
  157.       }
  158.  
  159.     chown (filename, userid, groupid);
  160.  
  161.     /* copy the message from standard input */
  162.     if (batch_only) {
  163.       while (fgets(very_long_buffer, VERY_LONG_STRING, stdin) != NULL)
  164.         fprintf(reply, "%s", very_long_buffer);
  165.     }
  166.  
  167.     if (copy_msg == FORM) {
  168.       sprintf(fname, "%s%d%s", temp_dir, getpid(), temp_form_file);
  169.       fclose(reply);    /* we can't retransmit a form! */
  170.       if (access(fname,ACCESS_EXISTS) != 0) {
  171.         if(batch_only)
  172.           printf("Couldn't find forms file!\n");
  173.         else
  174.           error("Couldn't find forms file!");
  175.         return(need_redraw);
  176.       }
  177.       dprint(4, (debugfile, "-- renaming existing file %s to file %s --\n",
  178.           fname, filename));
  179.       rename(fname, filename);
  180.     }
  181.     else if (copy_msg && ! retransmit) {  /* if retransmit we have it! */
  182.       if (forwarding) {
  183.         if (edit_message)
  184.           fputs("Forwarded message:\n", reply);
  185.       }
  186.       else if (attribution[0]) {
  187.         fprintf(reply, attribution, headers[current-1]->from);
  188.         fputc('\n', reply);
  189.       }
  190.       if (edit_message) {
  191.           copy_message(prefixchars, reply, noheader,FALSE,FALSE,TRUE,FALSE,TRUE);
  192.         already_has_text = TRUE;    /* we just added it, right? */
  193.       }
  194.       else
  195.           copy_message("", reply, noheader, FALSE, FALSE, TRUE, FALSE, FALSE);
  196.     }
  197.  
  198.         /* append signature now if we are going to use an external editor */
  199.     /* Don't worry about the remote/local determination too much */
  200.  
  201.         if (already_has_text ||
  202.            (strcmp(editor,"builtin") != 0 && strcmp(editor,"none") != 0)) {
  203.          signature_done = TRUE;
  204.              if (!(forwarding && !edit_message) &&
  205.                  !retransmit && copy_msg != FORM)
  206.            already_has_text |= append_sig(reply);
  207.     }
  208.  
  209.     if (! retransmit && copy_msg != FORM)
  210.       if (reply != NULL)
  211.         (void) fclose(reply);    /* on replies, it won't be open! */
  212.  
  213.     /** Edit the message **/
  214.  
  215.     if (edit_message)
  216.       create_readmsg_file();    /* for "readmsg" routine */
  217.  
  218.     ch = edit_message? 'e' : ' ';    /* drop through if needed... */
  219.  
  220.     /* calculate default save_file name */
  221.     if(auto_cc) {
  222.       if(save_by_name) {
  223.         if(force_name) {
  224.           strcpy(copy_file, "=");    /* signals save by 'to' logname */
  225.         } else {
  226.           strcpy(copy_file, "=?");    /* conditional save by 'to' logname */
  227.         }
  228.       } else {
  229.         strcpy(copy_file, "<");    /* signals save to sentmail */
  230.       }
  231.     } else *copy_file = '\0';    /* signals to not save a copy */
  232.  
  233.  
  234.     if (! batch_only) {
  235.       do {
  236.         switch (ch) {
  237.           case 'e': need_redraw = 1;
  238.             if (edit_the_message(filename, already_has_text)) {
  239.               cancelled_msg = TRUE;
  240.               return(need_redraw);
  241.             }
  242.             break;
  243.  
  244.           case 'c': if (name_copy_file(copy_file))
  245.               need_redraw = 1;
  246.             break;
  247.  
  248.           case 'h': edit_headers();
  249.             need_redraw = 1;
  250.             break;
  251.  
  252. #ifdef ALLOW_SUBSHELL
  253.           case '!': if (subshell()) {
  254.               ClearScreen();
  255.               need_redraw = 1;
  256.             }
  257.             break;
  258. #endif
  259.  
  260.           default : /* do nothing */ ;
  261.         }
  262.  
  263.         /** ask that silly question again... **/
  264.  
  265.         if ((ch = verify_transmission(filename, &form)) == 'f') {
  266.           cancelled_msg = TRUE;
  267.           return(need_redraw);
  268.         }
  269.         
  270.         if (ch == 's' && 
  271.         perhaps_pgp_encode(filename) == -1)
  272.           ch = ' ';
  273.  
  274.       } while (ch != 's');
  275.  
  276.       if (form == YES)
  277.         if (format_form(filename) < 1) {
  278.           cancelled_msg = TRUE;
  279.           return(need_redraw);
  280.         }
  281.  
  282.       if ((reply = fopen(filename,"r")) == NULL) {
  283.           dprint(1, (debugfile,
  284.         "Attempt to open file %s for reading failed with error %s (mail)\n",
  285.                 filename, error_name(errno)));
  286.           error1("Could not open reply file (%s).", error_name(errno));
  287.           return(need_redraw);
  288.       }
  289.     }
  290.     else if ((reply = fopen(filename,"r")) == NULL) {
  291.       dprint(1, (debugfile,
  292.         "Attempt to open file %s for reading failed with error %s (mail)\n",
  293.              filename, error_name(errno)));
  294.       printf("Could not open reply file (%s).\n", error_name(errno));
  295.       return(need_redraw);
  296.     }
  297.  
  298.     cancelled_msg = FALSE;    /* it ain't cancelled, is it? */
  299.  
  300.     /** ask about bounceback if the user wants us to.... **/
  301.  
  302.     if (uucp_hops(to) > bounceback && bounceback > 0 && copy_msg != FORM)
  303.       if (verify_bounceback() == TRUE) {
  304.         if (strlen(cc) > 0) strcat(expanded_cc, ", ");
  305.         strcat(expanded_cc, bounce_off_remote(to));
  306.       }
  307.  
  308.     /** grab a copy if the user so desires... **/
  309.  
  310.     if (*copy_file && !no_save) /* i.e. if copy_file contains a name */
  311.       save_copy(expanded_to, expanded_cc, expanded_bcc,
  312.            filename, copy_file, form);
  313.  
  314.     /** write all header information into whole_msg_file **/
  315.  
  316.     if((whole_msg_file=tempnam(temp_dir, "snd")) == NULL) {
  317.       dprint(1, (debugfile, "couldn't make temp file nam! (mail)\n"));
  318.       if(batch_only)
  319.         printf("Sorry - couldn't make temp file name!\n");
  320.       else if(mail_only)
  321.         error("Sorry - couldn't make temp file name.");
  322.       else
  323.         set_error("Sorry - couldn't make temp file name.");
  324.       return(need_redraw);
  325.     }
  326.  
  327.     /** try to write headers to new temp file **/
  328.  
  329.     dprint(6, (debugfile, "Composition file='%s' and mail buffer='%s'\n",
  330.             filename, whole_msg_file));
  331.  
  332.     dprint(2,(debugfile,"--\nTo: %s\nCc: %s\nBcc: %s\nSubject: %s\n---\n",
  333.           expanded_to, expanded_cc, expanded_bcc, subject));
  334.  
  335.     if ((real_reply=
  336.        write_header_info(whole_msg_file, expanded_to, expanded_cc, 
  337.              expanded_bcc, form == YES, FALSE, resent)) == NULL) {
  338.  
  339.       /** IT FAILED!!  MEIN GOTT!  Use a dumb mailer instead! **/
  340.  
  341.       dprint(3, (debugfile, "** write_header failed: %s\n",
  342.          error_name(errno)));
  343.  
  344.       if (cc[0] != '\0') {          /* copies! */
  345.         strcat(expanded_to, " ");
  346.         strcat(expanded_to, expanded_cc);
  347.       }
  348.  
  349.       quote_args(very_long_buffer, strip_parens(strip_commas(expanded_to)));
  350.       strcpy(expanded_to, very_long_buffer);
  351.  
  352.       sprintf(very_long_buffer, "%s -f %s -s \"%s\" %s",
  353.           mailx, filename, subject, expanded_to);
  354.  
  355.       if(batch_only)
  356.         printf("Message sent using dumb mailer %s.\n", mailx);
  357.       else
  358.         error1("Message sent using dumb mailer %s.", mailx);
  359.       sleep(2);    /* ensure time to see this prompt! */
  360.  
  361.     }
  362.     else {
  363.  
  364.       copy_message_across(reply, real_reply, FALSE);
  365.  
  366.           /* Append signature if not done earlier */
  367.  
  368.           if (!signature_done && !retransmit && copy_msg != FORM)
  369.                append_sig(real_reply);
  370.  
  371.       fclose(real_reply);
  372.  
  373.       if (cc[0] != '\0') {                 /* copies! */
  374.         strcat(expanded_to, " ");
  375.         strcat(expanded_to, expanded_cc);
  376.       }
  377.  
  378.       if (bcc[0] != '\0') {
  379.         strcat(expanded_to, " ");
  380.         strcat(expanded_to, expanded_bcc);
  381.       }
  382.  
  383.       remove_hostbang(expanded_to);
  384.  
  385.       if (strcmp(sendmail, mailer) == 0)
  386.       {
  387. #if 1
  388.         sprintf(very_long_buffer,"sndmail %s -af %s -f %s@%s -t %s >nul 2>&1",
  389.             background ? "-bg" : "",
  390.             whole_msg_file, username, hostfromname, 
  391.             strip_parens(strip_commas(expanded_bcc)));
  392. #else
  393.         sprintf(very_long_buffer,"sndmail %s -af %s -f %s@%s %s >nul 2>&1",
  394.             background ? "-bg" : "",
  395.             whole_msg_file, username, hostfromname, 
  396.             strip_parens(strip_commas(expanded_to)));
  397. #endif
  398.       }
  399.       else
  400.       {
  401.         sprintf(very_long_buffer,"%s -f %s %s 2>nul",
  402.             mailer, whole_msg_file, submitflags);
  403.       }
  404.     }
  405.  
  406.     fclose(reply);
  407.  
  408.     if(batch_only)
  409.       printf("Sending mail...\r\n");
  410.     else {
  411.       PutLine0(LINES,0,"Sending mail...");
  412.       CleartoEOLN();
  413.     }
  414.  
  415.     /* Take note of mailer return value */
  416.  
  417.     if ( sys_status = system_call(very_long_buffer, SH, FALSE, FALSE) ) {
  418.         /* problem case: */
  419.         if (mail_only || batch_only)
  420.            printf("\r\nmailer returned error status %d\r\n", sys_status);
  421.         else {
  422.            sprintf(very_long_buffer, "mailer returned error status %d", sys_status);
  423.            set_error(very_long_buffer);
  424.         }
  425.     } else {
  426.         /* Success case: */
  427.         if(batch_only)
  428.           printf("Mail sent!\r\n");
  429.         else if(mail_only)
  430.           error("Mail sent!");
  431.         else
  432.           set_error("Mail sent!");
  433.     }
  434.  
  435.     /* Unlink temp file now.
  436.      * This is a precaution in case the message was encrypted.
  437.      * I.e. even though this file is readable by the owner only,
  438.      * encryption is supposed to hide things even from someone
  439.      * with root privelges. The best we can do is not let this
  440.      * file just hang after we're finished with it.
  441.      */
  442.     if (!background) /* but only if not using sendmail in background mode */
  443.       (void)unlink(whole_msg_file);
  444.     (void)unlink(filename);
  445.         free(whole_msg_file);
  446.     return(need_redraw);
  447. }
  448.  
  449. /*
  450.  * remove_hostbang - Given an expanded list of addresses, remove all
  451.  * occurrences of "thishost!" at the beginning of addresses.
  452.  * This hack is useful in itself, but it is required now because of the
  453.  * kludge disallowing alias expansion on return addresses.
  454.  */
  455.  
  456. remove_hostbang(addrs)
  457. char *addrs;
  458. {
  459.     int i, j, hlen, flen;
  460.  
  461.     if ((hlen = strlen(hostname)) < 1)
  462.       return;
  463.  
  464.     flen = strlen(hostfullname);
  465.     i = j = 0;
  466.  
  467.     while (addrs[i]) {
  468.       if (i == 0 || isspace(addrs[i - 1])) {
  469.         if (strncmp(&addrs[i], hostname, hlen) == 0 &&
  470.           addrs[i + hlen] == '!') {
  471.             i += hlen + 1;
  472.             continue;
  473.         }
  474.         if (strncmp(&addrs[i], hostfullname, flen) == 0 &&
  475.           addrs[i + flen] == '!') {
  476.             i += flen + 1;
  477.             continue;
  478.         }
  479.       }
  480.       addrs[j++] = addrs[i++];
  481.     }
  482.     addrs[j] = 0;
  483. }
  484.  
  485. mail_form(address, subj)
  486. char *address, *subj;
  487. {
  488.     /** copy the appropriate variables to the shared space... */
  489.  
  490.     strcpy(subject, subj);
  491.     strcpy(to, address);
  492.     strcpy(expanded_to, address);
  493.  
  494.     return(mail(FORM, NO, NO));
  495. }
  496.  
  497. int
  498. recall_last_msg(filename, copy_msg, cancelled_msg, already_has_text)
  499. char *filename;
  500. int  copy_msg, *cancelled_msg, *already_has_text;
  501. {
  502.     char ch;
  503.  
  504.     /** If filename exists and we've recently cancelled a message,
  505.         the ask if the user wants to use that message instead!  This
  506.         routine returns TRUE if the user wants to retransmit the last
  507.         message, FALSE otherwise...
  508.     **/
  509.  
  510.     register int retransmit = FALSE;
  511.  
  512.     if (access(filename, EDIT_ACCESS) == 0 && *cancelled_msg) {
  513.       Raw(ON);
  514.       CleartoEOLN();
  515.       if (copy_msg)
  516.         PutLine1(LINES-1,0,"Recall last kept message instead? (y/n) y%c",
  517.              BACKSPACE);
  518.       else
  519.         PutLine1(LINES-1,0,"Recall last kept message? (y/n) y%c",
  520.              BACKSPACE);
  521.       fflush(stdout);
  522.       ch = ReadCh();
  523.       if (tolower(ch) != 'n') {
  524.         Write_to_screen("Yes.",0);
  525.             retransmit++;
  526.         *already_has_text = TRUE;
  527.       }
  528.       else
  529.         Write_to_screen("No.",0);
  530.  
  531.       fflush(stdout);
  532.  
  533.       *cancelled_msg = 0;
  534.     }
  535.  
  536.     return(retransmit);
  537. }
  538.  
  539. int
  540. verify_transmission(filename, form_letter)
  541. char *filename;
  542. int  *form_letter;
  543. {
  544.     /** Ensure the user wants to send this.  This routine returns
  545.         the character entered.  Modified compliments of Steve Wolf
  546.         to add the'dead.letter' feature.
  547.         Also added form letter support...
  548.     **/
  549.  
  550.     FILE *deadfd, *messagefd;
  551.     char ch, buffer[SLEN], fname[SLEN];
  552.     int x_coord, y_coord;
  553.  
  554.     while(1) {
  555.       /* clear bottom part of screen */
  556.       MoveCursor(LINES-2,0);
  557.       CleartoEOS();
  558.  
  559.       /* display prompt and menu according to
  560.        * user level and what's available on the menu */
  561.       if (user_level == 0) {
  562.         PutLine0(LINES-2,0,
  563.       "Please choose one of the following options by parenthesized letter: s");
  564.         GetXYLocation(&x_coord, &y_coord);
  565.         y_coord--;    /* backspace over default answer */
  566.         Centerline(LINES-1,
  567.           "e)dit message, edit h)eaders, s)end it, or f)orget it.");
  568.       } else {
  569.         PutLine0(LINES-2, 0, "And now: s");
  570.         GetXYLocation(&x_coord, &y_coord);
  571.         y_coord--;    /* backspace over default answer */
  572.         if (*form_letter == PREFORMATTED)  {
  573.            strcpy(buffer, "Choose ");
  574.         } else if (*form_letter == YES) {
  575.            strcpy(buffer, "Choose e)dit form, ");
  576.         } else if (*form_letter == MAYBE)  {
  577.            strcpy(buffer, "Choose e)dit msg, m)ake form, ");
  578.         } else {
  579.              strcpy(buffer, "Choose e)dit msg, ");
  580.         }
  581. #ifdef ALLOW_SUBSHELL
  582.         strcat(buffer, "!)shell, ");
  583. #endif
  584.           strcat(buffer, "h)drs, c)opy file, s)end, f)orget");
  585.         Centerline(LINES-1, buffer);
  586.       }
  587.  
  588.       /* wait for answer */
  589.       fflush(stdin);
  590.       fflush(stdout);
  591.       Raw(ON);    /* double check... testing only... */
  592.       MoveCursor(x_coord, y_coord);
  593.       ch = ReadCh();
  594.       ch = tolower(ch);
  595.  
  596.       /* process answer */
  597.       switch (ch) {
  598.          case 'f': Write_to_screen("Forget",0);
  599.                if (mail_only) {
  600.              /** try to save it as a dead letter file **/
  601.              save_file_stats(fname);
  602.              sprintf(fname, "%s/%s", home, dead_letter);
  603.              if ((deadfd = fopen(fname,"a")) == NULL) {
  604.                dprint(1, (debugfile,
  605.            "\nAttempt to append to deadletter file '%s' failed: %s\n\r",
  606.                    fname, error_name(errno)));
  607.                error("Message not saved, Sorry.");
  608.              }
  609.              else if ((messagefd = fopen(filename, "r")) == NULL) {
  610.                dprint(1, (debugfile,
  611.                  "\nAttempt to read reply file '%s' failed: %s\n\r",
  612.                    filename, error_name(errno)));
  613.                error("Message not saved, Sorry.");
  614.              } else {
  615.                /* if we get here we're okay for everything */
  616.                while (fgets(buffer, SLEN, messagefd) != NULL)
  617.                  fputs(buffer, deadfd);
  618.  
  619.                fclose(messagefd);
  620.                fclose(deadfd);
  621.                restore_file_stats(fname);
  622.  
  623.                error1("Message saved in file \"$HOME/%s\".",
  624.                  dead_letter);
  625.  
  626.             }
  627.                } else if (user_level != 0)
  628.             set_error("Message kept. Can be restored at next f)orward, m)ail or r)eply.");
  629.                break;
  630.  
  631.          case '\n' :
  632.          case '\r' :
  633.          case 's'  : Write_to_screen("Send",0);
  634.              ch = 's';        /* make sure! */
  635.              break;
  636.  
  637.          case 'm'  : if (*form_letter == MAYBE) {
  638.                *form_letter = YES;
  639.                    switch (check_form_file(filename)) {
  640.                  case -1 : return('f');
  641.                  case 0  : *form_letter = MAYBE;  /* check later!*/
  642.                        error("No fields in form!");
  643.                        return('e');
  644.                  default : continue;
  645.                        }
  646.              }
  647.              else {
  648.                         Write_to_screen("%c??", 1, 07);    /* BEEP */
  649.                 sleep(1);
  650.                     continue;
  651.                      }
  652.          case 'e'  :  if (*form_letter != PREFORMATTED) {
  653.                 Write_to_screen("Edit",0);
  654.                      if (*form_letter == YES)
  655.                   *form_letter = MAYBE;
  656.                       }
  657.               else {
  658.                         Write_to_screen("%c??", 1, 07);    /* BEEP */
  659.                 sleep(1);
  660.                     continue;
  661.                      }
  662.              break;
  663.  
  664.          case 'h'  : Write_to_screen("Headers",0);
  665.              break;
  666.  
  667.          case 'c'  : Write_to_screen("Copy file",0);
  668.              break;
  669.  
  670.          case '!'  : break;
  671.  
  672.          default   : Write_to_screen("%c??", 1, 07);    /* BEEP */
  673.              sleep(1);
  674.                  continue;
  675.        }
  676.  
  677.        return(ch);
  678.     }
  679. }
  680.  
  681. FILE *
  682. write_header_info(filename, long_to, long_cc, long_bcc, form, copy, resend)
  683. char *filename, *long_to, *long_cc, *long_bcc;
  684. int   form, copy, resend;
  685. {
  686.     /** Try to open filedesc as the specified filename.  If we can,
  687.         then write all the headers into the file.  The routine returns
  688.         'filedesc' if it succeeded, NULL otherwise.  Added the ability
  689.         to have backquoted stuff in the users .elmheaders file!
  690.         If copy is TRUE, then treat this as the saved copy of outbound
  691.         mail.
  692.     **/
  693.  
  694.     char opentype[2];
  695.     long time(), thetime;
  696.     char *ctime();
  697.     static FILE *filedesc;        /* our friendly file descriptor  */
  698.     char *resent = resend ? "Resent-" : "";  /* forwarding ? */
  699.  
  700. #ifdef SITE_HIDING
  701.     char  buffer[SLEN];
  702.     int   is_hidden_user;        /* someone we should know about?  */
  703. #endif
  704. #ifdef MMDF
  705.     int   is_submit_mailer;        /* using submit means change From: */
  706. #endif /* MMDF */
  707.  
  708.     char  *get_arpa_date();
  709.  
  710.     if(copy)
  711.         strcpy(opentype, "a");
  712.     else
  713.         strcpy(opentype, "w");
  714.  
  715.     save_file_stats(filename);
  716.     if ((filedesc = fopen(filename, opentype)) == NULL) {
  717.       dprint(1, (debugfile,
  718.         "Attempt to open file %s for writing failed! (write_header_info)\n",
  719.          filename));
  720.       dprint(1, (debugfile, "** %s - %s **\n\n", error_name(errno),
  721.          error_description(errno)));
  722.       error2("Error %s encountered trying to write to %s.",
  723.         error_name(errno), filename);
  724.       sleep(2);
  725.       return(NULL);        /* couldn't open it!! */
  726.     }
  727.  
  728.     restore_file_stats(filename);
  729.  
  730.     if(copy) {    /* Add top line that mailer would add */
  731. #ifdef MMDF
  732.       fprintf(filedesc, MSG_SEPERATOR);
  733. #endif /* MMDF */
  734.       thetime = time((long *) 0);
  735.       fprintf(filedesc,"From %s %s", username, ctime(&thetime));
  736.     }
  737.  
  738. #ifdef SITE_HIDING
  739.     if ( !copy && (is_hidden_user = is_a_hidden_user(username))) {
  740.       /** this is the interesting part of this trick... **/
  741.       sprintf(buffer, "From %s!%s %s\n",  HIDDEN_SITE_NAME,
  742.           username, get_ctime_date());
  743.       fprintf(filedesc, "%s", buffer);
  744.       dprint(1,(debugfile, "\nadded: %s", buffer));
  745.       /** so is this perverted or what? **/
  746.     }
  747. #endif
  748.  
  749.  
  750.     /** Subject moved to top of headers for mail because the
  751.         pure System V.3 mailer, in its infinite wisdom, now
  752.         assumes that anything the user sends is part of the
  753.         message body unless either:
  754.         1. the "-s" flag is used (although it doesn't seem
  755.            to be supported on all implementations??)
  756.         2. the first line is "Subject:".  If so, then it'll
  757.            read until a blank line and assume all are meant
  758.            to be headers.
  759.         So the gory solution here is to move the Subject: line
  760.         up to the top.  I assume it won't break anyone elses program
  761.         or anything anyway (besides, RFC-822 specifies that the *order*
  762.         of headers is irrelevant).  Gahhhhh....
  763.     **/
  764.  
  765.     fprintf(filedesc,"%sDate: %s\n", resent, get_arpa_date());
  766.  
  767. #ifndef DONT_ADD_FROM
  768.     fputs(resent, filedesc);
  769. #ifdef MMDF
  770.     is_submit_mailer = (strcmp(submitmail,mailer) == 0);
  771. #endif /* MMDF */
  772. # ifdef SITE_HIDING
  773. #    ifdef MMDF
  774.     if (is_submit_mailer)
  775.       fprintf(filedesc,"From: %s <%s>\n", full_username, username);
  776.     else
  777. #    endif /* MMDF */
  778.     if (is_hidden_user)
  779.       fprintf(filedesc,"From: %s <%s!%s!%s>\n", full_username,
  780.           hostname, HIDDEN_SITE_NAME, username);
  781.     else
  782.       fprintf(filedesc,"From: %s <%s!%s>\n", full_username,
  783.           hostname, username);
  784. # else
  785. #  ifdef  INTERNET
  786. #   ifdef  USE_DOMAIN
  787. #    ifdef _MMDF
  788.     if (is_submit_mailer)
  789.       fprintf(filedesc,"From: %s <%s>\n", full_username, username);
  790.     else
  791. #    endif /* MMDF */
  792.       fprintf(filedesc,"From: %s <%s@%s>\n", full_username,
  793.         username, hostfromname);
  794. #   else
  795. #    ifdef _MMDF
  796.     if (is_submit_mailer)
  797.       fprintf(filedesc,"From: %s <%s>\n", full_username, username);
  798.     else
  799. #    endif /* MMDF */
  800.     fprintf(filedesc,"From: %s <%s@%s>\n", full_username,
  801.         username, hostname);
  802. #   endif
  803. #  else
  804. #    ifdef MMDF
  805.     if (is_submit_mailer)
  806.       fprintf(filedesc,"From: %s <%s>\n", full_username, username);
  807.     else
  808. #    endif /* MMDF */
  809.     fprintf(filedesc,"From: %s <%s!%s>\n", full_username,
  810.         hostname, username);
  811. #  endif
  812. # endif
  813. #endif
  814.  
  815.     fprintf(filedesc, "%sSubject: %s\n", resent, subject);
  816.  
  817.     fprintf(filedesc, "%sTo: %s\n", resent, format_long(long_to, strlen("To:")));
  818.  
  819.     if (cc[0] != '\0')
  820.         fprintf(filedesc, "%sCc: %s\n", resent, format_long(long_cc, strlen("Cc: ")));
  821.  
  822.     if ((copy || stricmp(sendmail, mailer) != 0) &&
  823.         (bcc[0] != '\0'))
  824.         fprintf(filedesc, "%sBcc: %s\n", resent, format_long(long_bcc, strlen("Bcc: ")));
  825.  
  826.     if (strlen(action) > 0)
  827.         fprintf(filedesc, "Action: %s\n", action);
  828.  
  829.     if (strlen(priority) > 0)
  830.         fprintf(filedesc, "Priority: %s\n", priority);
  831.  
  832.     if (strlen(expires) > 0)
  833.         fprintf(filedesc, "Expires: %s\n", expires);
  834.  
  835.     if (strlen(reply_to) > 0)
  836.         fprintf(filedesc, "%sReply-To: %s\n", resent, reply_to);
  837.  
  838.     if (strlen(in_reply_to) > 0)
  839.         fprintf(filedesc, "In-Reply-To: %s\n", in_reply_to);
  840.  
  841.     if (strlen(user_defined_header) > 0)
  842.         fprintf(filedesc, "%s\n", user_defined_header);
  843.  
  844.     add_mailheaders(filedesc);
  845.  
  846.     if (form)
  847.       fprintf(filedesc, "Content-Type: mailform\n");
  848.  
  849. #ifndef NO_XHEADER
  850.     fprintf(filedesc, "X-Mailer: ELM [version %s] for OS/2\n", version_buff);
  851. #endif /* !NO_XHEADER */
  852.  
  853.         if (!resend)
  854.        putc('\n', filedesc);
  855.  
  856.     return((FILE *) filedesc);
  857. }
  858.  
  859. copy_message_across(source, dest, copy)
  860. FILE *source, *dest;
  861. int copy;
  862. {
  863.     /** Copy the message in the file pointed to by source to the
  864.         file pointed to by dest.
  865.         If copy is TRUE, treat as a saved copy of outbound mail. **/
  866.  
  867.     int  crypted = FALSE;            /* are we encrypting?  */
  868.     int  encoded_lines = 0;            /* # lines encoded     */
  869.     char buffer[SLEN];            /* file reading buffer */
  870.  
  871.     while (fgets(buffer, SLEN, source) != NULL) {
  872.       if (buffer[0] == '[') {
  873.         if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0)
  874.           crypted = TRUE;
  875.         else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0)
  876.           crypted = FALSE;
  877.         else if ((strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0)
  878.               || (strncmp(buffer, DONT_SAVE2, strlen(DONT_SAVE2)) == 0)) {
  879.           if(copy) break;  /* saved copy doesn't want anything after this */
  880.           else continue;   /* next line? */
  881.         }
  882.         else if (crypted) {
  883.           if (! gotten_key++)
  884.             getkey(ON);
  885.           else if (! encoded_lines)
  886.             get_key_no_prompt();        /* reinitialize.. */
  887.           encode(buffer);
  888.           encoded_lines++;
  889.         }
  890.       }
  891.       else if (crypted) {
  892.         if (batch_only) {
  893.           printf(
  894.         "Sorry. Cannot send encrypted mail in \"batch mode\".\n\r");
  895.           leave();
  896.         } else if (! gotten_key++)
  897.           getkey(ON);
  898.         else if (! encoded_lines)
  899.           get_key_no_prompt();        /* reinitialize.. */
  900.         encode(buffer);
  901.         encoded_lines++;
  902.       }
  903.  
  904.       if (copy && (strncmp(buffer, "From ", 5) == 0))
  905.         /* Add in the > to a From on our copy */
  906.         fprintf(dest, ">%s", buffer);
  907.  
  908.       else if (!copy && strcmp(buffer, ".\n") == 0)
  909.         /* Because some mail transport agents take a lone period to
  910.          * mean EOF, we add a blank space on outbound message.
  911.          */
  912.         fputs(". \n", dest);
  913.         else
  914.           if (fputs(buffer, dest) == EOF) {
  915.         Write_to_screen("\n\rWrite failed in copy_message_across\n\r", 0);
  916.         emergency_exit();
  917.         }
  918.     }
  919. #ifdef _MMDF
  920.     if (copy) fputs(MSG_SEPERATOR, dest);
  921. #else
  922.     if (copy) fputs("\n", dest);    /* ensure a blank line at the end */
  923. #endif /* MMDF */
  924. }
  925.  
  926. int
  927. verify_bounceback()
  928. {
  929.     char    ch;
  930.  
  931.     /** Ensure the user wants to have a bounceback copy too.  (This is
  932.         only called on messages that are greater than the specified
  933.         threshold hops and NEVER for non-uucp addresses.... Returns
  934.         TRUE iff the user wants to bounce a copy back....
  935.      **/
  936.  
  937.     MoveCursor(LINES,0);
  938.     CleartoEOLN();
  939.     PutLine1(LINES,0,
  940.           "\"Bounce\" a copy off the remote machine? (y/n) y%c",
  941.           BACKSPACE);
  942.     fflush(stdin);    /* wait for answer! */
  943.     fflush(stdout);
  944.     ch = ReadCh();
  945.     if (tolower(ch) != 'y') {
  946.       Write_to_screen("No.", 0);
  947.       fflush(stdout);
  948.       return(FALSE);
  949.     }
  950.     Write_to_screen("Yes.", 0);
  951.     fflush(stdout);
  952.  
  953.     return(TRUE);
  954. }
  955.  
  956.  
  957. int
  958. append_sig(file)
  959. FILE *file;
  960. {
  961.     /* Append the correct signature file to file.  Return TRUE if
  962.            we append anything.  */
  963.  
  964.         /* Look at the to and cc list to determine which one to use */
  965.  
  966.     /* We could check the bcc list too, but we don't want people to
  967.            know about bcc, even indirectly */
  968.  
  969.     /* Some people claim that  user@anything.same_domain should be
  970.        considered local.  Since it's not the same machine, better be
  971.            safe and use the remote sig (presumably it has more complete
  972.            information).  You can't necessarily finger someone in the
  973.            same domain. */
  974.  
  975.       if (!batch_only && (local_signature[0] || remote_signature[0])) {
  976.  
  977.             char filename2[SLEN];
  978.         char *sig;
  979.  
  980.           if (index(expanded_to, '!') || index(expanded_cc,'!'))
  981.               sig = remote_signature;        /* ! always means remote */
  982.             else {
  983.           /* check each @ for @thissite.domain */
  984.           /* if any one is different than this, then use remote sig */
  985.           int len;
  986.           char *ptr;
  987.           char sitename[SLEN];
  988.           sprintf(sitename,"@%s",hostfullname);
  989.           len = strlen(sitename);
  990.               sig = local_signature;
  991.               for (ptr = index(expanded_to,'@'); ptr;  /* check To: list */
  992.               ptr = index(ptr+1,'@')) {
  993.         if (strincmp(ptr,sitename,len) != 0
  994.             || (*(ptr+len) != ',' && *(ptr+len) != 0
  995.             && *(ptr+len) != ' ')) {
  996.               sig = remote_signature;
  997.                   break;
  998.                 }
  999.               }
  1000.               if (sig == local_signature)           /* still local? */
  1001.                 for (ptr = index(expanded_cc,'@'); ptr;   /* check Cc: */
  1002.             ptr = index(ptr+1,'@')) {
  1003.           if (strincmp(ptr,sitename,len) != 0
  1004.               || (*(ptr+len) != ',' && *(ptr+len) != 0
  1005.               && *(ptr+len) != ' ')) {
  1006.                 sig = remote_signature;
  1007.                     break;
  1008.                   }
  1009.                 }
  1010.             }
  1011.  
  1012.             if (sig[0]) {  /* if there is a signature file */
  1013.           if (sig_dashes) /* dashes are optional */
  1014.             fprintf(file, "\n-- \n");  /* News 2.11 compatibility? */
  1015. #ifdef OS2
  1016.           if (sig[0] != '/' && sig[0] != '\\' &&
  1017.           (!isalpha(sig[0]) || sig[1] != ':'))
  1018. #else
  1019.           if (sig[0] != '/')
  1020. #endif
  1021.             sprintf(filename2, "%s/%s", home, sig);
  1022.           else
  1023.             strcpy(filename2, sig);
  1024.           (void) append(file, filename2);
  1025.  
  1026.               return TRUE;
  1027.             }
  1028.           }
  1029.  
  1030. return FALSE;
  1031.  
  1032. }
  1033.  
  1034. perhaps_pgp_encode(filename)
  1035. char *filename;
  1036. {
  1037.   char buffer[VERY_LONG_STRING];
  1038.   FILE *msg;
  1039.   int encrypt = 0;
  1040.   int sign = 0;
  1041.  
  1042.   if ((msg = fopen(filename, "r")) == NULL)
  1043.     return -1;
  1044.  
  1045.   while (fgets(buffer, sizeof(buffer), msg) != NULL)
  1046.     if (strncmp(buffer, "[pgp-encrypt]\n", 14) == 0) {
  1047.       encrypt = 1;
  1048.       strcpy(buffer, strip_parens(strip_commas(expanded_to)));
  1049.       if (expanded_cc[0]) {
  1050.     strcat(buffer, " ");
  1051.     strcat(buffer, strip_parens(strip_commas(expanded_cc)));
  1052.       }
  1053.       if (expanded_bcc[0]) {
  1054.     strcat(buffer, " ");
  1055.     strcat(buffer, strip_parens(strip_commas(expanded_bcc)));
  1056.       }
  1057.       strcat(buffer, " ");
  1058.       strcat(buffer, username); /* add sender id too! */
  1059.       strcat(buffer, "@");
  1060.       strcat(buffer, hostname);
  1061.       break;
  1062.     }
  1063.     else if (strncmp(buffer, "[pgp-sign]\n", 11) == 0) {
  1064.       sign = 1;
  1065.       break;
  1066.     }
  1067.     else if (strncmp(buffer, "[pgp-encrypt ", 13) == 0 &&
  1068.          strncmp(buffer + strlen(buffer) - 2, "]\n", 2) == 0) {
  1069.       strcpy(buffer, buffer + 13);
  1070.       buffer[strlen(buffer) - 2] = 0;
  1071.       encrypt = 1;
  1072.       break;
  1073.     }
  1074.   fclose(msg);
  1075.  
  1076.   if (encrypt)
  1077.     return pgp_encrypt(filename, buffer);
  1078.  
  1079.   if (sign)
  1080.     return pgp_sign(filename);
  1081.  
  1082.   return 0;
  1083. }
  1084.  
  1085. pgp_encrypt(filename, to)
  1086. char *filename, *to;
  1087. {
  1088.   char  buffer[SLEN];
  1089.   char  pgpfn[SLEN];
  1090.   int   dotpos = 0;
  1091.  
  1092.   sprintf(buffer, "pgp -seaw %s %s", filename, to);
  1093.   puts("\r\n\n");
  1094.  
  1095.   if (system_call(buffer, SH, FALSE, FALSE) == 0) {
  1096.  
  1097.     do { ++dotpos; } while (filename[dotpos] != '.');
  1098.     strncpy(pgpfn, filename, dotpos);
  1099.     strcpy(pgpfn + dotpos, ".asc");
  1100.  
  1101.     if(rename(pgpfn,filename)) {
  1102.       printf("Error with renaming %s to %s in pgp_encrypt! (%s)\n",
  1103.          pgpfn, filename, error_name(errno));
  1104.       return(-1);
  1105.     }
  1106.  
  1107.     return(0);
  1108.   }
  1109.   else {            /* something went wrong. Bad password or user spec */
  1110.     printf("Error while encrypting. Try again.");
  1111.     return(-1);
  1112.   }
  1113. }
  1114.  
  1115. pgp_sign(filename)
  1116. char *filename;
  1117. {
  1118.   char  buffer[SLEN];
  1119.   char  pgpfn[SLEN];
  1120.   int   dotpos = 0;
  1121.  
  1122.   sprintf(buffer, "pgp -sta +clearsig=on %s", filename);
  1123.   puts("\r\n\n");
  1124.  
  1125.   if (system_call(buffer, SH, FALSE, FALSE) == 0) {
  1126.  
  1127.     do { ++dotpos; } while (filename[dotpos] != '.');
  1128.     strncpy(pgpfn, filename, dotpos);
  1129.     strcpy(pgpfn + dotpos, ".asc");
  1130.  
  1131.     if(unlink(filename) || rename(pgpfn,filename)) {
  1132.       printf("Error with renaming %s to %s in pgp_sign! (%s)\n",
  1133.          pgpfn, filename, error_name(errno));
  1134.       return(-1);
  1135.     }
  1136.  
  1137.     return(0);
  1138.   }
  1139.   else {            /* something went wrong. Bad password or user spec */
  1140.     printf("Error while signing. Try again.");
  1141.     return(-1);
  1142.   }
  1143. }
  1144.