home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / INTERNET / UPC2S1.ZIP / RMAIL.C < prev    next >
C/C++ Source or Header  |  1993-09-20  |  42KB  |  1,040 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       r m a i l . c                                                */
  3. /*                                                                    */
  4. /*       Delivery agent for UUPC/extended                             */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.             */
  9. /*                                                                    */
  10. /*    Changes Copyright (c) 1990-1993 by Kendra Electronic            */
  11. /*    Wonderworks.                                                    */
  12. /*                                                                    */
  13. /*    All rights reserved except those explicitly granted by the      */
  14. /*    UUPC/extended license agreement.                                */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*--------------------------------------------------------------------*/
  18. /*                          RCS Information                           */
  19. /*--------------------------------------------------------------------*/
  20.  
  21. /*
  22.  *    $Id: rmail.c 1.13 1993/09/20 04:39:51 ahd Exp $
  23.  *
  24.  *    $Log: rmail.c $
  25.  * Revision 1.13  1993/09/20  04:39:51  ahd
  26.  * OS/2 2.x support
  27.  *
  28.  * Revision 1.12  1993/07/31  16:22:16  ahd
  29.  * Changes in support of Robert Denny's Windows 3.x support
  30.  *
  31.  * Revision 1.11  1993/07/24  03:40:55  ahd
  32.  * Make usage() return code unique
  33.  *
  34.  * Revision 1.10  1993/06/13  14:06:00  ahd
  35.  * Save invoked program name and use it for recursive calls
  36.  *
  37.  * Revision 1.9  1993/05/09  03:41:47  ahd
  38.  * Don't use debuglevel -1, it suppresses important configuration errors
  39.  *
  40.  * Revision 1.8  1993/04/15  03:17:21  ahd
  41.  * Correct conditions under which name in userp structure used
  42.  *
  43.  * Revision 1.7  1993/04/13  02:26:30  ahd
  44.  * Make return codes more unique
  45.  *
  46.  * Revision 1.6  1993/04/11  00:33:05  ahd
  47.  * Global edits for year, TEXT, etc.
  48.  *
  49.  * Revision 1.5  1992/12/05  23:38:43  ahd
  50.  * Let logger close the log, not rmail
  51.  *
  52.  * Revision 1.4  1992/12/04  01:00:27  ahd
  53.  * Add copyright messages
  54.  *
  55.  */
  56.  
  57. /*--------------------------------------------------------------------*/
  58. /*    Function:   Stand alone mail delivery module for                */
  59. /*                UUPC/extended                                       */
  60. /*    Language:   Borland C++ 3.1 (ANSI C mode) or Microsoft C 6.0.   */
  61. /*    Arguments:  One or more addresses to deliver mail to            */
  62. /*                or "-t" to direct rmail to read the addresses       */
  63. /*                from the RFC-822 header.                            */
  64. /*                A third mode of operation is to specify '-w' and/   */
  65. /*                or '-s subject' followed by one or more addresses   */
  66. /*                with optional carbon copy flags (-c or -b) before   */
  67. /*                additional addresses.  This causes rmail to         */
  68. /*                function like a bare bones batch version of the     */
  69. /*                MAIL program; a valid RFC-822 header is generated   */
  70. /*                and the mail is delivered, aliases are not expanded */
  71. /*                and the mail is not locally logged.  (The current   */
  72. /*                user id as the from address is used unless the      */
  73. /*                environment variable LOGNAME is set, in which case  */
  74. /*                it is used.)                                        */
  75. /*                Optional argument "-f" to denote file to read in    */
  76. /*                place of stdin.                                     */
  77. /*                Optional argument "-F" to denote file to read in    */
  78. /*                place of stdin and DELETE after readering.          */
  79. /*                Optional argument "-x" to for debug level           */
  80. /*    Input:      mail to be delivered, with RFC-822 header, on       */
  81. /*                stdin.                                              */
  82. /*    Output:     'From' and 'Received:' headers are added,           */
  83. /*                'Bcc:' headers are removed, and the mail is         */
  84. /*                delivered to one or more local users and/or         */
  85. /*                one or more remote users.                           */
  86. /*    Exit code:  0  Success                                          */
  87. /*                1  One or more letters not delivered                */
  88. /*                2  No mail delivered                                */
  89. /*                3 Configuration file error                          */
  90. /*                4 Invalid option/help specified                     */
  91. /*                5 Input/output error                                */
  92. /*                6 Input/output error                                */
  93. /*                7 Input/output error                                */
  94. /*                                                                    */
  95. /*    Note:       When parsing RFC-822 headers, this program          */
  96. /*                expects them to be "well-behaved", that is in       */
  97. /*                format generated by UUPC/extended.  This implies:   */
  98. /*                                                                    */
  99. /*                      One address per line                          */
  100. /*                                                                    */
  101. /*                      Resent- headers, if any, before the original  */
  102. /*                      headers.                                      */
  103. /*                                                                    */
  104. /*                      From: header must precede To: header.         */
  105. /*                                                                    */
  106. /*                      To: header must precede Cc: and Bcc: headers. */
  107. /*                                                                    */
  108. /*                      Cc: and Bcc: headers must be together (one    */
  109. /*                      after the other)                              */
  110. /*                                                                    */
  111. /*                      The MUA has prefixed any obsolete Resent-     */
  112. /*                      headers by X-                                 */
  113. /*                                                                    */
  114. /*    Note:       The "-t" flag is supported by BSD sendmail for the  */
  115. /*                purpose listed above, but we also turn use it to    */
  116. /*                control other special options, all of which         */
  117. /*                basically cause the program to act more like a      */
  118. /*                local mailer than a remote mailer; these options    */
  119. /*                include:                                            */
  120. /*                                                                    */
  121. /*                      Stripping off blind carbon copies             */
  122. /*                                                                    */
  123. /*                      Generating the UUCP From line differently     */
  124. /*--------------------------------------------------------------------*/
  125.  
  126. /*--------------------------------------------------------------------*/
  127. /*                        System include files                        */
  128. /*--------------------------------------------------------------------*/
  129.  
  130. #include <stdio.h>
  131. #include <ctype.h>
  132. #include <io.h>
  133. #include <stdlib.h>
  134. #include <string.h>
  135. #include <time.h>
  136. #include <signal.h>
  137.  
  138. #ifdef _Windows
  139. #include <windows.h>
  140. #endif
  141.  
  142. /*--------------------------------------------------------------------*/
  143. /*                     Application include files                      */
  144. /*--------------------------------------------------------------------*/
  145.  
  146. #include "lib.h"
  147. #include "address.h"
  148. #include "arpadate.h"
  149. #include "deliver.h"
  150. #include "getopt.h"
  151. #include "hlib.h"
  152. #include "hostable.h"
  153. #include "logger.h"
  154. #include "security.h"
  155. #include "usertabl.h"
  156. #include "timestmp.h"
  157. #include "catcher.h"
  158.  
  159. #ifdef _Windows
  160. #include "winutil.h"
  161. #endif
  162.  
  163. /*--------------------------------------------------------------------*/
  164. /*                           Local defines                            */
  165. /*--------------------------------------------------------------------*/
  166.  
  167. #define  MOPLEN      10          /* Length of formatted header lines */
  168. #define  UUCPFROM    "From "     /* Length of UUCP incoming mail     */
  169.  
  170. /*--------------------------------------------------------------------*/
  171. /*                   Prototypes for internal files                    */
  172. /*--------------------------------------------------------------------*/
  173.  
  174. static boolean CopyTemp( void );
  175.  
  176. static void ParseFrom( void );
  177.  
  178. static char **Parse822( boolean *header,
  179.                         size_t *count);
  180.  
  181. static void Terminate( const int rc);
  182.  
  183.  static void PutHead( const char *label,
  184.                       const char *operand,
  185.                       FILE *stream,
  186.                       const boolean resent);
  187.  
  188. static boolean DaemonMail( const char *subject,
  189.                            char **address,
  190.                            int count );
  191.  
  192.  
  193.  static void usage( void );
  194.  
  195. /*--------------------------------------------------------------------*/
  196. /*                          Global variables                          */
  197. /*--------------------------------------------------------------------*/
  198.  
  199.  currentfile();               /* Declare file name for checkref()    */
  200.  char *tempname = NULL;       /* Pointer to temporary input file     */
  201.  char *namein = CONSOLE;
  202.  FILE *datain = stdin;        /* Handle for reading input mail       */
  203.  FILE *dataout = NULL;        /* Handle for the output of mail       */
  204.  char fromuser[MAXADDR] = ""; /* User id of originator               */
  205.  char fromnode[MAXADDR] = ""; /* Node id of originator               */
  206.  char *now;                   /* Time stamp for Received: banner     */
  207.  char *myProgramName = NULL;  // Name for recursive invocation
  208.  
  209.  static char received[] = "Received:";
  210.  static char receivedlen = sizeof( received) - 1;
  211.  
  212. /*--------------------------------------------------------------------*/
  213. /*                            main program                            */
  214. /*--------------------------------------------------------------------*/
  215.  
  216. void main(int argc, char **argv)
  217. {
  218.    boolean ReadHeader = FALSE;   /* TRUE = Parse RFC-822 headers      */
  219.  
  220.    int  option;                  /* For parsing option list           */
  221.    char **address;               /* Pointer to list of target
  222.                                     addresses                         */
  223.    char *token;
  224.    size_t addressees;            /* Number of targets in address      */
  225.    size_t count;                 /* Loop variable for delivery        */
  226.    size_t delivered = 0;         /* Count of successfull deliveries   */
  227.    int user_debug  = -1;
  228.    boolean header = TRUE;
  229.    boolean DeleteInput = FALSE;
  230.  
  231.    boolean daemon = FALSE;
  232.  
  233.    char *subject = NULL;
  234.    myProgramName = newstr( argv[0] );   // Copy before banner() mangles it
  235.  
  236. /*--------------------------------------------------------------------*/
  237. /*    Make a copy of the Borland copyright for debugging purposes     */
  238. /*--------------------------------------------------------------------*/
  239.  
  240. #if defined(__CORE__)
  241.    copywrong = strdup(copyright);
  242.    checkref(copywrong);
  243. #endif
  244.  
  245.    logfile = stderr;             // Prevent redirection of error
  246.                                  // messages during configuration
  247.  
  248.    banner( argv);
  249.  
  250.    now = arpadate();          /* Set the current date                */
  251.    debuglevel =  0;
  252.  
  253. /*--------------------------------------------------------------------*/
  254. /* Load the UUPC/extended configuration file, and exit if any errors  */
  255. /*--------------------------------------------------------------------*/
  256.  
  257.    if (!configure(B_MTA))
  258.       Terminate(3);
  259.  
  260. /*--------------------------------------------------------------------*/
  261. /*                    Handle control-C interrupts                     */
  262. /*--------------------------------------------------------------------*/
  263.  
  264.     if( signal( SIGINT, ctrlchandler ) == SIG_ERR )
  265.     {
  266.         printmsg( 0, "Couldn't set SIGINT\n" );
  267.         panic();
  268.     }
  269.  
  270. /*--------------------------------------------------------------------*/
  271. /*                       Begin logging messages                       */
  272. /*--------------------------------------------------------------------*/
  273.  
  274.    openlog( NULL );
  275.  
  276. /*--------------------------------------------------------------------*/
  277. /*                      Parse our operand flags                       */
  278. /*--------------------------------------------------------------------*/
  279.  
  280.    while ((option = getopt(argc, argv, "ws:tF:f:x:")) != EOF)
  281.    {
  282.       switch (option) {
  283.       case 'w':
  284.          daemon = TRUE;
  285.          break;
  286.  
  287.       case 's':
  288.          subject = optarg;
  289.          daemon = TRUE;
  290.          break;
  291.  
  292.       case 't':
  293.          ReadHeader = TRUE;
  294.          break;
  295.  
  296.       case 'x':
  297.          user_debug = debuglevel = atoi(optarg);
  298.          break;
  299.  
  300.       case 'F':
  301.          DeleteInput = TRUE;
  302.       case 'f':
  303.          namein = optarg;
  304.          datain = FOPEN(namein , "r",TEXT_MODE);
  305.          break;
  306.  
  307.       case '?':
  308.          usage();
  309.          Terminate(4);
  310.       } /* switch */
  311.    } /* while */
  312.  
  313.    if ( debuglevel > 1 )
  314.    {
  315.       for ( count = 1; (int) count < argc; count ++)
  316.          printmsg(4,"rmail argv[%d] = \"%s\"", count, argv[count] );
  317.    } /* if ( debuglevel > 4 ) */
  318.  
  319.    if ((optind == argc) != ReadHeader)
  320.    {
  321.       puts("Missing/extra parameter(s) at end.");
  322.       Terminate(4);
  323.    }
  324.  
  325. #if defined(_Windows)
  326.    atexit( CloseEasyWin );               // Auto-close EasyWin on exit
  327. #endif
  328.  
  329.    remoteMail = ! (ReadHeader || daemon);
  330.                               /* If not reading headers, must be in
  331.                                  normal rmail mode ...               */
  332.  
  333. /*--------------------------------------------------------------------*/
  334. /*    If in local mode and the user doesn't want output, suppress     */
  335. /*    routine delivery messages                                       */
  336. /*--------------------------------------------------------------------*/
  337.  
  338.    if (( user_debug == -1 ) && (debuglevel == 0))
  339.    {
  340.       if (remoteMail)
  341.          debuglevel = 1;
  342.       else
  343.          debuglevel = (int) bflag[F_VERBOSE];
  344.    }
  345.  
  346. /*--------------------------------------------------------------------*/
  347. /*               Verify we have input stream available                */
  348. /*--------------------------------------------------------------------*/
  349.  
  350.    if (datain == NULL )
  351.    {
  352.       printerr(namein);
  353.       Terminate(6);
  354.    } /* if */
  355.  
  356. /*--------------------------------------------------------------------*/
  357. /*                   Open up the output data stream                   */
  358. /*--------------------------------------------------------------------*/
  359.  
  360.    tempname = mktempname( NULL , "TMP");
  361.    dataout = FOPEN(tempname, "w",TEXT_MODE);
  362.  
  363.    if (dataout == NULL)
  364.    {
  365.       printmsg(0,"Cannot open temporary file \"%s\" for output",
  366.             tempname);
  367.       Terminate(5);
  368.    } /* if */
  369.  
  370. /*--------------------------------------------------------------------*/
  371. /*   If in local mail mode, make up a list of addresses to mail to    */
  372. /*--------------------------------------------------------------------*/
  373.  
  374.    if ( daemon )
  375.    {
  376.       addressees = argc - optind;
  377.       address = &argv[optind];
  378.       DaemonMail( subject, address, addressees );
  379.       header = FALSE;
  380.    }
  381.    else if (ReadHeader)
  382.       address = Parse822( &header, &addressees );
  383.    else {
  384.       ParseFrom();               /* Copy remote header instead       */
  385.       addressees = argc - optind;
  386.       address = &argv[optind];
  387.    } /* if */
  388.  
  389.    if ( addressees == 0 )        /* Can we deliver mail?             */
  390.    {
  391.       printmsg(0, "No addressees to deliver to!");
  392.       Terminate( 2 );            /* No --> Execute punt formation    */
  393.    }
  394.  
  395. /*--------------------------------------------------------------------*/
  396. /*       Copy the rest of the input file into our holding tank        */
  397. /*--------------------------------------------------------------------*/
  398.  
  399.    header = CopyTemp( ) && header ;
  400.    if (header)                   /* Was the header ever terminated?  */
  401.    {
  402.       printmsg(0,"rmail: Improper header, adding trailing newline");
  403.       fputc('\n', dataout);      /* If not, it is now ...            */
  404.    }
  405.  
  406.    fclose(datain);
  407.    fclose(dataout);
  408.  
  409.    if (DeleteInput)              /* Make room for more data on disk  */
  410.       remove(namein);
  411.  
  412. /*--------------------------------------------------------------------*/
  413. /*        Determine requestor node and user id for remote mail        */
  414. /*--------------------------------------------------------------------*/
  415.  
  416.  
  417. /*--------------------------------------------------------------------*/
  418. /*                    Perform delivery of the mail                    */
  419. /*--------------------------------------------------------------------*/
  420.  
  421.    while ((token = strpbrk(tempname ,"/")) != NULL)
  422.       *token = '\\';
  423.  
  424.    for ( count = 0; count < addressees; count++)
  425.          if ( *address[count] == '-')
  426.             delivered ++;     /* Ignore option flags on delivery     */
  427.          else
  428.             delivered += Deliver(tempname, address[count], FALSE, TRUE);
  429.  
  430. /*--------------------------------------------------------------------*/
  431. /*                       Terminate the program                        */
  432. /*--------------------------------------------------------------------*/
  433.  
  434.    printmsg(8,"rmail: %d addressees, delivered to %d mailboxes",
  435.             addressees, delivered);
  436.  
  437.    if ( delivered >= addressees )
  438.       Terminate( 0 );         /* All mail delivered                  */
  439.    else if ( delivered == 0 )
  440.       Terminate( 2 );         /* No mail delivered                   */
  441.    else
  442.       Terminate (1 );         /* Some mail delivered                 */
  443.  
  444. } /* main */
  445.  
  446. /*--------------------------------------------------------------------*/
  447. /*    T e r m i n a t e                                               */
  448. /*                                                                    */
  449. /*    Cleanup open files and return to operating system               */
  450. /*--------------------------------------------------------------------*/
  451.  
  452. static void Terminate( const int rc)
  453. {
  454.    if (tempname != NULL)         /* Did temporary file get named?    */
  455.    {
  456.       if (datain != stdin)       /* Non-standard input?              */
  457.         fclose(stdin);           /* Yes --> Close it                 */
  458.       remove(tempname);          /* Purge temporary file, if exists  */
  459.    } /* if */
  460.  
  461.    exit( rc );                   /* Return to operating systems      */
  462. }  /* Terminate */
  463.  
  464. /*--------------------------------------------------------------------*/
  465. /*    P a r s e F r o m                                               */
  466. /*                                                                    */
  467. /*    Read the from address of incoming data from UUCP                */
  468. /*--------------------------------------------------------------------*/
  469.  
  470. static void ParseFrom()
  471. {
  472.    static char from[] = "From ";
  473.    static char remote[] = "remote from ";
  474.    static int  remotelen = sizeof remote - 1;
  475.    static int  fromlen = sizeof from - 1;
  476.    char *token;
  477.    char buf[BUFSIZ];
  478.    boolean hit;
  479.  
  480. /*--------------------------------------------------------------------*/
  481. /*                Use UUXQT Information, if available                 */
  482. /*--------------------------------------------------------------------*/
  483.  
  484.    token = getenv( UU_MACHINE );
  485.    if ( token == NULL )
  486.       *fromnode = '\0';
  487.    else {
  488.       strncpy( fromnode, token , sizeof fromnode );
  489.       fromnode[ sizeof fromnode - 1 ] = '\0';
  490.    }
  491.  
  492.    fgets(buf, BUFSIZ , datain);
  493.    hit = equaln(buf, from, fromlen );
  494.  
  495.    if (hit)
  496.    {
  497.       int nodelen = strlen( fromnode ) + 1; /* Plus ! */
  498.       char *s;
  499.       token = strtok( &buf[ fromlen ], " ");
  500.       s = strtok( NULL, "\n");
  501.  
  502.       if (strlen( token ) + nodelen >= MAXADDR)
  503.       {
  504.          char *next;
  505.          token = strtok( token, "!" );
  506.  
  507.          while ((next = strtok( NULL , "!")) != NULL )
  508.          {
  509.             token = next;
  510.             if (strlen( next ) + nodelen < MAXADDR)
  511.                break;
  512.          } /* while */
  513.       } /* if */
  514.  
  515.       strncpy(fromuser, token , sizeof fromuser );
  516.       fromuser[ sizeof fromuser - nodelen ] = '\0';
  517.  
  518.       if ( *fromnode == '\0')
  519.       {
  520.          while ( *s != '\0')
  521.          {
  522.             if equaln(s, remote, remotelen)
  523.                break;
  524.             else
  525.                s++;
  526.          } /* while */
  527.          strncpy( fromnode ,
  528.                 (*s == '\0') ? E_nodename : s + remotelen ,
  529.                  sizeof fromnode );
  530.          fromnode[ sizeof fromnode -1 ] = '\0';
  531.       } /* if ( *fromnode != '\0') */
  532.  
  533.    } /* if */
  534.    else {
  535.       if ( *fromnode == '\0')
  536.          strcpy(fromnode, E_nodename );
  537.       strcpy(fromuser, "/dev/null");
  538.    } /* else */
  539.  
  540. /*--------------------------------------------------------------------*/
  541. /*       Generate required "From " and "Received" header lines        */
  542. /*--------------------------------------------------------------------*/
  543.  
  544.    fprintf(dataout,"%-10s from %s by %s (%s %s) with UUCP;\n%-10s %s\n",
  545.             "Received:", fromnode, E_domain, compilep, compilev,
  546.             " ", now);
  547.  
  548. /*--------------------------------------------------------------------*/
  549. /*    If what we read wasn't a From line, write into the new file     */
  550. /*--------------------------------------------------------------------*/
  551.  
  552.    if (!hit)
  553.    {
  554.       fputs(buf, dataout);
  555.       if (ferror(dataout))
  556.       {
  557.          printerr(tempname);
  558.          Terminate(6);
  559.       } /* if */
  560.    } /* if */
  561.  
  562. /*--------------------------------------------------------------------*/
  563. /*              Determine the requestor user id and node              */
  564. /*--------------------------------------------------------------------*/
  565.  
  566.    token = getenv( UU_USER ); /* Get exactly what remote told us     */
  567.  
  568.    if ( token != NULL )
  569.    {                     /* Use exactly what remote told us     */
  570.       ruser = strtok( token , WHITESPACE );
  571.       rnode = strtok( NULL  , WHITESPACE );
  572.    } /* else */
  573.  
  574.    if ((rnode == NULL) || (strchr(rnode,'.') == NULL ))
  575.                               /* Did it tell us the domain?          */
  576.    {                          /* No --> Use from information         */
  577.       char node[MAXADDR];
  578.       char user[MAXADDR];
  579.  
  580.       sprintf(buf ,"%s!%s", fromnode, fromuser);
  581.       user_at_node(buf , buf, node, user);
  582.       ruser = newstr( user );
  583.       rnode = newstr( node );
  584.    }
  585.  
  586.    uuser = "uucp";            /* Effective id is always our daemon   */
  587.  
  588. }  /* ParseFrom */
  589.  
  590. /*--------------------------------------------------------------------*/
  591. /*    P a r s e 8 2 2                                                 */
  592. /*                                                                    */
  593. /*    Parse an RFC-822 header generated by that esteemed mail user    */
  594. /*    agent, UUPC/extended's MAIL.                                    */
  595. /*                                                                    */
  596. /*    Note that we parse the header in the format we KNOW that UUPC   */
  597. /*    generated it in:  "To:", "Cc:", "Bcc:", optionally prefixed     */
  598. /*    by "Resent-".  We also know that mail comes in one address      */
  599. /*    per line, and that the Resent- headers, if any, precede the     */
  600. /*    original headers.                                               */
  601. /*--------------------------------------------------------------------*/
  602.  
  603. static char **Parse822( boolean *header,
  604.                         size_t *count)
  605. {
  606.  
  607. /*--------------------------------------------------------------------*/
  608. /*  Define the headers we will be examining and variables for their   */
  609. /*                              lengths                               */
  610. /*--------------------------------------------------------------------*/
  611.  
  612.    static char *to     = "Resent-To:";
  613.    static char *cc     = "Resent-Cc:";
  614.    static char *bcc    = "Resent-Bcc:";
  615.    static char *resent = "Resent-";
  616.    static char *from   = "Resent-From:";
  617.  
  618.    size_t tolen;
  619.    size_t cclen;
  620.    size_t bcclen;
  621.    size_t resentlen =  strlen(resent);
  622.    size_t offset = resentlen; /* Subscript for examining headers,
  623.                                  which allows us to ignore Resent-   */
  624.    size_t fromlen =  strlen( &from[offset] );
  625.    size_t allocated = 5;      /* Reasonable first size for address   */
  626.                               /* Note: MUST BE AT LEAST 2 because we
  627.                                        add 50% below!                */
  628.    boolean blind = FALSE;
  629.  
  630.    char **addrlist = calloc( sizeof *addrlist , allocated);
  631.    char buf[BUFSIZ];          /* Input buffer for reading header     */
  632.    char address[MAXADDR];     /* Buffer for parsed address           */
  633.    char path[MAXADDR];
  634.    char *token;               /* For parsing line in buf             */
  635.    struct HostTable *hostp;
  636.  
  637. /*--------------------------------------------------------------------*/
  638. /*                          Begin processing                          */
  639. /*--------------------------------------------------------------------*/
  640.  
  641.    *count = 0;                /* No addresses discovered yet         */
  642.    checkref(addrlist);        /* Verify we had room for the list     */
  643.  
  644.    fprintf(dataout,"%-10s by %s (%s %s);\n%-10s %s\n",
  645.               "Received:",E_domain,compilep, compilev,
  646.               " ", now );
  647.  
  648. /*--------------------------------------------------------------------*/
  649. /*                        Find the From: line                         */
  650. /*--------------------------------------------------------------------*/
  651.  
  652.    do {
  653.       if (fgets( buf, BUFSIZ, datain) == NULL)  /* End of file?      */
  654.          return NULL;         /* Yes --> Very bad, report error      */
  655.       fputs(buf, dataout );
  656.       if (*buf == '\n')       /* End of the header?                  */
  657.          return NULL;         /* Yes --> Very bad, report error      */
  658.       else if (equalni(resent, buf, resentlen))
  659.       {
  660.          offset = 0;
  661.          fromlen = strlen(&from[offset]);
  662.       } /* if */
  663.       else if (equalni(received, buf, receivedlen))
  664.          hops++;
  665.    } while (!equalni(&from[offset], buf, fromlen));
  666.  
  667.    strtok( buf , WHITESPACE);    /* Drop the leading token           */
  668.    token = strtok( NULL, "\n");  /* Get the token with From: addr    */
  669.    ExtractAddress( address, token, FALSE );
  670.                                  /* Get the From: address itself     */
  671.    user_at_node(address, path, fromnode, fromuser);
  672.                                  /* Separate portions of the address */
  673.  
  674. /*--------------------------------------------------------------------*/
  675. /*               Generate a Sender: line if we need it                */
  676. /*--------------------------------------------------------------------*/
  677.  
  678.    if (equal(fromnode,HostAlias(E_fdomain))) /* Same as hidden site? */
  679.       strcpy(fromnode, E_nodename);/* Yes --> Declare as local system  */
  680.  
  681.    hostp = checkname( fromnode );   /* Look up real system name      */
  682.  
  683.    if (!equal(fromuser,E_mailbox) ||
  684.        (hostp == BADHOST) || (hostp->hstatus != localhost))
  685.    {
  686.       sprintf(buf, "%s <%s@%s>", E_name, E_mailbox, E_fdomain );
  687.       PutHead("Sender:", buf, dataout , offset == 0 );
  688.    } /* if */
  689.  
  690. /*--------------------------------------------------------------------*/
  691. /*      Set UUCP requestor name while we've got the information       */
  692. /*--------------------------------------------------------------------*/
  693.  
  694.    if ((hostp != BADHOST) && (hostp->hstatus == localhost))
  695.       rnode = bflag[F_BANG] ? E_nodename : E_fdomain;
  696.                               /* Use full domain address, if possible */
  697.    else
  698.       rnode = fromnode;
  699.  
  700.    uuser = ruser = fromuser;  /* User and requestor always the same
  701.                                  for locally generated mail          */
  702.  
  703. /*--------------------------------------------------------------------*/
  704. /*                       Generate a message-id                        */
  705. /*--------------------------------------------------------------------*/
  706.  
  707.    sprintf(buf, "<%lx.%s@%s>", time( NULL ) , E_nodename, E_domain);
  708.    PutHead("Message-ID:", buf, dataout , offset == 0 );
  709.    PutHead(NULL, NULL, dataout , FALSE );
  710.  
  711. /*--------------------------------------------------------------------*/
  712. /*                 Locate the To: or Resent-To: line                  */
  713. /*--------------------------------------------------------------------*/
  714.  
  715.    tolen =    strlen( &to[offset] );
  716.  
  717.    do {
  718.       if (fgets( buf, BUFSIZ, datain ) == NULL)  /* End of file?     */
  719.          return NULL;         /* Yes --> Very bad, report error      */
  720.       fputs(buf, dataout );
  721.       if (*buf == '\n')       /* End of the header?                  */
  722.          return NULL;         /* Yes --> Very bad, report error      */
  723.       else if (equalni(received, buf, receivedlen))
  724.          hops++;
  725.    } while ( !equalni(&to[offset] , buf , tolen ));
  726.  
  727.    token = strpbrk( buf ," \t");
  728.  
  729. /*--------------------------------------------------------------------*/
  730. /*                Proccess the rest of the addressees                 */
  731. /*--------------------------------------------------------------------*/
  732.  
  733.    cclen =    strlen( &cc[offset] );
  734.    bcclen =   strlen( &bcc[offset] );
  735.  
  736.    do {
  737.       if (allocated == (*count+1))  /* Do we have room for addr?     */
  738.       {
  739.          allocated += allocated / 2;   /* Choose larger array size   */
  740.          addrlist = realloc( addrlist ,
  741.                              allocated * sizeof( *addrlist ));
  742.          checkref(addrlist);  /* Verify the allocation worked        */
  743.       } /* if */
  744.  
  745.       ExtractAddress( address, token, FALSE );  /* Get address itself*/
  746.       if (!strlen(address))
  747.       {
  748.          printmsg(0,"Could not locate expected address in header");
  749.          *count = 0;
  750.          return NULL;
  751.       } /* if */
  752.       else {
  753.          addrlist[*count] = newstr( address );
  754.                               /* Save permanent copy of address      */
  755.          checkref( addrlist[*count] ); /* Verify strdup worked       */
  756.          printmsg(4,"address[%d]= \"%s\"",*count, address);
  757.          *count += 1;         /* Flag we got the address             */
  758.       } /* else */
  759.  
  760.       if (fgets( buf, BUFSIZ, datain ) == NULL) /* End of file?      */
  761.          token = NULL;        /* Yes --> Odd, but no major problem   */
  762.       else if (*buf == '\n')  /* End of the header?                  */
  763.       {
  764.          token = NULL;        /* Yes --> Exit loop                   */
  765.          *header = FALSE;     /* Report to caller the header is done */
  766.          blind = FALSE;       /* Denote not a blind header           */
  767.       }
  768.       else if (isspace(*buf)) /* Another address?                    */
  769.          token = buf;         /* Yes --> Write it out                */
  770.       else {                  /* No --> Determine what next header is*/
  771.          blind = FALSE;       /* Assume not a blind header           */
  772.          if (equalni(&cc[offset], buf, cclen))   /* Cc: header?       */
  773.             token = strpbrk(buf," \t");
  774.          else if (equalni(&bcc[offset], buf, bcclen))  /* Bcc: header?*/
  775.          {
  776.             token = strpbrk(buf ," \t");
  777.             blind = TRUE;
  778.          } /* if */
  779.          else                 /* Unsupported header, exit loop       */
  780.             token = NULL;
  781.       } /* else */
  782.       if ( ! blind )
  783.          fputs(buf, dataout );
  784.    } while (token != NULL );
  785.  
  786. /*--------------------------------------------------------------------*/
  787. /*                   Return address list to caller                    */
  788. /*--------------------------------------------------------------------*/
  789.  
  790.    return addrlist;
  791.  
  792. } /* Parse822 */
  793.  
  794. /*--------------------------------------------------------------------*/
  795. /*    C o p y T e m p                                                 */
  796. /*                                                                    */
  797. /*    Copy the un-parsed parts of a message into the holding file     */
  798. /*--------------------------------------------------------------------*/
  799.  
  800. static boolean CopyTemp( void )
  801. {
  802.    boolean header = TRUE;
  803.    char buf[BUFSIZ];
  804.    boolean newline = TRUE;
  805.  
  806.    while (fgets(buf, BUFSIZ, datain) != NULL)
  807.    {
  808.       if (header)
  809.       {
  810.          if (*buf == '\n')
  811.             header = FALSE;
  812.          else if (equalni(received, buf, receivedlen))
  813.             hops++;
  814.       }
  815.  
  816.       newline = buf[ strlen( buf ) - 1 ] == '\n';
  817.  
  818.       if (fputs(buf, dataout) == EOF)  /* I/O error?                 */
  819.       {
  820.          printerr(tempname);
  821.          printmsg(0,"I/O error on \"%s\"", tempname);
  822.          fclose(dataout);
  823.          return FALSE;
  824.       } /* if */
  825.    } /* while */
  826.  
  827.    if (ferror(datain))        /* Clean end of file on input?         */
  828.    {
  829.       printerr(namein);
  830.       Terminate(7);
  831.    }
  832.  
  833.    if ( !newline )            /* Is the file terminated properly?    */
  834.    {
  835.       printmsg(0, "rmail: Improperly formed message, adding final newline!");
  836.       fputc( '\n', dataout );
  837.    }
  838.  
  839.    return header;
  840. }  /* CopyTemp */
  841.  
  842. /*--------------------------------------------------------------------*/
  843. /*    D a e m o n M a i l                                             */
  844. /*                                                                    */
  845. /*    Send text in a mailbag file to address(es) specified by address */
  846. /*--------------------------------------------------------------------*/
  847.  
  848. static boolean DaemonMail( const char *subject,
  849.                           char **address,
  850.                           int count )
  851. {
  852.    char buf[BUFSIZ];
  853.    char *logname;
  854.    char *token;
  855.    char *moi = NULL;
  856.    struct UserTable *userp;
  857.    char *header = "To:";
  858.    char *cc     = "Cc:";
  859.    boolean print = TRUE;
  860.  
  861. /*--------------------------------------------------------------------*/
  862. /*                         Validate the input                         */
  863. /*--------------------------------------------------------------------*/
  864.  
  865.    if ( count == 0 )
  866.    {
  867.       printmsg(0,"rmail: No addresseses to deliver to!");
  868.       return FALSE;
  869.    }
  870.  
  871. /*--------------------------------------------------------------------*/
  872. /*                       Determine our user id                        */
  873. /*--------------------------------------------------------------------*/
  874.  
  875.    logname = getenv( LOGNAME );
  876.    if ( logname == NULL )
  877.       logname = E_mailbox;
  878.  
  879. /*--------------------------------------------------------------------*/
  880. /*              Get the name of the user, or make one up              */
  881. /*--------------------------------------------------------------------*/
  882.  
  883.    userp = checkuser(logname);   /* Locate user id in host table     */
  884.  
  885.    if ( (userp != BADUSER) &&
  886.         (userp->realname != NULL) &&
  887.          !equal(userp->realname, EMPTY_GCOS ))
  888.       moi = userp->realname;
  889.    else if ( equali(logname, E_postmaster) || equali(logname, POSTMASTER))
  890.       moi = "Postmaster";
  891.    else if ( equali( logname, "uucp" ))
  892.       moi = "Unix to Unix Copy";
  893.    else
  894.       moi = logname;          /* Dummy to ease formatting From: line  */
  895.  
  896. /*--------------------------------------------------------------------*/
  897. /*    Add the boilerplate the front:                                  */
  898. /*                                                                    */
  899. /*       Date, From, Organization, and Reply-To                       */
  900. /*--------------------------------------------------------------------*/
  901.  
  902.    fprintf(dataout,"%-10s by %s (%s %s);\n%-10s %s\n",
  903.               "Received:",E_domain,compilep, compilev,
  904.               " ", now );
  905.  
  906. /*--------------------------------------------------------------------*/
  907. /*                       Generate a message-id                        */
  908. /*--------------------------------------------------------------------*/
  909.  
  910.    sprintf(buf, "<%lx.%s@%s>", time( NULL ) , E_nodename, E_domain);
  911.    PutHead("Message-ID:", buf, dataout , FALSE );
  912.    PutHead(NULL, NULL, dataout , FALSE );
  913.  
  914.    PutHead("Date:", arpadate() , dataout, FALSE);
  915.  
  916.    if (bflag[F_BANG])
  917.       sprintf(buf, "(%s) %s!%s", moi, E_nodename, logname );
  918.    else {
  919.       checkname( E_nodename );  /* Force loading of the E_fdomain name */
  920.       sprintf(buf, "\"%s\" <%s@%s>", moi, logname , E_fdomain );
  921.    }
  922.  
  923.    PutHead("From:", buf, dataout, FALSE );
  924.  
  925.    if (E_organization != NULL )
  926.       PutHead("Organization:", E_organization, dataout, FALSE);
  927.  
  928. /*--------------------------------------------------------------------*/
  929. /*                      Write the address out                         */
  930. /*--------------------------------------------------------------------*/
  931.  
  932.    while( (count-- > 0) && print )
  933.    {
  934.       token = *address++;
  935.       if ( *token == '-')  /* Option flag?                        */
  936.       {
  937.          if (token[1] == 'c')
  938.          {
  939.             header = cc;
  940.             cc = "";
  941.          }
  942.          else if (token[1] == 'b')
  943.             print = FALSE;
  944.          else
  945.             printmsg(0,"rmail: Invalid flag \"%s\" ignored!", token);
  946.       } /* if ( token == '-') */
  947.       else if ( print )
  948.       {
  949.          if (strpbrk(token,"!@") == nil(char))
  950.          {
  951.             if (bflag[F_BANG])
  952.                sprintf(buf, "%s!%s", E_nodename, token );
  953.             else
  954.                sprintf(buf, "%s@%s", token , E_fdomain );
  955.             token = buf;
  956.          }
  957.  
  958.          PutHead(header , token, dataout, FALSE);
  959.          header = "";         /* Continue same field by default      */
  960.       }
  961.    } /* while( (count-- > 0) && print ) */
  962.  
  963. /*--------------------------------------------------------------------*/
  964. /*                     Handle the subject, if any                     */
  965. /*--------------------------------------------------------------------*/
  966.  
  967.    if (subject != NULL)
  968.       PutHead("Subject:", subject, dataout, FALSE);
  969.  
  970.    PutHead(NULL, "", dataout, FALSE);  /* Terminate the header line   */
  971.    PutHead(NULL, "", dataout, FALSE);  /* Terminate the header file   */
  972.  
  973. /*--------------------------------------------------------------------*/
  974. /*                          Return to caller                          */
  975. /*--------------------------------------------------------------------*/
  976.  
  977.    uuser = ruser = strncpy(fromuser, logname, sizeof fromuser);
  978.                               /* Define user for UUCP From line      */
  979.    fromuser[ sizeof fromuser - 1 ] = '\0';
  980.    rnode = bflag[F_BANG] ? E_nodename : E_fdomain;
  981.                               /* Use full domain address, if possible */
  982.  
  983.    strcpy(fromnode, E_nodename);/* Declare as local system           */
  984.    return TRUE;
  985.  
  986. } /*DaemonMail*/
  987.  
  988. /*--------------------------------------------------------------------*/
  989. /*    P u t H e a d                                                   */
  990. /*                                                                    */
  991. /*    Write one line of an RFC-822 header                             */
  992. /*--------------------------------------------------------------------*/
  993.  
  994.  static void PutHead( const char *label,
  995.                       const char *operand,
  996.                       FILE *stream,
  997.                       const boolean resent)
  998.  {
  999.    static boolean terminate = TRUE;
  1000.  
  1001.    if (label == NULL )        /* Terminate call?                     */
  1002.    {                          /* Yes --> Reset Flag and return       */
  1003.       fputc('\n', stream);    /* Terminate the current line          */
  1004.       terminate = TRUE;
  1005.       return;
  1006.    } /* if */
  1007.  
  1008.    if (strlen(label))         /* First line of a header?             */
  1009.    {
  1010.       if (!terminate)         /* Terminate previous line?            */
  1011.          fputc('\n', stream);
  1012.  
  1013.       if (resent)
  1014.          fprintf(stream,"Resent-%s %s",label, operand);
  1015.       else
  1016.          fprintf(stream,"%-10s %s",label, operand);
  1017.       terminate = FALSE;          /* Flag that we did not end file   */
  1018.    } /* if */
  1019.    else                       /* Continuing line                     */
  1020.       fprintf(stream,",\n%-10s %s",label, operand);
  1021.  } /* PutHead */
  1022.  
  1023. /*--------------------------------------------------------------------*/
  1024. /*    u s a g e                                                       */
  1025. /*                                                                    */
  1026. /*    Report how the program works                                    */
  1027. /*--------------------------------------------------------------------*/
  1028.  
  1029.  static void usage( void )
  1030.  {
  1031.  
  1032.    static char syntax[] =
  1033.       "Usage:\tRMAIL\t-t [-x debug] [-f | -F file]\n"
  1034.       "\t\t-w [-x debug] [-f | -F file] [-s subject] addr1 [-c] addr2  [-b] addr3 ...\n"
  1035.       "\t\t[-x debug] [-f | -F file] addr1 addr2 addr3 ...\n";
  1036.  
  1037.    puts( syntax );
  1038.    exit(99);
  1039.  }
  1040.