home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / EXTRAS / UUCODE / UUPC / TEST / UPC12ES3.ZIP / MAIL / rmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-13  |  42.9 KB  |  1,093 lines

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