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

  1. /*--------------------------------------------------------------------*/
  2. /*    d e l i v e r  . c                                              */
  3. /*                                                                    */
  4. /*    UUPC/extended mail delivery subroutines                         */
  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: deliver.c 1.18 1993/11/13 17:43:26 ahd Exp $
  21.  *
  22.  *    $Log: deliver.c $
  23.  * Revision 1.18  1993/11/13  17:43:26  ahd
  24.  * Add call grading support
  25.  * Add suppressfrom, shortfrom options
  26.  *
  27.  * Revision 1.17  1993/10/12  01:30:23  ahd
  28.  * Normalize comments to PL/I style
  29.  *
  30.  * Revision 1.16  1993/09/23  03:26:51  ahd
  31.  * Alter bounce message for "no path to host" error
  32.  *
  33.  * Revision 1.15  1993/09/20  04:41:54  ahd
  34.  * OS/2 2.x support
  35.  *
  36.  * Revision 1.14  1993/08/02  03:24:59  ahd
  37.  * Further changes in support of Robert Denny's Windows 3.x support
  38.  *
  39.  * Revision 1.13  1993/07/31  16:26:01  ahd
  40.  * Changes in support of Robert Denny's Windows support
  41.  *
  42.  * Revision 1.12  1993/06/21  02:17:31  ahd
  43.  * Correct errors in mail routing via HOSTPATH
  44.  *
  45.  * Revision 1.11  1993/06/13  14:06:00  ahd
  46.  * Save invoked program name and use it for recursive calls
  47.  * Loosen up bounced mail copy loop to avoid NT crashes
  48.  *
  49.  * Revision 1.10  1993/05/30  00:01:47  ahd
  50.  * Expand path of system alias files to allow userid references
  51.  *
  52.  * Revision 1.9  1993/05/06  03:41:48  ahd
  53.  * Don't rebounce mail to the postmaster
  54.  * Change directories as needed to provide reasonable default drives
  55.  * Do not use possibly invalid home directory to push directory on
  56.  * system aliases
  57.  *
  58.  * Revision 1.8  1993/05/03  02:41:57  ahd
  59.  * Make deliver not rebounce mail to the postmonstor
  60.  *
  61.  * Revision 1.7  1993/04/16  12:55:36  dmwatt
  62.  * Windows/NT sound support
  63.  *
  64.  * Revision 1.6  1993/04/15  03:17:21  ahd
  65.  * Basic bounce support
  66.  *
  67.  * Revision 1.5  1993/04/11  00:33:05  ahd
  68.  * Global edits for year, TEXT, etc.
  69.  *
  70.  * Revision 1.4  1992/12/18  13:05:18  ahd
  71.  * Use one token on request line for UUCP
  72.  *
  73.  * Revision 1.3  1992/12/05  23:38:43  ahd
  74.  * Skip blanks as well as unprintable characters
  75.  *
  76.  * Revision 1.2  1992/12/04  01:00:27  ahd
  77.  * Add system alias support
  78.  *
  79.  */
  80.  
  81. /*--------------------------------------------------------------------*/
  82. /*    Embedded Japanese support provided by Kenji Rikitake            */
  83. /*    28-AUG-1991                                                     */
  84. /*                                                                    */
  85. /*    On Japanese support:                                            */
  86. /*                                                                    */
  87. /*    Japanese MS-DOS uses a 2byte Kanji (Japanese ideogram) code     */
  88. /*    called "Shift-JIS".  This cannot be delivered via SMTP since    */
  89. /*    Shift-JIS maps its first byte from 0x80-0x9f and 0xe0-0xfc.     */
  90. /*    JUNET requests all hosts to send Kanji in a 7bit subset of      */
  91. /*    ISO2022.  This is commonly called "JIS 7bit".                   */
  92. /*                                                                    */
  93. /*    To provide Japanese functionality, you need to convert all      */
  94. /*    remote delivery messages to JIS 7bit, and all local delivery    */
  95. /*    messages to Shift-JIS.                                          */
  96. /*--------------------------------------------------------------------*/
  97.  
  98. #define INCLUDE ":include:"
  99.  
  100. /*--------------------------------------------------------------------*/
  101. /*                        System include files                        */
  102. /*--------------------------------------------------------------------*/
  103.  
  104. #include <stdio.h>
  105. #include <stdlib.h>
  106. #include <io.h>
  107. #include <ctype.h>
  108. #include <sys/types.h>
  109. #include <string.h>
  110. #include <process.h>
  111. #include <limits.h>
  112. #include <time.h>
  113.  
  114. /*--------------------------------------------------------------------*/
  115. /*                    UUPC/extended include files                     */
  116. /*--------------------------------------------------------------------*/
  117.  
  118. #include "lib.h"
  119. #include "address.h"
  120. #include "deliver.h"
  121. #include "expath.h"
  122. #include "execute.h"
  123. #include "getseq.h"
  124. #include "kanjicnv.h"
  125. #include "hlib.h"
  126. #include "hostable.h"
  127. #include "import.h"
  128. #include "pushpop.h"
  129. #include "security.h"
  130. #include "stater.h"
  131. #include "usertabl.h"
  132. #include "sysalias.h"
  133. #include "timestmp.h"
  134. #include "trumpet.h"
  135.  
  136. /*--------------------------------------------------------------------*/
  137. /*        Define current file name for panic() and printerr()         */
  138. /*--------------------------------------------------------------------*/
  139.  
  140. currentfile();
  141.  
  142. /*--------------------------------------------------------------------*/
  143. /*                        Internal prototypes                         */
  144. /*--------------------------------------------------------------------*/
  145.  
  146. static size_t DeliverLocal( const char *input,  /* Input file name    */
  147.                           char *user,     /* Target address           */
  148.                           const boolean sysalias,
  149.                                              /* Already sys alias     */
  150.                           boolean validate); /* Validate/forward
  151.                                                 local mail            */
  152.  
  153. static int DeliverFile( const char *input,
  154.                         const char *mboxname,
  155.                         const long start,
  156.                         const long end,
  157.                         boolean *announce,
  158.                         struct UserTable *userp,
  159.                         const boolean sysalias,  /* Already sys alias */
  160.                         const boolean validate,
  161.                         const char *user );
  162.  
  163. static size_t DeliverRemote( const char *input, /* Input file name    */
  164.                              const char *address,  /* Target address  */
  165.                              const char *path);
  166.  
  167. static size_t DeliverGateway(   const char *input,
  168.                                 const char *user,
  169.                                 const char *node,
  170.                                 const struct HostTable *hostp,
  171.                                 const boolean validate );
  172.  
  173. static int CopyData(   const boolean remotedelivery,
  174.                        const char *input,
  175.                        FILE *mbox);
  176.  
  177. static char *stats( const char *fname );
  178.  
  179. size_t Bounce( const char *input,
  180.                const char *text,
  181.                const char *data,
  182.                const char *address,
  183.                const boolean validate );
  184.  
  185. /*--------------------------------------------------------------------*/
  186. /*   Global (set by rmail.c) for number of hops this mail has seen    */
  187. /*--------------------------------------------------------------------*/
  188.  
  189.  KEWSHORT hops = 0;
  190.  
  191.  boolean remoteMail = FALSE;
  192.  
  193.  char *ruser = NULL;
  194.  char *rnode = NULL;
  195.  char *uuser = NULL;
  196.  
  197. /*--------------------------------------------------------------------*/
  198. /*    D e l i v e r                                                   */
  199. /*                                                                    */
  200. /*    Deliver mail to one user                                        */
  201. /*--------------------------------------------------------------------*/
  202.  
  203. size_t Deliver(       const char *input,    /* Input file name        */
  204.                             char *address,  /* Target address          */
  205.                       const boolean sysalias,  /* Already sys alias    */
  206.                           boolean validate)  /* Validate/forward
  207.                                                 local mail            */
  208. {
  209.    char node[MAXADDR];
  210.    char path[MAXADDR];
  211.    char user[MAXADDR];
  212.    char *token;
  213.    struct HostTable *hostp;
  214.  
  215.    if ( strlen( address ) >= MAXADDR )
  216.       return Bounce( input,
  217.                      "Excessive address length",
  218.                      address,
  219.                      address,
  220.                      validate );
  221.  
  222.    user_at_node(address, path, node, user);
  223.  
  224. /*--------------------------------------------------------------------*/
  225. /*                       Handle local delivery                        */
  226. /*--------------------------------------------------------------------*/
  227.  
  228.    if (equal(path, E_nodename)) /* Local node?                        */
  229.    {
  230.       struct HostTable *hostx = checkname( node );
  231.       if (hostx->hstatus == localhost)  /* Really the local node?     */
  232.          return DeliverLocal( input, user, sysalias, validate );
  233.                                  /* Yes!                              */
  234.       else
  235.          return Bounce( input,
  236.                  "No known delivery path for host",
  237.                   address,
  238.                   address,
  239.                   validate );
  240.    }  /* if */
  241.  
  242. /*--------------------------------------------------------------------*/
  243. /*                    Do we need loop protection?                     */
  244. /*--------------------------------------------------------------------*/
  245.  
  246.    if (hops > E_maxhops)
  247.       return Bounce(input,
  248.              "Excessive number of hops",
  249.              address,
  250.              address,
  251.              validate );
  252.  
  253. /*--------------------------------------------------------------------*/
  254. /*                   Deliver to a gateway if needed                   */
  255. /*--------------------------------------------------------------------*/
  256.  
  257.    hostp = checkname( path );
  258.    if ( (hostp != BADHOST) && (hostp->hstatus == gatewayed))
  259.       return DeliverGateway( input, user, node, hostp, validate );
  260.  
  261. /*--------------------------------------------------------------------*/
  262. /*         Deliver mail to a system directory connected to us         */
  263. /*--------------------------------------------------------------------*/
  264.  
  265.    if (equal(path,node))   /* Directly connected system?          */
  266.       return DeliverRemote( input, user, path); /* Yes            */
  267.  
  268. /*--------------------------------------------------------------------*/
  269. /*   Default delivery; strip any this node and the directly           */
  270. /*   connected system from the address, then deliver to the next      */
  271. /*   hop on the route                                                 */
  272. /*--------------------------------------------------------------------*/
  273.  
  274.    strcpy(node,address);
  275.    token = strtok(node,"!");  /* Get first host in path        */
  276.    if (equal( HostAlias(token), E_nodename)) /* Local system?  */
  277.    {
  278.       token =  strtok(NULL,"");  /* Yes --> Get rest of addr   */
  279.       strcpy(address, token);    /* Use it for address         */
  280.       token = strtok(token,"!"); /* Get next host in path      */
  281.    } /* if */
  282.  
  283.    if (equal( HostAlias(token), path ))  /* Next system?       */
  284.    {
  285.       token =  strtok(NULL,"");  /* Yes --> Get rest of addr   */
  286.       strcpy(address, token);    /* Use it for address         */
  287.    } /* if */
  288.  
  289.    if (!strpbrk(address,"!@"))   /* Any host delimiters?       */
  290.    {                             /* No --> Check for % routing */
  291.       token = strrchr(address,'%'); /* Get last percent sign   */
  292.       if (token != NULL)
  293.          *token = '@';           /* Make it an RFC-822 address */
  294.       else
  295.          printmsg(0,"Deliver: Cannot find node in \"%s\"",
  296.                address);         /* That's odd, it should not  */
  297.                                  /* be a local address!        */
  298.    } /* if */
  299.  
  300.    return DeliverRemote( input, address, path );
  301.  
  302. } /* Deliver */
  303.  
  304. /*--------------------------------------------------------------------*/
  305. /*    D e l i v e r L o c a l                                         */
  306. /*                                                                    */
  307. /*    Handle local delivery, including optional forwarding            */
  308. /*--------------------------------------------------------------------*/
  309.  
  310. static size_t DeliverLocal( const char *input,
  311.                                           /* Input file name          */
  312.                           char *user,     /* Target address           */
  313.                           const boolean sysalias,
  314.                                           /* Already sys alias     */
  315.                           boolean validate)  /* TRUE = validate,
  316.                                                 forward user's mail   */
  317. {
  318.    char mboxname[FILENAME_MAX];
  319.    struct UserTable *userp = NULL;
  320.    ALIASTABLE *aliasp = NULL;
  321.    int delivered = 0;
  322.    boolean announce = FALSE;
  323.    FILE *mbox;
  324.  
  325. /*--------------------------------------------------------------------*/
  326. /*    If the parameter is the postmaster, use the configuration       */
  327. /*    defined value for the postmaster                                */
  328. /*--------------------------------------------------------------------*/
  329.  
  330.    if (equali(user, POSTMASTER))
  331.       user = E_postmaster;
  332.  
  333. /*--------------------------------------------------------------------*/
  334. /*             Validate user id and check for forwarding              */
  335. /*--------------------------------------------------------------------*/
  336.  
  337.    if (validate)
  338.    {
  339.       validate = strcmp( E_postmaster , user);
  340.                                  /* Don't loop delivering to postmast*/
  341.  
  342.       userp = checkuser(user);   /* Locate user id in host table      */
  343.  
  344. /*--------------------------------------------------------------------*/
  345. /*                     Process any system aliases                     */
  346. /*--------------------------------------------------------------------*/
  347.  
  348.       if ( ! sysalias )
  349.       {
  350.          aliasp = checkalias( user );  /* System alias?             */
  351.  
  352.          if ( aliasp != NULL )
  353.          {
  354.             delivered += DeliverFile( input,
  355.                                       SysAliases,
  356.                                       aliasp->start,
  357.                                       aliasp->end,
  358.                                       &announce ,
  359.                                       userp,
  360.                                       TRUE,
  361.                                       validate,
  362.                                       user );
  363.  
  364.             if ( announce && ( userp != BADUSER ) && remoteMail )
  365.                trumpet( userp->beep);  /* Yes --> Inform the user     */
  366.             return delivered;
  367.  
  368.          } /* if */
  369.       } /* if */
  370.  
  371. /*--------------------------------------------------------------------*/
  372. /*             No system alias, verify the user is valid              */
  373. /*--------------------------------------------------------------------*/
  374.  
  375.       if ( userp == BADUSER )    /* Invalid user id?                  */
  376.       {                          /* Yes --> Dump in trash bin         */
  377.          return Bounce( input,
  378.                         "Invalid local address (not defined in PASSWD or ALIASES)",
  379.                         user,
  380.                         user,
  381.                         validate );
  382.       } /* if */
  383.  
  384. /*--------------------------------------------------------------------*/
  385. /*               The user id validated; handle the mail               */
  386. /*--------------------------------------------------------------------*/
  387.  
  388.       mkfilename(mboxname, userp->homedir, DOTFORWARD);
  389.  
  390.       if (access( mboxname, 0 )) /* The .forward file exists?         */
  391.          announce = TRUE;        /* No --> Fall through               */
  392.       else {
  393.          delivered += DeliverFile( input,
  394.                                    mboxname,
  395.                                    0,
  396.                                    LONG_MAX,
  397.                                    &announce,
  398.                                    userp,
  399.                                    FALSE,
  400.                                    validate,
  401.                                    user );
  402.  
  403.          if (announce && remoteMail)   /* Did we deliver mail locally? */
  404.             trumpet( userp->beep);     /* Yes --> Inform the user      */
  405.          return delivered;
  406.  
  407.       } /* if */
  408.  
  409.    } /* if (validate) */
  410.  
  411. /*--------------------------------------------------------------------*/
  412. /*       The user is valid (or not validated) and not forwarded       */
  413. /*--------------------------------------------------------------------*/
  414.  
  415.    if ((*user == '/') || (isalpha( *user ) && user[1] == ':'))
  416.                               /* Absolute path from recursive call?   */
  417.       strcpy(mboxname, user); /* Yes --> Use it as-is                 */
  418.    else
  419.       mkmailbox(mboxname, user);
  420.                               /* No --> Build normal name             */
  421.  
  422.    printmsg(1,"Delivering mail %sfrom %s%s%s to %s",
  423.                         stats( input ),
  424.                         ruser,
  425.                         remoteMail ? "@" : "",
  426.                         remoteMail ? rnode : "",
  427.                          user );
  428.  
  429.    if ( announce && remoteMail )
  430.       trumpet( userp->beep);  /* Local delivery, inform the user      */
  431.  
  432.    mbox = FOPEN( mboxname , "a",TEXT_MODE );
  433.    if (mbox == NULL )
  434.    {
  435.       printerr(mboxname);
  436.       printmsg(0,"Cannot open mailbox \"%s\" for output",
  437.                   mboxname);
  438.       panic();
  439.    }
  440.  
  441.    if (!isatty(fileno(mbox)))
  442.       fputs(MESSAGESEP,mbox); /* Write separator line                 */
  443.  
  444.    return CopyData( FALSE, input , mbox );
  445.  
  446. } /* DeliverLocal */
  447.  
  448. /*--------------------------------------------------------------------*/
  449. /*       D e l i v e r F i l e                                        */
  450. /*                                                                    */
  451. /*       Process a local or system aliases file                       */
  452. /*--------------------------------------------------------------------*/
  453.  
  454. static int DeliverFile( const char *input,
  455.                         const char *fwrdname,
  456.                         const long start,
  457.                         const long end,
  458.                         boolean *announce,
  459.                         struct UserTable *userp,
  460.                         const boolean sysalias,  /* Already sys alias */
  461.                         const boolean validate,
  462.                         const char *user )
  463. {
  464.    char buf[BUFSIZ];
  465.    FILE *fwrd = FOPEN(fwrdname, "r",TEXT_MODE);
  466.    char *cwd = sysalias ? E_tempdir : userp->homedir;
  467.    int delivered = 0;
  468.  
  469.    if ( fwrd == NULL )
  470.    {
  471.       printerr( fwrdname );
  472.       return Bounce( input,
  473.                      "Cannot open forward file",
  474.                      fwrdname,
  475.                      user,
  476.                      validate );
  477.    }
  478.  
  479.    if ( start != 0 )
  480.       fseek( fwrd, start, SEEK_SET);
  481.  
  482.    while((ftell(fwrd) < end) && (fgets( buf, BUFSIZ, fwrd) != NULL ))
  483.    {
  484.       char *s = buf;
  485.       char c;
  486.       char *nextfile = NULL;
  487.  
  488.       if ( buf[ strlen(buf) - 1 ]== '\n')
  489.          buf[ strlen(buf) - 1 ] = '\0';
  490.  
  491.       while( *s && ! isgraph( *s ))    /* Trim leading white space     */
  492.          s++;
  493.  
  494.       printmsg(8,"Forwarding to \"%s\"", s);
  495.       if ( equalni( buf, INCLUDE, strlen(INCLUDE)))
  496.       {
  497.          nextfile = strtok( s + strlen(INCLUDE), WHITESPACE );
  498.          if ( nextfile == NULL )
  499.          {
  500.             return Bounce(input,
  501.                           "Missing forwarding file for alias",
  502.                           fwrdname,
  503.                           user,
  504.                           validate );
  505.          }
  506.          else
  507.             c = ':';
  508.       } /* if */
  509.       else if ( isalpha(*s ) && (s[1] == ':'))  /* Drive name?    */
  510.          c = '/';             /* Yes --> flag as absolute path    */
  511.       else if ( *s == ':')    /* Avoid false triggers ...         */
  512.          c = ' ';             /* ... by making it general case    */
  513.       else                    /* Handle other cases in switch ... */
  514.          c = *s;
  515.  
  516.       switch(c)
  517.       {
  518.          case '#':
  519.             break;            /* Comment, ignore            */
  520.  
  521.          case '\0':
  522.             break;            /* Empty line, ignore         */
  523.  
  524.          case '|':               /* Pipe mail into a command   */
  525.          {
  526.             long here = ftell(fwrd);
  527.  
  528.             fclose(fwrd);
  529.             PushDir( cwd );
  530.             printmsg(1,"Piping mail%s from %s@%s for %s into %s",
  531.                         stats( input ),
  532.                         ruser,
  533.                         rnode,
  534.                         user,
  535.                         s + 1 );
  536.  
  537.             executeCommand( s + 1, input, NULL, TRUE, FALSE );
  538.             PopDir();
  539.             delivered += 1;
  540.             fwrd = FOPEN(fwrdname, "r",TEXT_MODE);
  541.             fseek( fwrd, here, SEEK_SET);
  542.             break;
  543.          } /* case */
  544.  
  545.          case '\\':              /* Deliver without forwarding */
  546.             delivered += Deliver( input, &s[1], TRUE, FALSE );
  547.             *announce = TRUE;
  548.             break;
  549.  
  550.          case ':':
  551.          {
  552.             char fname[FILENAME_MAX];
  553.             strcpy( fname, nextfile);
  554.             expand_path(nextfile, NULL, cwd, E_mailext);
  555.             delivered += DeliverFile( input, nextfile, 0, LONG_MAX,
  556.                                       announce, userp,
  557.                                       FALSE, TRUE, user );
  558.             break;
  559.          }
  560.  
  561.          case '/':               /* Save in absolute path name */
  562.          case '~':
  563.             if (expand_path(s, NULL, cwd, E_mailext) == NULL )
  564.             {
  565.                return Bounce(input,
  566.                              "Invalid path in forwarding file name",
  567.                              s,
  568.                              user,
  569.                              validate );
  570.  
  571.             }
  572.             else
  573.                delivered += DeliverLocal( input, s, sysalias, FALSE );
  574.             *announce = TRUE;
  575.             break;
  576.  
  577.          default:                /* Deliver normally           */
  578.               delivered += Deliver( input, s, sysalias, validate );
  579.       } /* switch */
  580.    } /* while */
  581.  
  582.    fclose( fwrd );
  583.  
  584.    return delivered;
  585.  
  586. } /* DeliverFile */
  587.  
  588. /*--------------------------------------------------------------------*/
  589. /*    D e l i v e r G a t e w a y                                     */
  590. /*                                                                    */
  591. /*    Deliver mail via a gateway program                              */
  592. /*--------------------------------------------------------------------*/
  593.  
  594. static size_t DeliverGateway(   const char *input,
  595.                                 const char *user,
  596.                                 const char *node,
  597.                                 const struct HostTable *hostp,
  598.                                 const boolean validate )
  599. {
  600.    char command[BUFSIZ];
  601.    int rc;
  602.  
  603. /*--------------------------------------------------------------------*/
  604. /*    Format the command and tell the user what we're going to do     */
  605. /*--------------------------------------------------------------------*/
  606.  
  607.    sprintf(command , "%s %s %s %s",
  608.                      hostp->via,          /* Program to perform forward */
  609.                      hostp->hostname,     /* Nominal host routing via  */
  610.                      node ,               /* Final destination system  */
  611.                      user );              /* user on "node" for delivery*/
  612.  
  613.    printmsg(3,"DeliverGateway: %s", command);
  614.  
  615.    printmsg(1,
  616.       "Gatewaying mail %sfrom %s@%s to %s@%s via %s using \"%s\"",
  617.        stats( input ),
  618.        ruser, rnode, user, node, hostp->hostname, hostp->via);
  619.  
  620. /*--------------------------------------------------------------------*/
  621. /*  Run the command and return caller with count of mail delivered    */
  622. /*--------------------------------------------------------------------*/
  623.  
  624.    rc = executeCommand( command, input, NULL, TRUE, FALSE );
  625.  
  626.    if ( rc == 0 )
  627.       return 1;
  628.    else {
  629.       char who[MAXADDR];
  630.  
  631.       sprintf( who, "%s@%s", user, node );
  632.       return Bounce( input,
  633.                      "Gateway command returned non-zero exit status",
  634.                      command,
  635.                      who,
  636.                      validate );
  637.    } /* else */
  638.  
  639. } /* DeliveryGateway */
  640.  
  641. /*--------------------------------------------------------------------*/
  642. /*    D e l i v e r R e m o t e                                       */
  643. /*                                                                    */
  644. /*    Queue mail for delivery on another system via UUCP              */
  645. /*--------------------------------------------------------------------*/
  646.  
  647. static size_t DeliverRemote( const char *input, /* Input file name    */
  648.                     const char *address,  /* Target address           */
  649.                     const char *path)
  650. {
  651.    static char *spool_fmt = SPOOLFMT;              /* spool file name */
  652.    static char *dataf_fmt = DATAFFMT;
  653.    static char *send_cmd  = "S %s %s %s - %s 0666\n";
  654.    static long seqno = 0;
  655.    static char *SavePath = NULL;
  656.    FILE *stream;              /* For writing out data                 */
  657.    static char everyone[500]; /* 512, with room for "rmail "          */
  658.  
  659.    char msfile[FILENAME_MAX]; /* MS-DOS format name of files          */
  660.    char msname[22];           /* MS-DOS format w/o path name          */
  661.  
  662.    char tmfile[15];           /* Call file, UNIX format name          */
  663.    static char ixfile[15];    /* eXecute file for remote system,
  664.                                 UNIX format name for local system   */
  665.    static char idfile[15];    /* Data file, UNIX format name          */
  666.    static char rdfile[15];    /* Data file name on remote system,
  667.                                  UNIX format                          */
  668.    static char rxfile[15];    /* Remote system UNIX name of eXecute
  669.                                  file                                 */
  670.  
  671.    printmsg(1,"Spooling mail %sfrom %s%s%s to %s via %s",
  672.                stats( input ),
  673.                ruser,
  674.                remoteMail ? "@" : "",
  675.                remoteMail ? rnode : "",
  676.                address ,
  677.                path);
  678.  
  679. /*--------------------------------------------------------------------*/
  680. /*          Create the UNIX format of the file names we need          */
  681. /*--------------------------------------------------------------------*/
  682.  
  683.    if ((seqno == 0) ||
  684.        (SavePath == NULL) ||
  685.        !equal(SavePath, path) ||
  686.        ((int) (strlen(everyone) + strlen(address) + 2) > (int) sizeof everyone))
  687.    {
  688.       char *seq;
  689.       seqno = getseq();
  690.       seq = JobNumber( seqno );
  691.  
  692.       if  (SavePath != NULL )
  693.       {
  694.          free(SavePath);
  695.          SavePath = NULL;
  696.       } /* if */
  697.  
  698.       sprintf(tmfile, spool_fmt, 'C', path,     grade , seq);
  699.       sprintf(idfile, dataf_fmt, 'D', E_nodename , seq, 'd');
  700.       sprintf(rdfile, dataf_fmt, 'D', E_nodename , seq, 'r');
  701.       sprintf(ixfile, dataf_fmt, 'D', E_nodename , seq, 'e');
  702.       sprintf(rxfile, dataf_fmt, 'X', E_nodename , seq, 'r');
  703.       strcpy(everyone,address);
  704.  
  705.    } /* if */
  706.    else {
  707.       strcat(everyone," ");
  708.       strcat(everyone,address);
  709.    } /* else */
  710.  
  711. /*--------------------------------------------------------------------*/
  712. /*                     create remote X (xqt) file                     */
  713. /*--------------------------------------------------------------------*/
  714.  
  715.    importpath( msname, ixfile, path);
  716.    mkfilename( msfile, E_spooldir, msname);
  717.  
  718.    stream = FOPEN(msfile, "w", BINARY_MODE);
  719.    if ( stream == NULL )
  720.    {
  721.       printerr(msfile);
  722.       printmsg(0, "DeliverRemote: cannot open X file %s", msfile);
  723.       return 0;
  724.    } /* if */
  725.  
  726.  
  727.    fprintf(stream, "R %s@%s\nU %s %s\nF %s\nI %s\nC rmail %s\n",
  728.                ruser, rnode, uuser , E_nodename,
  729.                rdfile, rdfile, everyone);
  730.    fclose(stream);
  731.  
  732.    if (SavePath != NULL)
  733.       return 1;
  734.  
  735. /*--------------------------------------------------------------------*/
  736. /*  Create the data file with the mail to send to the remote system   */
  737. /*--------------------------------------------------------------------*/
  738.  
  739.    importpath(msname, idfile, path);
  740.    mkfilename( msfile, E_spooldir, msname);
  741.  
  742.    stream = FOPEN(msfile, "w", BINARY_MODE);
  743.    if (stream == NULL )
  744.    {
  745.       printerr(msfile);
  746.       printmsg(0,
  747.                "DeliverRemote: Cannot open spool file \"%s\" for output",
  748.                 msfile);
  749.       return 0;
  750.    }
  751.  
  752.    if (!CopyData( TRUE, input , stream ))
  753.    {
  754.       remove( msfile );
  755.       return 0;
  756.    }
  757.  
  758. /*--------------------------------------------------------------------*/
  759. /*                     create local C (call) file                     */
  760. /*--------------------------------------------------------------------*/
  761.  
  762.    importpath( msname, tmfile, path);
  763.    mkfilename( msfile, E_spooldir, msname);
  764.  
  765.    stream = FOPEN(msfile, "w",TEXT_MODE);
  766.    if (stream == NULL)
  767.    {
  768.       printerr( msname );
  769.       printmsg(0, "DeliverRemote: cannot open C file %s", msfile);
  770.       return 0;
  771.    }
  772.  
  773.    fprintf(stream, send_cmd, idfile, rdfile, uuser, idfile);
  774.    fprintf(stream, send_cmd, ixfile, rxfile, uuser, ixfile);
  775.    fclose(stream);
  776.  
  777.    if (bflag[F_MULTI])        /* Deliver to multiple users at once?   */
  778.       SavePath = strdup(path);   /* Yes --> Save routing info         */
  779.  
  780.    return 1;
  781. } /* DeliverRemote */
  782.  
  783. /*--------------------------------------------------------------------*/
  784. /* C o p y D a t a                                                    */
  785. /*                                                                    */
  786. /* Copy data into its final resting spot                              */
  787. /*--------------------------------------------------------------------*/
  788.  
  789. static int CopyData( const boolean remotedelivery,
  790.                      const char *input,
  791.                      FILE *dataout)
  792. {
  793.    FILE *datain = FOPEN(input, "r",TEXT_MODE);
  794.    char buf[BUFSIZ];
  795.    char trailer[BUFSIZ];
  796.    int column = 0;
  797.    boolean success = TRUE;
  798.  
  799.    int (*put_string) (char *, FILE *) = (int (*)(char *, FILE *)) fputs;
  800.                               /* Assume no Kanji translation needed   */
  801.  
  802.    if ( bflag[F_SHORTFROM] )
  803.       *trailer = '\0';
  804.    else {
  805.       time_t now;
  806.  
  807.       time( &now );
  808.       sprintf(trailer, " %.24s remote from %s", ctime( &now ), E_nodename);
  809.    }
  810.  
  811. /*--------------------------------------------------------------------*/
  812. /*                      Verify the input opened                       */
  813. /*--------------------------------------------------------------------*/
  814.  
  815.    if (datain == NULL)
  816.    {
  817.       printerr(input);
  818.       printmsg(0,"Unable to open input file \"%s\"", input);
  819.       fclose(dataout);
  820.       return 0;
  821.    } /* datain */
  822.  
  823. /*--------------------------------------------------------------------*/
  824. /*    When we do the From line, we also determine if we must          */
  825. /*    translate the data.  Note that the default is initialized to    */
  826. /*    fputs() above.                                                  */
  827. /*                                                                    */
  828. /*    If Kanji is not enabled, don't translate it                     */
  829. /*                                                                    */
  830. /*    If local mail queued for local delivery, the data is already    */
  831. /*    in Shift JIS, so don't translate it.                            */
  832. /*                                                                    */
  833. /*    If remote mail is queued for remote delivery, the data is       */
  834. /*    already in JIS 7bit, so don't translate it.                     */
  835. /*                                                                    */
  836. /*    If delivering remote mail locally, translate to Shift JIS       */
  837. /*                                                                    */
  838. /*    If delivering local mail remotely, translate to JIS 7 bit       */
  839. /*--------------------------------------------------------------------*/
  840.  
  841. /*--------------------------------------------------------------------*/
  842. /*                        Generate a FROM line                        */
  843. /*--------------------------------------------------------------------*/
  844.  
  845.    switch( (int) remoteMail * 2 + (int) remotedelivery )
  846.    {
  847.       case 3:                 /* Remote sender, remote delivery       */
  848.          strcpy( buf, fromuser );
  849.          strtok( buf, "!");   /* Get first host in list               */
  850.  
  851.  
  852.          if ( bflag[ F_SUPPRESSFROM ] )
  853.             ;                 /* No operation                        */
  854.          else if ( equal(HostAlias( buf ), fromnode ))
  855.                               /* Host already in list?                */
  856.          {                    /* Yes --> Don't do it twice            */
  857.             fprintf(dataout, "From %s%s\n",
  858.                     fromuser,
  859.                     trailer );
  860.          }
  861.          else {                /* No --> Insert it                    */
  862.             fprintf(dataout, "From %s!%s%s\n",
  863.                     fromnode,
  864.                     fromuser,
  865.                     trailer );
  866.          }
  867.          break;
  868.  
  869.       case 2:                 /* Remote sender, local delivery        */
  870.          if ( bflag[ F_KANJI ] )
  871.                               /* Kanji from remote node?              */
  872.             put_string = (int (*)(char *, FILE *)) fputs_shiftjis;
  873.                               /* Yes --> Translate it                 */
  874.  
  875.          if ( ! bflag[ F_SUPPRESSFROM ] )
  876.             fprintf(dataout, "From %s%s\n",
  877.                     fromuser,
  878.                     trailer );
  879.  
  880.          break;
  881.  
  882.       case 1:                 /* Local sender, remote delivery        */
  883.          if ( bflag[F_KANJI]) /* Translation enabled?                 */
  884.             put_string = (int (*)(char *, FILE *)) fputs_jis7bit;
  885.                               /* Translate into 7 bit Kanji           */
  886.  
  887.  
  888.          if ( ! bflag[ F_SUPPRESSFROM ] )
  889.          {
  890.             column = strlen(E_domain) - 5;
  891.             if ((column > 0) && equali(&E_domain[column],".UUCP"))
  892.                               /* UUCP domain?                         */
  893.                fprintf(dataout, "From %s%s\n",
  894.                                 fromuser,
  895.                                 trailer );
  896.  
  897.                               /* Yes --> Use simple address           */
  898.             else
  899.                fprintf(dataout, "From %s!%s%s\n",
  900.                        E_domain,
  901.                        fromuser,
  902.                        trailer );
  903.                               /* No --> Use domain address            */
  904.          }
  905.          break;
  906.  
  907.       case 9:                 /* Local sender, remote delivery        */
  908.          if ( bflag[F_KANJI]) /* Translation enabled?                 */
  909.             put_string = (int (*)(char *, FILE *)) fputs_jis7bit;
  910.                               /* Translate into 7 bit Kanji           */
  911.  
  912.          if ( ! bflag[ F_SUPPRESSFROM ] )
  913.          {
  914.             column = strlen(E_domain) - 5;
  915.             if ((column > 0) && equali(&E_domain[column],".UUCP"))
  916.                               /* UUCP domain?                         */
  917.                fprintf(dataout,
  918.                        "From %s%s\n",
  919.                        fromuser,
  920.                        trailer );
  921.                               /* Yes --> Use simple address           */
  922.             else
  923.                fprintf(dataout, "From %s!%s%s\n",
  924.                       E_domain,
  925.                       fromuser,
  926.                       trailer );
  927.                               /* No --> Use domain address            */
  928.          }
  929.          break;
  930.  
  931.       case 0:                 /* Local sender, local delivery         */
  932.          if ( ! bflag[ F_SUPPRESSFROM ] )
  933.             fprintf(dataout, "From %s%.25s\n", fromuser, trailer );
  934.          break;
  935.  
  936.    } /* switch */
  937.  
  938. /*--------------------------------------------------------------------*/
  939. /*                       Loop to copy the data                        */
  940. /*--------------------------------------------------------------------*/
  941.  
  942.    while (fgets(buf, BUFSIZ, datain) != NULL)
  943.    {
  944.       if ((*put_string)(buf, dataout) == EOF)     /* I/O error? */
  945.       {
  946.          printerr("output");
  947.          printmsg(0,"I/O error on \"%s\"", "output");
  948.          fclose(dataout);
  949.          return 0;
  950.       } /* if */
  951.    } /* while */
  952.  
  953. /*--------------------------------------------------------------------*/
  954. /*                      Close up shop and return                      */
  955. /*--------------------------------------------------------------------*/
  956.  
  957.    if (ferror(datain))        /* Clean end of file on input?          */
  958.    {
  959.       printerr(input);
  960.       clearerr(datain);
  961.       success = FALSE;
  962.    }
  963.  
  964.    fclose(datain);
  965.    fclose(dataout);
  966.    return success;
  967.  
  968. } /* CopyData */
  969.  
  970. /*--------------------------------------------------------------------*/
  971. /*       b o u n c e                                                  */
  972. /*                                                                    */
  973. /*       Report failed mail to a user.  Based on code contributed     */
  974. /*       by Kevin Meyer <kmeyer@sauron.alt.za>                        */
  975. /*                                                                    */
  976. /*       This code has a major hole in that the address it replies    */
  977. /*       to is weak, really having been previously only been used     */
  978. /*       for internal messages.  Perhaps the full address from the    */
  979. /*       UUCP From line should be used.                               */
  980. /*--------------------------------------------------------------------*/
  981.  
  982. size_t Bounce( const char *input,
  983.                const char *text,
  984.                const char *data,
  985.                const char *address ,
  986.                const boolean validate )
  987. {
  988.    FILE *newfile, *otherfile;
  989.    char tname[FILENAME_MAX]; /* name of temporary file used */
  990.    char buf[BUFSIZ];
  991.    char sender[MAXADDR];
  992.  
  993.    boolean bounce = bflag[F_BOUNCE];
  994.  
  995.    sprintf(sender, "%s%s%s",
  996.                ruser,
  997.                remoteMail ? "@" : "",
  998.                remoteMail ? rnode : "" );
  999.  
  1000.     printmsg(0,"Bounce: Mail from %s for %s failed, %s: %s",
  1001.                sender,
  1002.                address,
  1003.                text,
  1004.                (data == NULL) ? "(no data)" : data );
  1005.  
  1006. /*--------------------------------------------------------------------*/
  1007. /*           Never bounce mail to a select list of user ids           */
  1008. /*--------------------------------------------------------------------*/
  1009.  
  1010.    if ( equali( ruser, "postmaster") ||
  1011.         equali( ruser, "uucp") ||
  1012.         equali( ruser, "root") ||
  1013.         equali( ruser, "mmdf") ||
  1014.         equali( ruser, "mailer-daemon"))
  1015.       bounce = FALSE;
  1016.  
  1017.    if ( ! bounce )
  1018.      return Deliver( input, E_postmaster, FALSE, validate );
  1019.  
  1020.    mktempname( tname , "TMP");  /* Generate a temp file name           */
  1021.  
  1022.    if ((otherfile = FOPEN(input,"r", TEXT_MODE ))==NULL)
  1023.    {
  1024.        printerr( input );
  1025.        panic();
  1026.    };
  1027.  
  1028.    if ((newfile = FOPEN(tname, "w", TEXT_MODE ))==NULL)
  1029.    {
  1030.        printerr( tname );
  1031.        panic();
  1032.    };
  1033.  
  1034.    fprintf(newfile,
  1035.      "Dear %s,\n"
  1036.      "Your message for address <%s> could not be delivered at system\n"
  1037.      "%s (uucp node %s) for the following reason:\n\t\t%s.\n",
  1038.                   ruser,
  1039.                   address, E_domain, E_nodename, text );
  1040.  
  1041.    if ( data != NULL )
  1042.       fprintf(newfile,
  1043.              "The problem address or file in question was:  %s\n",
  1044.              data );
  1045.  
  1046.       fprintf(newfile,
  1047.               "\nA copy of the failed mail follows.\n\n"
  1048.               "Electronically Yours,\n"
  1049.               "%s %s UUCP mailer daemon\n",
  1050.               compilep, compilev );
  1051.  
  1052.     fputs("\n------ Failed Message Follows -----\n", newfile);
  1053.  
  1054.     while ( fgets(buf, sizeof buf, otherfile) != NULL)
  1055.       fputs(buf, newfile);
  1056.  
  1057.     fclose(newfile);
  1058.     fclose(otherfile);
  1059.  
  1060. /*--------------------------------------------------------------------*/
  1061. /*          Recursively invoke RMAIL to deliver our message           */
  1062. /*--------------------------------------------------------------------*/
  1063.  
  1064.    putenv("LOGNAME=uucp");
  1065.  
  1066.    sprintf( buf, "-w -F %s -s \"Failed mail for %.20s\" %s -c postmaster",
  1067.             tname,
  1068.             address,
  1069.             sender );
  1070.  
  1071.     if ( execute( myProgramName, buf, NULL, NULL, TRUE, FALSE ))
  1072.          DeliverLocal( input, E_postmaster, FALSE, validate);
  1073.  
  1074.     return (1);
  1075.  
  1076. } /* Bounce */
  1077.  
  1078.  
  1079. /*--------------------------------------------------------------------*/
  1080. /*    s t a t s                                                       */
  1081. /*                                                                    */
  1082. /*    Report size of file in message, if desired                      */
  1083. /*--------------------------------------------------------------------*/
  1084.  
  1085. static char *stats( const char *fname )
  1086. {
  1087.    if (bflag[ F_COLLECTSTATS ] )
  1088.    {
  1089.       long size;
  1090.       time_t ltime = stater(fname, &size);
  1091.  
  1092.       if ( ltime == -1 )
  1093.       {
  1094.          printerr( fname );
  1095.          return "(unknown size)";
  1096.       }
  1097.       else {
  1098.          static char buf[25];  /* "(nnnnnnn bytes) " */
  1099.                                /*  ....+....+....+.. */
  1100.          sprintf(buf,   "(%ld bytes) ",size );
  1101.          return buf;
  1102.       } /* else */
  1103.    } /* if */
  1104.    else
  1105.       return "";              /* Pretend we were never here       */
  1106.  
  1107. } /* stats */
  1108.