home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / INTERNET / UPC2S1.ZIP / MAILSEND.C < prev    next >
C/C++ Source or Header  |  1993-10-04  |  36KB  |  1,020 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    m a i l s e n d . c                                             */
  3. /*                                                                    */
  4. /*    Subroutines for sending mail for UUPC/extended                  */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  9. /*       Wonderworks.                                                 */
  10. /*                                                                    */
  11. /*       All rights reserved except those explicitly granted by       */
  12. /*       the UUPC/extended license agreement.                         */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: mailsend.c 1.6 1993/10/04 03:57:20 ahd Exp $
  21.  *
  22.  *    Revision history:
  23.  *    $Log: mailsend.c $
  24.  * Revision 1.6  1993/10/04  03:57:20  ahd
  25.  * Clarify error message
  26.  *
  27.  * Revision 1.5  1993/08/02  03:24:59  ahd
  28.  * Further changes in support of Robert Denny's Windows 3.x support
  29.  *
  30.  * Revision 1.4  1993/07/31  16:26:01  ahd
  31.  * Changes in support of Robert Denny's Windows support
  32.  *
  33.  */
  34.  
  35. /*--------------------------------------------------------------------*/
  36. /*                        System include files                        */
  37. /*--------------------------------------------------------------------*/
  38.  
  39. #include <ctype.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <sys/types.h>
  44. #include <sys/stat.h>
  45.  
  46. /*--------------------------------------------------------------------*/
  47. /*                    UUPC/extended include files                     */
  48. /*--------------------------------------------------------------------*/
  49.  
  50. #include "lib.h"
  51.  
  52. #include "arpadate.h"
  53. #include "expath.h"
  54. #include "execute.h"
  55. #include "hlib.h"
  56. #include "mlib.h"
  57. #include "alias.h"
  58. #include "mail.h"
  59. #include "maillib.h"
  60. #include "mailblib.h"
  61. #include "mailsend.h"
  62. #include "safeio.h"
  63. #include "address.h"
  64.  
  65. /*--------------------------------------------------------------------*/
  66. /*                     Local function prototypes                      */
  67. /*--------------------------------------------------------------------*/
  68.  
  69.  static char *ExplodeAlias(char *header ,
  70.                       const char *alias,
  71.                       FILE *stream,
  72.                       const boolean resent);
  73.  
  74.  
  75.  static void PutHead( const char *label,
  76.                       const char *operand,
  77.                       FILE *stream,
  78.                       const boolean resent);
  79.  
  80.  static boolean Append_Signature(FILE *mailbag,
  81.                      const boolean alternate);
  82.  
  83.  static void Prompt_Input( char *tmailbag,
  84.                           FILE *fmailbag,
  85.                            char *subject,
  86.                           const int current);
  87.  
  88.  static boolean Subcommand( char *buf,
  89.                            FILE *fmailbag,
  90.                            char *tmailbag,
  91.                            char *subject,
  92.                            const int current_msg);
  93.  
  94.  static void CopyOut( const char* input);
  95.  
  96.  static void filter( char *tmailbag, char *command);
  97.  
  98.  static char *GetString( char *input);
  99.  
  100. currentfile();                /* Define current file for panic()     */
  101.  
  102. /*--------------------------------------------------------------------*/
  103. /*    E x p l o d e A l i a s                                         */
  104. /*                                                                    */
  105. /*    Resolves an alias, exploding it into a list if needed.          */
  106. /*--------------------------------------------------------------------*/
  107.  
  108.  static char *ExplodeAlias(char *header ,
  109.                       const char *alias,
  110.                       FILE *stream,
  111.                       const boolean resent)
  112. {
  113.    char *fullname;
  114.    char buffer[LSIZE];
  115.  
  116.    if ((alias == NULL) || (strlen(alias) == 0))
  117.    {
  118.       printmsg(0,"ExplodeAlias: NULL or empty string for argument");
  119.       panic();
  120.    }
  121.  
  122.    fullname = AliasByNick(alias);
  123.  
  124.    printmsg(4,"Processing alias '%s', result '%s'", alias,
  125.       (fullname == NULL) ? alias : fullname);
  126.  
  127.    if (fullname == NULL)            /* No alias found for user?     */
  128.    {                                /* No --> Try node lookup       */
  129.       char user[MAXADDR];
  130.       char node[MAXADDR];
  131.       char path[MAXADDR];
  132.       char bucket[MAXADDR];
  133.  
  134.       ExtractAddress(bucket, (char *) alias, FALSE);
  135.       user_at_node(bucket, path, node, user);
  136.       fullname = AliasByAddr( node, user);
  137.  
  138.       if (fullname == NULL)         /* Did we come up empty?         */
  139.       {
  140.          char *hisuser, *hisnode;
  141.  
  142.          hisuser = strtok( bucket, "@");
  143.          hisnode = strtok( NULL, "@");
  144.          if ((*bucket != '@') &&
  145.              equal(hisuser, user ) && (hisnode != NULL) &&
  146.              equal(hisnode, node ) && (strchr( node, '.') == NULL))
  147.          {
  148.             if (equal(hisnode, E_nodename))
  149.                strcpy(node, E_fdomain);
  150.             else {
  151.                strcat(node,".");
  152.                strcat(node,E_localdomain);
  153.             }
  154.  
  155.             ExtractAddress(path, (char *) alias, TRUE);
  156.             if (strlen( path ) == 0)
  157.                sprintf(buffer,"%s@%s", hisuser, node );
  158.             else
  159.                sprintf(buffer,"\"%s\" <%s@%s>", path, hisuser, node);
  160.             fullname = buffer;
  161.          }
  162.          else
  163.             fullname = (char *) alias; /* Use original information      */
  164.       }
  165.    }
  166.    else {
  167.       ExtractAddress(buffer,fullname,TRUE);
  168.       if (strlen(buffer) == 0)      /* A list of users?              */
  169.       {                             /* Yes --> Do recursive call     */
  170.          char *current = buffer;    /* Current token being processed */
  171.          char *next = NULL;         /* Next token to process         */
  172.  
  173.          strcpy(buffer,fullname);
  174.  
  175.          do {
  176.             current = strtok(current,",\t "); /* Get next alias to process */
  177.             next    = strtok(NULL,"");    /* Also save rest of list        */
  178.             header  = ExplodeAlias( header , current, stream, resent);
  179.                                           /* Get alias, including sub-list */
  180.             current  = next;
  181.          } while ( next != NULL );        /* Until no more tokens exist    */
  182.  
  183.          return header;                   /* Have written header, return   */
  184.  
  185.       } /* if */
  186.    } /* else */
  187.  
  188.    if (strpbrk(fullname,"!@") == nil(char))
  189.    {
  190.       sprintf(buffer,"%s@%s", fullname , E_fdomain);
  191.                               /* Local address                    */
  192.       fullname = buffer;      /* Write out the formatted address  */
  193.    }
  194.  
  195.    PutHead(header, fullname, stream, resent);
  196.                               /* Remote address                   */
  197.    return "";                 /* Make header empty string for
  198.                                  next caller                      */
  199. } /* ExplodeAlias */
  200.  
  201. /*--------------------------------------------------------------------*/
  202. /*    A p p e n d _ S i g n a t u r e                                 */
  203. /*                                                                    */
  204. /*    Append the signature file to the specified mailbag file         */
  205. /*                                                                    */
  206. /*    [Broke this code out from Send_Mail to support the ~a mail      */
  207. /*    subcommand]                                                     */
  208. /*                                                                    */
  209. /*    Returns:  0 on success, 1 if signature file not found           */
  210. /*--------------------------------------------------------------------*/
  211.  
  212. static boolean Append_Signature(FILE *mailbag_fp ,
  213.                      const boolean alternate)
  214. {
  215.    FILE *sigfp;
  216.    char *sig;
  217.    char sigfile[FILENAME_MAX];
  218.    char buf[BUFSIZ];
  219.  
  220.    sig = alternate ? E_altsignature : E_signature;
  221.  
  222.    if(sig != nil(char)) {
  223.       mkfilename(sigfile, E_homedir, sig);
  224.       printmsg(4, "Append_Signature: signature file %s", sigfile);
  225.       if ((sigfp = FOPEN(sigfile, "r",TEXT_MODE)) != nil(FILE)) {
  226.          fputs("-- \n", mailbag_fp);
  227.          while (fgets(buf, BUFSIZ, sigfp) != nil(char))
  228.             fputs(buf, mailbag_fp);
  229.          fclose(sigfp);
  230.          return(0);
  231.       }
  232.       else {
  233.          printmsg(0, "Signature file \"%s\" doesn't exist!\n", sigfile);
  234.          return(1);
  235.       }
  236.    }
  237.    return(0);
  238. }  /* Append_Signature */
  239.  
  240. /*--------------------------------------------------------------------*/
  241. /*    S e n d _ M a i l                                               */
  242. /*                                                                    */
  243. /*    Send text in a mailbag file to address(es) specified by line.   */
  244. /*--------------------------------------------------------------------*/
  245.  
  246. boolean Send_Mail(FILE *datain,
  247.                int argc,
  248.                char *argv[],
  249.                char *subject,
  250.                const boolean resent)
  251. {
  252.    int argx = 0;
  253.    char buf[LSIZE];
  254.    char *header    = "To:";
  255.    char *CcHeader  = "Cc:";
  256.    char *BccHeader = "Bcc:";
  257.    char *pipename  = mktempname(NULL, "TMP");
  258.    FILE *stream = FOPEN(pipename , "w",TEXT_MODE);
  259.    int status;
  260.  
  261. /*--------------------------------------------------------------------*/
  262. /*                     Verify our workfile opened                     */
  263. /*--------------------------------------------------------------------*/
  264.  
  265.    if ( stream == NULL )
  266.    {
  267.       printerr(pipename);
  268.       free(pipename);
  269.       return FALSE;
  270.    }
  271.  
  272. /*--------------------------------------------------------------------*/
  273. /*    Add the boilerplate the front:                                  */
  274. /*                                                                    */
  275. /*       Date, From, Organization, and Reply-To                       */
  276. /*--------------------------------------------------------------------*/
  277.  
  278.    PutHead("Date:", arpadate() , stream, resent);
  279.  
  280.    if (bflag[F_BANG])
  281.       sprintf(buf, "(%s) %s!%s", E_name, E_fdomain, E_mailbox );
  282.    else
  283.       sprintf(buf, "\"%s\" <%s@%s>", E_name, E_mailbox, E_fdomain );
  284.    PutHead("From:", buf, stream , resent);
  285.  
  286.    if (E_organization != NULL )
  287.       PutHead("Organization:", E_organization, stream, resent );
  288.  
  289.    if (E_replyto != NULL )
  290.    {
  291.       if (strpbrk(E_replyto,"!@") == nil(char))
  292.          sprintf(buf,"\"%s\" <%s@%s>", E_name, E_replyto , E_fdomain);
  293.       else
  294.          sprintf(buf,"\"%s\" <%s>", E_name, E_replyto);
  295.       PutHead("Reply-To:", buf, stream, resent );
  296.    }
  297.  
  298. /*--------------------------------------------------------------------*/
  299. /*                      Write the addressees out                      */
  300. /*--------------------------------------------------------------------*/
  301.  
  302.    for (argx = 0 ; argx < argc; argx++ )
  303.    {
  304.       if (equal(argv[argx],"-c"))
  305.       {
  306.          header = CcHeader;
  307.          CcHeader = "";
  308.       } /* if */
  309.       else if (equal(argv[argx],"-b"))
  310.       {
  311.          header = BccHeader;
  312.          CcHeader = BccHeader = "";
  313.       } /* if else */
  314.       else
  315.          header = ExplodeAlias( header , argv[argx], stream, resent);
  316.    } /* for */
  317.  
  318. /*--------------------------------------------------------------------*/
  319. /*                  Prompt for carbon copies, if any                  */
  320. /*--------------------------------------------------------------------*/
  321.  
  322.    if ( bflag[F_ASKCC] && Is_Console(stdin) &&
  323.         Console_fgets(buf,LSIZE,"Cc: "))
  324.    {
  325.       char *current = buf;
  326.       header = CcHeader;
  327.       CcHeader = "";
  328.       printmsg(4,"CC buffer: %s",current);
  329.  
  330.       while ((current != NULL) &&
  331.              (current = strtok(current,",\t\n ")) != NULL)
  332.       {
  333.          char *next  =  strtok(NULL,"");
  334.          if (equal(current,"-b"))
  335.          {
  336.             header = BccHeader;
  337.             CcHeader = BccHeader = "";
  338.          } /* if */
  339.          else
  340.             header = ExplodeAlias( header, current, stream, resent);
  341.          current = next;
  342.       } /* while */
  343.    }  /* If Console_fgets() */
  344.  
  345. /*--------------------------------------------------------------------*/
  346. /*                     Handle the subject, if any                     */
  347. /*--------------------------------------------------------------------*/
  348.  
  349.    if (subject != NULL)
  350.       PutHead("Subject:",subject, stream, resent);
  351.    PutHead(NULL, "", stream, resent);  /* Terminate the header file   */
  352.  
  353. /*--------------------------------------------------------------------*/
  354. /*                    Copy the body of the message                    */
  355. /*--------------------------------------------------------------------*/
  356.  
  357.    while (fgets(buf, LSIZE, datain) != nil(char))
  358.    {
  359.       int result = fputs(buf, stream );
  360.       if (result == EOF)
  361.       {
  362.          printerr( pipename );
  363.          panic();
  364.       } /* if */
  365.       if (buf[strlen(buf)-1] != '\n')
  366.             fputc('\n', stream);
  367.    } /* while */
  368.  
  369.    if (!feof(datain))
  370.    {
  371.       printerr("Send_Mail:");
  372.       panic();
  373.    } /* if */
  374.  
  375.    if (datain != stdin)
  376.       fclose(datain);
  377.  
  378. /*--------------------------------------------------------------------*/
  379. /*    Append user's primary signature file, if autosign option on     */
  380. /*--------------------------------------------------------------------*/
  381.  
  382.    if ( bflag[F_AUTOSIGN] )
  383.       Append_Signature(stream, FALSE);
  384.  
  385.    fclose(stream);
  386.  
  387. /*--------------------------------------------------------------------*/
  388. /*                  Invoke the mail delivery program                  */
  389. /*--------------------------------------------------------------------*/
  390.  
  391.  
  392.    sprintf(buf, "-t -f %s", pipename);
  393.    status = execute(RMAIL, buf, NULL, NULL, TRUE, FALSE );
  394.  
  395.    if ( status < 0 )
  396.    {
  397.       printerr( RMAIL );
  398.       printmsg(0,"Unable to execute rmail; mail not delivered.");
  399.    }
  400.    else if ( status > 0 )
  401.       printmsg(0,
  402.          "rmail returned non-zero status; delivery may be incomplete.");
  403.  
  404. /*--------------------------------------------------------------------*/
  405. /*               Log a copy of the mail for the sender                */
  406. /*--------------------------------------------------------------------*/
  407.  
  408.    if (bflag[F_SAVERESENT] || ! resent)
  409.       CopyOut(pipename);
  410.  
  411. /*--------------------------------------------------------------------*/
  412. /*                   Clean up and return to caller                    */
  413. /*--------------------------------------------------------------------*/
  414.  
  415.    remove(pipename);
  416.    free(pipename);
  417.    return (status == 0 );
  418.  
  419. } /*Send_Mail*/
  420.  
  421. /*--------------------------------------------------------------------*/
  422. /*    C o p y O u t                                                   */
  423. /*                                                                    */
  424. /*    Save copy of outgoing mail, if desired                          */
  425. /*--------------------------------------------------------------------*/
  426.  
  427. static void CopyOut( const char* input)
  428. {
  429.    FILE *datain;
  430.    FILE *dataout;
  431.    char buf[BUFSIZ];
  432.    char outbox[FILENAME_MAX];
  433.  
  434.    if (E_filesent == NULL)
  435.       return;
  436.  
  437.    strcpy( outbox, E_filesent);
  438.    expand_path( outbox, E_homedir, E_homedir, E_mailext );
  439.  
  440.    datain = FOPEN( input, "r",TEXT_MODE);
  441.  
  442.    if (datain == NULL )
  443.    {
  444.       printerr(input);
  445.       panic();
  446.    } /* if */
  447.  
  448.    dataout = FOPEN( outbox, "a",TEXT_MODE);
  449.    if (dataout == NULL )
  450.    {
  451.       printerr( outbox );
  452.       panic();
  453.    } /* if */
  454.  
  455.    fputs(MESSAGESEP,dataout);
  456.  
  457.    while (fgets(buf, BUFSIZ, datain) != nil(char))
  458.    {
  459.       int result = fputs(buf, dataout);
  460.       if (result == EOF)
  461.       {
  462.          printerr( outbox );
  463.          panic();
  464.       } /* if */
  465.    } /* while */
  466.  
  467.    if (!feof(datain))
  468.    {
  469.       printerr(input);
  470.       panic();
  471.    } /* if */
  472.  
  473.    fclose(datain);
  474.    fclose(dataout);
  475. } /* CopyOut */
  476.  
  477. /*--------------------------------------------------------------------*/
  478. /* P u t H e a d                                                      */
  479. /*                                                                    */
  480. /* Write one line of an RFC-822 header                                */
  481. /*--------------------------------------------------------------------*/
  482.  
  483.  static void PutHead( const char *label,
  484.                       const char *operand,
  485.                       FILE *stream,
  486.                       const boolean resent)
  487.  {
  488.    static boolean terminate = TRUE;
  489.                               /* If previous line was terminated     */
  490.  
  491.    if (label == NULL )        /* Terminate call?                     */
  492.    {                          /* Yes --> Reset Flag and return       */
  493.       fputc('\n', stream);    /* Terminate the current line          */
  494.       if (!resent)
  495.          fputc('\n', stream); /* Terminate the header file           */
  496.       terminate = TRUE;
  497.       return;
  498.    } /* if */
  499.  
  500.    if (strlen(label))         /* First line of a header?             */
  501.    {
  502.       if (!terminate)         /* Terminate previous line?            */
  503.          fputc('\n', stream);
  504.       if (resent)
  505.          fprintf(stream,"Resent-%s %s",label, operand);
  506.       else
  507.          fprintf(stream,"%-10s %s",label, operand);
  508.       terminate = FALSE;          /* Flag that we did not end file   */
  509.    } /* if */
  510.    else                       /* Continuing line                     */
  511.       fprintf(stream,",\n%-10s %s",label, operand);
  512.  } /* PutHead */
  513.  
  514. /*--------------------------------------------------------------------*/
  515. /*    C o l l e c t _ M a i l                                         */
  516. /*                                                                    */
  517. /*    Create mailbox file for delivery                                */
  518. /*--------------------------------------------------------------------*/
  519.  
  520. boolean Collect_Mail(FILE *stream,
  521.                   int argc,
  522.                   char **argv,
  523.                   const int current_msg,
  524.                   const boolean reply)
  525. {
  526.    boolean editonly = FALSE;
  527.    char Subuffer[LSIZE];
  528.    char *subject = NULL;
  529.    char *tmailbag;
  530.    int  c;                    /* Really a 'char', but who cares?     */
  531.    boolean done = FALSE;
  532.    FILE  *fmailbag;
  533.  
  534.  
  535. /*--------------------------------------------------------------------*/
  536. /*      Determine if we are running interactively; if not, just       */
  537. /*         pass the input stream to Send_Mail for processing          */
  538. /*--------------------------------------------------------------------*/
  539.  
  540.    if (!Is_Console(stream))
  541.    {
  542.       if ( equal(argv[0], "-s" ) )
  543.          return Send_Mail( stream, argc-2, argv+2, argv[1], FALSE);
  544.       else
  545.          return Send_Mail( stream , argc , argv, NULL , FALSE);
  546.    } /* if */
  547.  
  548. /*--------------------------------------------------------------------*/
  549. /*    We are running interactively; create a determine the name of    */
  550. /*                        our work file to be.                        */
  551. /*--------------------------------------------------------------------*/
  552.  
  553.    *Subuffer = '\0';          /* Assume no subject */
  554.    tmailbag = mktempname( NULL, "TXT");
  555.  
  556. /*--------------------------------------------------------------------*/
  557. /*         Determine if we should go straight into the editor         */
  558. /*--------------------------------------------------------------------*/
  559.  
  560.    editonly = bflag[F_AUTOEDIT] && (E_editor != NULL);
  561.  
  562.    if ( equal(argv[0],"-s"))     /* Any subject specified?           */
  563.    {
  564.       strcpy( Subuffer , argv[1] ); /* Save the subject for later    */
  565.       argv += 2;                 /* Skip over it in argument list    */
  566.       argc -= 2;                 /* Giving us fewer args left        */
  567.    }
  568.    else {                        /* No --> Prompt for one            */
  569.       if(Console_fgets(Subuffer,LSIZE,"Subject: "))
  570.       {
  571.          if (Subuffer[strlen(Subuffer) - 1 ] == '\n')
  572.             Subuffer[strlen(Subuffer)-1] = '\0';   /* End the subject */
  573.       }  /* If Console_fgets() */
  574.    } /* if ( equal(argv[0],"-s")) */
  575.  
  576. /*--------------------------------------------------------------------*/
  577. /*      Copy a message from the original input to temporary file      */
  578. /*--------------------------------------------------------------------*/
  579.  
  580.    fmailbag = FOPEN(tmailbag, "w",TEXT_MODE);
  581.    if (fmailbag == NULL )
  582.    {
  583.       printerr( tmailbag );
  584.       panic();
  585.    }
  586.  
  587. /*--------------------------------------------------------------------*/
  588. /*               Include incoming message if requested                */
  589. /*--------------------------------------------------------------------*/
  590.  
  591.    if ( bflag[F_AUTOINCLUDE] && reply)
  592.    {
  593.        CopyMsg(current_msg, fmailbag, fromheader , TRUE);
  594.        fprintf(stdout, "Message %d Included\n", current_msg+1);
  595.    } /* if ( bflag[F_AUTOINCLUDE] && reply) */
  596.  
  597. /*--------------------------------------------------------------------*/
  598. /*                     Edit the file if requested                     */
  599. /*--------------------------------------------------------------------*/
  600.  
  601.    if (editonly)              /* Enter editor immediately?     ahd   */
  602.    {                          /* Yes --> Go to it                    */
  603.       fclose(fmailbag);
  604.       Invoke(E_editor, tmailbag);
  605.    } /* if */
  606.    else {                     /* No  --> prompt for data       ahd   */
  607.       Prompt_Input( tmailbag , fmailbag , Subuffer, current_msg );
  608.       fclose(fmailbag);
  609.    } /*else */
  610.  
  611.  
  612.    do {
  613.       fputs("\nAbort, Continue, Edit, List, or Send? ",stdout);
  614.       c     = Get_One();             /* adaptation for QuickC */  /* pdm */
  615.       switch (tolower( c ))
  616.       {
  617.          case 'c':
  618.             puts("Continue");
  619.             fmailbag = FOPEN(tmailbag, "a",TEXT_MODE);
  620.             Prompt_Input( tmailbag , fmailbag , Subuffer, current_msg );
  621.  
  622. #if defined(_Windows)
  623.             //
  624.             // Prompt_Input() comes back with EOF on stdin!
  625.             //
  626.             rewind(stdin);
  627. #endif
  628.             fclose(fmailbag);
  629.             break;
  630.  
  631.          case 'l':
  632.             puts("List");
  633.             Sub_Pager(tmailbag, islower(c) );
  634.             break;
  635.  
  636.          case 's':
  637.             puts("Send");
  638.             fmailbag = FOPEN(tmailbag, "r",TEXT_MODE);
  639.             if (fmailbag == NULL )
  640.             {
  641.                printerr(tmailbag);
  642.                panic();
  643.             }
  644.             if ( strlen( Subuffer ))
  645.                subject = Subuffer;
  646.             Send_Mail(fmailbag, argc, argv, subject, FALSE);
  647.             done = TRUE;
  648.             break;
  649.  
  650.          case 'e':
  651.             puts("Edit");
  652.             Invoke(E_editor, tmailbag);
  653.             break;
  654.  
  655.          case 'a':
  656.             fputs("Abort\nAre you sure? ", stdout);
  657.             safeflush();
  658.             c = Get_One();             /* for QuickC */          /* pdm */
  659.             switch (tolower(c)) {      /* unravel these two calls */
  660.             case 'y':
  661.                puts("Yes");
  662.                done = TRUE;
  663.                break;
  664.             default:
  665.                puts("No");
  666.             } /*switch*/
  667.             break;
  668.  
  669.          default:
  670.             puts("\n\aEnter A, C, E, L, or S.");
  671.             safeflush();
  672.             done = FALSE;
  673.       } /*switch*/
  674.    } while (!done);
  675.  
  676.    remove(tmailbag);
  677.    free(tmailbag);
  678.  
  679.    return TRUE;
  680. } /*Collect_Mail*/
  681.  
  682.  
  683. /*--------------------------------------------------------------------*/
  684. /*    P r o m p t _ I n p u t                                         */
  685. /*                                                                    */
  686. /*    Prompt for mail entry interactively.                            */
  687. /*--------------------------------------------------------------------*/
  688.  
  689. static void Prompt_Input( char *tmailbag,
  690.             FILE *fmailbag,
  691.             char *subject,
  692.             const int current_msg)
  693. {
  694.    char buf[LSIZE];
  695.  
  696.    printf("\nEnter message.  Enter ~? for help.  End input with %s\n",
  697.           bflag[ F_DOT ] ?  "a period (.)" :
  698.          "end-of-file (Control-Z)");
  699.    for ( ; ; )
  700.    {
  701.       if (Console_fgets(buf, LSIZE, "? "))
  702.       {
  703.          if (bflag[F_DOT] && equal(buf,".\n"))
  704.             break;
  705.          else if (Subcommand( buf, fmailbag, tmailbag, subject, current_msg) )
  706.             continue;      /*Don't write line out if subcommand   */
  707.       } /* if */
  708.       else
  709.          break;            /* Exit loop if end of file            */
  710.  
  711.       if (fputs(buf, fmailbag) == EOF )
  712.       {
  713.          printerr( tmailbag );
  714.          panic();
  715.       } /* if (fputs(buf, fmailbag) == EOF ) */
  716.  
  717.       if (buf[strlen(buf)-1] != '\n')
  718.          fputc('\n', fmailbag);
  719.    } /* for */
  720. } /* Prompt_Input */
  721.  
  722. /*--------------------------------------------------------------------*/
  723. /*    S u b c o m m a n d                                             */
  724. /*                                                                    */
  725. /*    Handle tilde (~) subcommands for Interactive mail               */
  726. /*--------------------------------------------------------------------*/
  727.  
  728. static boolean Subcommand( char *buf,
  729.                            FILE *fmailbag,
  730.                            char *tmailbag,
  731.                            char *subject,
  732.                            const int current_msg)
  733. {
  734.    int message;
  735.    char fname[FILENAME_MAX];
  736.    char *token;
  737.    FILE *stream;
  738.  
  739.    if(*buf == '~')        /* Handle mail subcommands  pdm */
  740.    {
  741.       switch(buf[1])
  742.       {
  743.  
  744. /*--------------------------------------------------------------------*/
  745. /*                     Treat as normal data line                      */
  746. /*--------------------------------------------------------------------*/
  747.  
  748.          case '~':
  749.             memmove( buf, buf + 1, strlen( buf + 1 ));
  750.             return FALSE;        // Treat as normal line
  751.  
  752. /*--------------------------------------------------------------------*/
  753. /*              Put signature file into current message               */
  754. /*--------------------------------------------------------------------*/
  755.  
  756.          case 'a':
  757.          case 'A':
  758.             Append_Signature(fmailbag, isupper( buf[1] ));
  759.             fputs("(continue)\n", stdout);
  760.             break;
  761.  
  762. /*--------------------------------------------------------------------*/
  763. /*                       Edit outgoing message                        */
  764. /*--------------------------------------------------------------------*/
  765.  
  766.          case 'v':            /* UNIX allows 'v'isual editor         */
  767.          case 'e':
  768.             /* invoke editor with current msg */
  769.             fclose(fmailbag);
  770.             Invoke(E_editor, tmailbag);
  771.             fmailbag = FOPEN(tmailbag, "a",TEXT_MODE);
  772.             fputs("(continue)\n", stdout);
  773.             break;
  774.  
  775. /*--------------------------------------------------------------------*/
  776. /*                 Include any letter in this message                 */
  777. /*--------------------------------------------------------------------*/
  778.  
  779.          case 'f':
  780.          case 'F':
  781.          case 'i':
  782.          case 'I':
  783.          case 'm':
  784.          case 'M':
  785.             if (fmailbox == NULL)
  786.                puts("Mailbox not accessible!");
  787.             else {
  788.                int *item_list;
  789.                int next_item = PushItemList( &item_list );
  790.                boolean first_pass = TRUE;
  791.  
  792.                token = GetString( &buf[2] );
  793.  
  794.                if (SelectItems( &token, current_msg, LETTER_OP ))
  795.                while( Get_Operand( &message, &token, LETTER_OP, first_pass))
  796.                {
  797.                   CopyMsg( message , fmailbag,
  798.                            islower(buf[1]) ? fromheader : noseperator ,
  799.                            tolower(buf[1]) != 'f');
  800.                   fprintf(stdout, "Message %d included\n", message + 1);
  801.                   first_pass = FALSE;
  802.                } /* while */
  803.  
  804.                PopItemList( item_list, next_item );
  805.             } /* else */
  806.             break;
  807.  
  808. /*--------------------------------------------------------------------*/
  809. /*                       Print current message                        */
  810. /*--------------------------------------------------------------------*/
  811.  
  812.          case 'p':
  813.          case 'P':
  814.             fclose(fmailbag);
  815.             Sub_Pager(tmailbag, islower(buf[1]) );
  816.             fmailbag = FOPEN(tmailbag, "a",TEXT_MODE);
  817.             fputs("(continue)\n", stdout);
  818.             break;
  819.  
  820. /*--------------------------------------------------------------------*/
  821. /*                           Include a file                           */
  822. /*--------------------------------------------------------------------*/
  823.  
  824.          case 'r':
  825.             token = strtok( &buf[2], " \t\n");
  826.             if ( token == NULL )
  827.             {
  828.                printf("Need a file name for this command!\n");
  829.                break;
  830.             }
  831.             strcpy( fname, token );
  832.             if ( expand_path( fname, NULL, E_homedir , NULL) == NULL )
  833.                break;
  834.             stream = FOPEN( fname, "r",TEXT_MODE);
  835.             if (stream == NULL )
  836.             {
  837.                printerr(fname);
  838.                break;
  839.             }
  840.             else while( fgets( buf, LSIZE, stream ))
  841.             {
  842.                fputs( buf, fmailbag);
  843.                if ferror( fmailbag )
  844.                {
  845.                   printerr( tmailbag);
  846.                   break;
  847.                } /* if */
  848.             } /* else while */
  849.             if (ferror( stream ) )
  850.             {
  851.                printerr( fname );
  852.                clearerr( stream );
  853.             } /* if */
  854.             fclose( stream );
  855.             fputs("(continue)\n", stdout);
  856.             break;
  857.  
  858.  
  859. /*--------------------------------------------------------------------*/
  860. /*                        Change mail subject                         */
  861. /*--------------------------------------------------------------------*/
  862.  
  863.          case 's':
  864.             token = GetString( &buf[2] );
  865.             if ( token != NULL )
  866.             {
  867.                strcpy( subject, token );
  868.             }
  869.             else
  870.                printf("No new subject, command ignored\n");
  871.             printf("Subject: %s\n",subject);
  872.             break;
  873.  
  874. /*--------------------------------------------------------------------*/
  875. /*                                Help                                */
  876. /*--------------------------------------------------------------------*/
  877.  
  878.          case '?':
  879.          {
  880.             mkfilename(fname, E_confdir, "tilde.hlp");
  881.             Sub_Pager( fname, TRUE );
  882.             break;
  883.          }
  884.  
  885. /*--------------------------------------------------------------------*/
  886. /*                             A subshell                             */
  887. /*--------------------------------------------------------------------*/
  888.  
  889.          case '!':
  890.             token = strtok( &buf[2], "\n");
  891.             subshell( token );
  892.             break;
  893.  
  894. /*--------------------------------------------------------------------*/
  895. /*                     Pipe mail through a filter                     */
  896. /*--------------------------------------------------------------------*/
  897.  
  898.          case '|':
  899.             fclose( fmailbag );
  900.             filter( tmailbag, &buf[2] );
  901.             fmailbag = FOPEN(tmailbag, "a",TEXT_MODE);
  902.             fputs("(continue)\n", stdout);
  903.             break;
  904.  
  905. /*--------------------------------------------------------------------*/
  906. /*                          Invalid command                           */
  907. /*--------------------------------------------------------------------*/
  908.  
  909.          default:
  910.             fputs("Unknown mail subcommand, ~? for help.\n",
  911.                   stdout);
  912.             break;
  913.       } /* switch */
  914.  
  915.       return TRUE;
  916.    } /* if */
  917.    else
  918.       return FALSE;           /* It wasn't a sub-command             */
  919.  
  920. } /*SubCommand*/
  921.  
  922. /*--------------------------------------------------------------------*/
  923. /*    f i l t e r                                                     */
  924. /*                                                                    */
  925. /*    Filter the next of an outgoing program into the output mail     */
  926. /*--------------------------------------------------------------------*/
  927.  
  928. static void filter( char *tmailbag, char *command)
  929. {
  930.  
  931.    char pipename[FILENAME_MAX];
  932.    struct stat statbuf;
  933.    int    result = 0;
  934.  
  935.    command = GetString( command );
  936.  
  937.    if ( command == NULL )
  938.    {
  939.       printf("No command given for filter");
  940.       return;
  941.    }
  942.  
  943. /*--------------------------------------------------------------------*/
  944. /*   Set up our standard input and standard output for the command    */
  945. /*--------------------------------------------------------------------*/
  946.  
  947.    mktempname(pipename, "TMP");
  948.  
  949. /*--------------------------------------------------------------------*/
  950. /*                          Run the command                           */
  951. /*--------------------------------------------------------------------*/
  952.  
  953.    result = executeCommand( command, tmailbag, pipename, TRUE, TRUE );
  954.  
  955.    if (result == -1)       /* Did spawn fail?            */
  956.          ;                 /* No operation               */
  957.    else if( stat( pipename, &statbuf) <0 )   /* Create output?    */
  958.    {
  959.       printf(0,"Cannot determine status of output %s",pipename);
  960.       printerr( pipename );
  961.    }
  962.    else if( statbuf.st_size == 0 )  /* Anything in the file?      */
  963.       printf("Output file %s is empty!\n", pipename);
  964.    else {                  /* Good output, replace input file     */
  965.       remove( tmailbag );
  966.       if (rename( pipename, tmailbag ))
  967.          printerr( pipename );
  968.    } /* else */
  969.  
  970. /*--------------------------------------------------------------------*/
  971. /*                   Clean up and return to caller                    */
  972. /*--------------------------------------------------------------------*/
  973.  
  974.    remove( pipename );
  975.  
  976. } /* filter */
  977.  
  978. /*--------------------------------------------------------------------*/
  979. /*    G e t S t r i n g                                               */
  980. /*                                                                    */
  981. /*    Get non-whitespace in a string                                  */
  982. /*--------------------------------------------------------------------*/
  983.  
  984. static char *GetString( char *input)
  985. {
  986.    char *end;
  987.  
  988. /*--------------------------------------------------------------------*/
  989. /*                   Look for first data in string                    */
  990. /*--------------------------------------------------------------------*/
  991.  
  992.    while( *input && !isgraph( *input ))
  993.       input++ ;
  994.  
  995. /*--------------------------------------------------------------------*/
  996. /*   If no input or all blanks, return NULL to denote empty string    */
  997. /*--------------------------------------------------------------------*/
  998.  
  999.    if (*input == '\0')
  1000.       return NULL ;
  1001.  
  1002. /*--------------------------------------------------------------------*/
  1003. /*                Delete whitespace from end of string                */
  1004. /*--------------------------------------------------------------------*/
  1005.  
  1006.    end = input + strlen( input ) - 1;
  1007.  
  1008.    while (!isgraph(*end))
  1009.       end--;
  1010.  
  1011.    end[1] = '\0';
  1012.  
  1013. /*--------------------------------------------------------------------*/
  1014. /*                 Return beginning of string to caller               */
  1015. /*--------------------------------------------------------------------*/
  1016.  
  1017.    return input;
  1018.  
  1019. } /* GetString */
  1020.