home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / duucp-1.17 / AU-117b4-src.lha / src / sendmail / sendmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-19  |  44.1 KB  |  2,123 lines

  1. /*#define PROCDEBUG*/
  2. /*
  3.  *  SENDMAIL / RMAIL
  4.  *
  5.  *  (C) Copyright 1989-1990 by Matthew Dillon,    All Rights Reserved.
  6.  *
  7.  *  Domain-Path Enhancement by Henning Schmiedehausen. This is PD.
  8.  *  Changes copyright 1993 by Michael B. Smith. This is PD.
  9.  *  MAILLOG idea and changes by Jeff Van Epps. This is PD.
  10.  *
  11.  *  SENDMAIL <file -f from -t to -s subject -c cc -b bcc -r
  12.  *  RMAIL user
  13.  *
  14.  *  Example:    Sendmail <datafile -froot
  15.  *
  16.  *  From: line is automatically added but can be overriden by a From:
  17.  *  header in the file.  stdin is made up of a list of headers, a blank
  18.  *  line, and then data until EOF.
  19.  *
  20.  *  The -r option tells sendmail that this is incoming mail.
  21.  *  If av [0] begins with an 'r' for RMail instead of an 's' for
  22.  *  Sendmail, then the rmail argument format is used (rmail user),
  23.  *  as well as forcing -r.
  24.  */
  25.  
  26. #include "defs.h"
  27.  
  28. #include <fcntl.h>
  29. #include <log.h>
  30. #include <time.h>
  31. #include <pwd.h>
  32. #include <config.h>
  33. #include <version.h>
  34. #include <owndevunit.h>
  35.  
  36. IDENT (".31");
  37.  
  38. #ifdef PROCDEBUG
  39. int
  40.     debug_delay = 0;
  41.  
  42. #define PROC(x)     const char _proc [] = { x }; printf ("%s: enter\n", _proc)
  43. #define D(x)        printf ("%s: ", _proc); if (debug_delay) Delay (debug_delay); printf x
  44. #else
  45. #define PROC(x)
  46. #define D(x)
  47. #endif
  48.  
  49. Prototype char *DefaultNode;
  50. Prototype char *NodeName;
  51. Prototype char *DomainPath;
  52. Prototype int  ROpt;
  53. Prototype int  BounceOpt;
  54. Prototype int  UserBounceOpt;
  55. Prototype int  CcPmBounceOpt;
  56.  
  57. Local    void Usage (void);
  58. Local    int brk (void);
  59. Local    void myexit (void);
  60. Local    struct Node *MakeNode (struct List *, char *);
  61. Local    void MakeToFixNode (struct List *, char *, char *);
  62. Local    int  fixCallBack (const char *, struct List *, int);
  63. Local    void IntegrateHeader (char *, int);
  64. Local    void FromFixup (struct List *);
  65. Local    void ToFixup (struct List *);
  66. Local    void MakeToAddrNode (struct List *, char *);
  67. Local    FILE *TermMailToUUCP (FILE *);
  68. Local    FILE *SendMailTo (struct List *, FILE *);
  69. Local    FILE *OneMailTo (char *, FILE *, int);
  70. Local    FILE *OneMailToPipe (char *, FILE *);
  71. Local    FILE *OneMailToUser (char *, FILE *);
  72. Local    FILE *OneMailToFile (char *, FILE *);
  73. Local    FILE *OneMailToUUCP (char *, char *, FILE *);
  74. Local    void DumpHeaderInfo (FILE *, int, int, int, char *);
  75. Local    void DumpHeader (FILE *, char *, struct List *, char *);
  76. Local    void DumpHeaderLast (FILE *, char *, struct List *, char *);
  77. Local    char *FindHeader (char *);
  78. Local    void DumpCombineHeader (FILE *, char *, struct List *, char *);
  79. Local    char *atime (time_t *);
  80. Local    int GetHourOffset (char *);
  81. Local    void PostPend (char *, int);
  82. Local    void FindSource (const char *);
  83. Local    char *BounceMail (FILE *, char *, char *, char *);
  84. Local    void DoBounceMail (FILE *, char *, char *, char *, int);
  85.  
  86. #define RCVR_UUCP    1
  87. #define RCVR_SENDMAIL    2
  88.  
  89. #define REMOTE_FROM    "remote from"
  90.  
  91. char
  92.     *CheckUser,
  93.     *UserName,
  94.     *RealName,
  95.     *NodeName,
  96.     *DomainPath = "",
  97.     *DomainName,
  98.     *TimeZoneName,        /* All caps, ex: PST            */
  99.     *DefaultNode,        /* for addr formats we don't understand */
  100.     *MailLog = NULL;    /* Where to log mail, when enabled        */
  101.  
  102. struct List
  103.     RecvList,    /*  Received:        */
  104.     FromList,    /*  last one rules  */
  105.     ToList,     /*  To:         */
  106.     CcList,     /*  Cc:         */
  107.     BccList,    /*  Bcc:        */
  108.     XccList,    /*  list of actual mail to be sent  */
  109.     SubjList,    /*  Subject:        */
  110.     HdrList,    /*  other headers not specifically parsed   */
  111.     UUHostList;    /*  tracking mail sent to a given UUCP host */
  112.  
  113. char
  114.     ScrBuf [1024],
  115.     ScrBuf2 [1024],
  116.     TempFileBuf [256];
  117. int
  118.     isRMail    = 0, /*  my basename() is r*               */
  119.     isSendMail = 1, /*  opposite of isRMail               */
  120.     _bufsiz = 8192, /*  for stdio                      */
  121.     TopSeq,     /*  Top sequence no for Message-Id:          */
  122.     Notify       = 0, /*  if > 0, a local message was delivered     */
  123.     ROpt       = 0, /*  RMAIL flag                      */
  124.     BounceOpt  = 0, /*  whether or not to generate domain bounces */
  125.     UserBounceOpt,    /*  whether or not to generate user bounces   */
  126.     CcPmBounceOpt,    /*  whether or not to CC postmaster on bounces*/
  127.     Strip_UUCP = 0, /*  if addr ends with UUCP, then strip it off */
  128.     SmartUUCP  = 0, /*  use FQDN in Received: headers, per RFC976 */
  129.     LogMail    = 0, /*  Log mailsize to UULib:MailLog          */
  130.     ForceNoBounce,
  131.     NoHdrOpt   = 0; /*  ignore headers opt                  */
  132.  
  133. static char
  134.     OrigFromLine [512],
  135.     FromLine [512]; /*  'From ' line, if ROpt   */
  136.  
  137. time_t
  138.     T;        /*  current time    */
  139.  
  140. struct Library
  141.     *OwnDevUnitBase = NULL;
  142.  
  143. /*
  144. **  MailLog stuff
  145. */
  146. static char
  147.     FromSystem [128],   /* system where mail originated   */
  148.     FromUser   [128],   /* use who originated mail          */
  149.     Feed       [128];   /* system which passed mail to us */
  150. static int
  151.     MailSize = 0;        /* how big the mail message is    */
  152.  
  153. int
  154. main (int ac, char **av)
  155. {
  156.     FILE
  157.         *fi;
  158.  
  159.     PROC ("main");
  160.  
  161.     onbreak (brk);
  162.  
  163.     LogProgram = "Sendmail";
  164.  
  165.     NewList (&RecvList);
  166.     NewList (&FromList);
  167.     NewList (&ToList);
  168.     NewList (&CcList);
  169.     NewList (&BccList);
  170.     NewList (&XccList);
  171.     NewList (&SubjList);
  172.     NewList (&HdrList);
  173.     NewList (&UUHostList);
  174.  
  175.     atexit (myexit);
  176.     if ((OwnDevUnitBase = OpenLibrary (ODU_NAME, 0)) == NULL) {
  177.         fprintf (stderr, "Unable to open %s\n", ODU_NAME);
  178.         exit (20);
  179.     }
  180.  
  181.     UserName = GetUserName ();
  182.     RealName = GetRealName ();
  183.  
  184.     T = time (NULL);        /* for global timestamps */
  185.     TopSeq = GetSequence (1);   /* for message ids */
  186.     D (("TopSeq = %ld\n", TopSeq));
  187.  
  188.     if (UserName == NULL) {
  189.         fprintf (stderr, "Sendmail: UserName config entry not found!\n");
  190.         ulog (-1, "UserName config missing");
  191.         exit (20);
  192.     }
  193.  
  194.     if (RealName == NULL) {
  195.         fprintf (stderr, "Sendmail: RealName config entry not found!\n");
  196.         ulog (-1, "RealName config missing");
  197.         exit (20);
  198.     }
  199.  
  200.     NodeName = FindConfig (NODENAME);
  201.     CheckUser = FindConfig (CHECKUSER);
  202.  
  203.     D (("UserName '%s', RealName '%s', NodeName '%s'\n", UserName, RealName, NodeName));
  204.  
  205.     {
  206.         char
  207.             *ptr = GetConfig (MAILBOUNCE, "0");
  208.  
  209.         if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
  210.             D (("BounceOpt set\n"));
  211.             BounceOpt = 1;
  212.         }
  213.  
  214.         ptr = GetConfig (USERBOUNCE, "0");
  215.         if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
  216.             D (("UserBounceOpt set\n"));
  217.             UserBounceOpt = 1;
  218.         }
  219.  
  220.         ptr = GetConfig (CCPMBOUNCE, "0");
  221.         if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
  222.             D (("CcPmBounceOpt set\n"));
  223.             CcPmBounceOpt = 1;
  224.         }
  225.  
  226.         ptr = GetConfig ("StripUUCP", "0");
  227.         if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
  228.             D (("StripUUCP set\n"));
  229.             Strip_UUCP = 1;
  230.         }
  231.  
  232.         ptr = GetConfig ("SmartUUCP", "0");
  233.         if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
  234.             D (("SmartUUCP set\n"));
  235.             SmartUUCP = 1;
  236.         }
  237.  
  238.         ptr = GetConfig ("LogMail", "0");
  239.         if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
  240.             D (("LogMail set\n"));
  241.             LogMail = 1;
  242.  
  243.             MailLog = GetConfig ("MailLog", "UUSpool:MailLog");
  244.         }
  245.     }
  246.  
  247.     if (NodeName == NULL) {
  248.         fprintf (stderr, "Sendmail: NodeName config entry not found!\n");
  249.         ulog (-1, "NodeName config missing");
  250.         exit (20);
  251.     }
  252.  
  253.     DomainName = FindConfig (DOMAINNAME);
  254.     if (DomainName == NULL) {
  255.         fprintf (stderr, "Sendmail: DomainName config entry not found! using .UUCP\n");
  256.         DomainName = ".uucp";
  257.     }
  258.  
  259.     D (("DomainName '%s'\n", DomainName));
  260.  
  261.     {
  262.         char
  263.             *str = GetConfig (DOMAINPATH, "N");
  264.  
  265.         if (str [0] == 'y' || str [0] == 'Y' || str [0] == '1') {
  266.             D (("DomainPath set\n"));
  267.             DomainPath = DomainName;
  268.         }
  269.     }
  270.  
  271.     DefaultNode  = FindConfig (DEFAULTNODE);
  272.     TimeZoneName = FindConfig (TIMEZONE);
  273.  
  274.     D (("DefaultNode '%s', TimeZone '%s'\n", DefaultNode, TimeZoneName));
  275.  
  276.     LoadAliases ();
  277.  
  278.     {
  279.         char
  280.             *ptr = av [0] + strlen (av [0]);
  281.  
  282.         /*
  283.          *  Skip path
  284.          */
  285.  
  286.         while (ptr >= av[0] && *ptr != ':' && *ptr != '/')
  287.             --ptr;
  288.         ++ptr;
  289.  
  290.         if (*ptr == 'r' || *ptr == 'R') {
  291.             isRMail = 1;
  292.             isSendMail = 0;
  293.             LogProgram = "RMail";
  294.         }
  295.     }
  296.  
  297.     if (isRMail) {
  298.         if (ac <= 1) {
  299.             MakeNode (&BccList, "MAILER-DAEMON");
  300.         }
  301.         else {
  302.             int
  303.                 i;
  304.  
  305.             for (i = 1; i < ac; ++i)
  306.                 MakeNode (&BccList, av [i]);
  307.         }
  308.         UserName = "postmaster";    /*  XXX  */
  309.         RealName = "Mr.Amiga";      /*  XXX  */
  310.         ROpt = 1;            /*    no header processing */
  311.     }
  312.  
  313.     if (isSendMail) {
  314.         int
  315.             i;
  316.         char
  317.             *arg;
  318.  
  319.         for (i = 1; i < ac; ++i) {
  320.             arg = av [i];
  321.             if (*arg != '-')
  322.                 Usage ();
  323.             arg += 2;
  324.             switch (arg [-1]) {
  325.                 case 'f':
  326.                     UserName = av [i + 1];
  327.                     if (strchr (UserName, '@') || strchr (UserName, '!'))
  328.                         MakeNode (&FromList, UserName);
  329.                     else {
  330.                         sprintf (ScrBuf, "%s@%s%s", UserName, NodeName, DomainName);
  331.                         MakeNode (&FromList, ScrBuf);
  332.                     }
  333.                     ++i;
  334.                     break;
  335.                 case 'R':
  336.                     RealName = av [++i];
  337.                     break;
  338.                 case 't':
  339.                     MakeNode (&ToList, av [++i]);
  340.                     break;
  341.                 case 'c':
  342.                     MakeNode (&CcList, av [++i]);
  343.                     break;
  344.                 case 'b':
  345.                     MakeNode (&BccList, av [++i]);
  346.                     break;
  347.                 case 's':
  348.                     MakeNode (&SubjList, av [++i]);
  349.                     break;
  350.                 case 'r':
  351.                     if (strcmp (arg, "aw") == 0)
  352.                         NoHdrOpt = 1;
  353.                     else
  354.                         ++ROpt;
  355.                     break;
  356.                 default:
  357.                     Usage ();
  358.             }
  359.         }
  360.  
  361.         if (LogMail) {
  362.             char
  363.                 *p;
  364.             /*
  365.             **  For locally originated mail, record our system
  366.             **  name and the sending user.
  367.             */
  368.             strcpy (FromSystem, NodeName);
  369.             strcpy (Feed, NodeName);
  370.             strcpy (FromUser, UserName);
  371.             if (p = strchr (FromUser, '@')) {
  372.                 *p = '\0';
  373.                 strcpy (FromSystem, p + 1);
  374.             }
  375.             else
  376.                 if (p = strrchr (UserName, '!')) {
  377.                     strcpy (FromUser, p + 1);
  378.                     strncpy (FromSystem, UserName, p - UserName);
  379.                     FromSystem [p - UserName] = '\0';
  380.                 }
  381.         }
  382.     }
  383.  
  384.     D (("isRmail %ld, isSendMail %ld, ROpt %ld, NoHdrOpt %ld\n",
  385.         isRMail, isSendMail, ROpt, NoHdrOpt));
  386.  
  387.     /*
  388.      *  Read headers from input file.  Headers are not necessarily
  389.      *  contained on a single line.  Maximum 4096 chars per header.
  390.      */
  391.  
  392.     if (ROpt) {
  393.         if (fgets (ScrBuf, sizeof (ScrBuf), stdin) == NULL) {
  394.             D (("exit, no mail file!\n"));
  395.             ulog (-1, "Error: empty mail file");
  396.             exit (20);
  397.         }
  398.  
  399.         if (strncmp (ScrBuf, ">From ", 6) && strncmp (ScrBuf, "From ", 5)) {
  400.             ulog (-1, "Receive mail, expected 'From ', got %s", ScrBuf);
  401.         }
  402.         else {
  403.             int
  404.                 ofst = ScrBuf [0] == '>' ? 1 : 0;
  405.  
  406.             strncpy (OrigFromLine, ScrBuf + ofst, sizeof (OrigFromLine));
  407.             strcpy (FromLine, "From ");
  408.             if (strstr (ScrBuf, REMOTE_FROM))
  409.                 PostPend (ScrBuf + (5 + ofst), 1);
  410.  
  411.             while (fgets (ScrBuf, sizeof (ScrBuf), stdin) && strncmp (ScrBuf, ">From ", 6) == 0) {
  412.                 strncpy (OrigFromLine, ScrBuf + 1, sizeof (OrigFromLine));
  413.                 if (strstr (ScrBuf, REMOTE_FROM))
  414.                     PostPend (ScrBuf + 6, 1);
  415.             }
  416.             strcpy (ScrBuf2, OrigFromLine + 5);
  417.             PostPend (ScrBuf2, 0);
  418.             if (LogMail) {
  419.                 /*
  420.                 **  For externally generated mail, parse the
  421.                 **  From line to find the Feed, FromSystem,
  422.                 **  and FromUser.
  423.                 */
  424.                 FindSource (FromLine);
  425.             }
  426.         }
  427.     }
  428.     else {
  429.         ScrBuf [0] = '\n';
  430.         if (NoHdrOpt == 0)
  431.             if (fgets (ScrBuf, sizeof (ScrBuf), stdin) == NULL) {
  432.                 D (("exit, no mail file!\n"));
  433.                 ulog (-1, "Error: empty mail file");
  434.                 exit (20);
  435.             }
  436.     }
  437.  
  438.     if (NoHdrOpt == 0) {
  439.         static char
  440.             *Hdr = NULL;
  441.         static int
  442.             h_size = 0;
  443.         int
  444.             i = 0;          /*  index into Hdr  */
  445.  
  446.         if (!Hdr) {
  447.             h_size = 4096;
  448.             Hdr = malloc (h_size);
  449.             if (!Hdr) {
  450.                 ulog (-1, "Error: No memory!");
  451.                 exit (20);
  452.             }
  453.         }
  454.  
  455.         while (ScrBuf [0] != '\n') {
  456.             char
  457.                 *ptr = ScrBuf;
  458.  
  459.             while (*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != ':')
  460.                 ++ptr;
  461.  
  462.             if (*ptr == ':') {      /*  found new header */
  463.                 if (i)        /*  Dump old header  */
  464.                     IntegrateHeader (Hdr, i);
  465.                 strcpy (Hdr, ScrBuf);
  466.                 i = strlen (Hdr);
  467.             }
  468.             else {          /*  append to existing header   */
  469.                 int
  470.                     len = strlen (ScrBuf);
  471.  
  472.                 if (i == 0)
  473.                     fprintf (stderr, "Expected a Header!\n");
  474.  
  475.                 if ((i + len) >= h_size) {
  476.                     h_size += 1024;
  477.                     Hdr = realloc (Hdr, h_size);
  478.                     if (!Hdr) {
  479.                         ulog (-1, "Error: Not enough memory!");
  480.                         exit (20);
  481.                     }
  482.                 }
  483.  
  484.                 strcpy (Hdr + i, ScrBuf);
  485.                 i = i + strlen (Hdr + i);
  486.             }
  487.  
  488.             if (fgets (ScrBuf, sizeof (ScrBuf), stdin) == NULL)
  489.                 ScrBuf [0] = '\n';
  490.         }
  491.  
  492.         if (i)
  493.             IntegrateHeader (Hdr, i);
  494.  
  495.         if (ScrBuf [0] != '\n') {
  496.             fprintf (stderr, "sendmail: no mail\n");
  497.             ulog (0, "No Mail");
  498.             exit (5);
  499.         }
  500.     }
  501.  
  502.     /*
  503.      *  Parse & fixup each To:, Cc:, and Bcc: field.
  504.      *
  505.      *  From:   we add the personal info arg from the password file
  506.      *  To:     we expand any aliases
  507.      *
  508.      *  OpenLog() : log optimization
  509.      */
  510.  
  511.     OpenLog ();
  512.     if (ROpt) {
  513.         ToFixup (&BccList);
  514.     }
  515.     else {
  516.         FromFixup (&FromList);
  517.         ToFixup (&ToList);
  518.         ToFixup (&CcList);
  519.         ToFixup (&BccList);
  520.     }
  521.     CloseLog ();
  522.  
  523.     if (IsListEmpty (&XccList)) {
  524.         ulog (-1, "Error: No destination specified!");
  525.         D (("exit, Empty destination lists!\n"));
  526.         exit (20);
  527.     }
  528.  
  529.     /*
  530.      *  If no Subject: field add a dummy one
  531.      */
  532.  
  533.     if (IsListEmpty (&SubjList))
  534.         MakeNode (&SubjList, "<none>");
  535.  
  536.     if (IsListEmpty (&FromList)) {
  537.         sprintf (ScrBuf, "%s@%s%s", UserName, NodeName, DomainName);
  538.         MakeNode (&FromList, ScrBuf);
  539.     }
  540.  
  541.     fi = SendMailTo (&XccList, stdin);
  542.  
  543.     if (fi && fi != stdin)
  544.         fclose (fi);
  545.  
  546.     if (TempFileBuf [0])
  547.         remove (TempFileBuf);
  548.  
  549.     UnLockFiles ();
  550.  
  551.     /*
  552.      *  Notify if T:MailRdy does not exist (created by us, deleted by
  553.      *  notify when notify exits).    Prevents running multiple notifies.
  554.      */
  555.  
  556.     if (Notify) {
  557.         int
  558.             fd = open ("T:MailRdy", O_RDONLY);
  559.  
  560.         if (fd < 0) {
  561.             char
  562.                 *cmd;
  563.  
  564.             if (cmd = FindConfig (MAILREADYCMD)) {
  565.                 fd = open ("T:MailRdy", O_CREAT|O_TRUNC, 0666);
  566.                 if (fd >= 0)
  567.                     close (fd);
  568.                 sprintf (ScrBuf, "Run %s -x T:MailRdy", cmd);
  569.                 Execute (ScrBuf, 0, 0);
  570.             }
  571.         }
  572.         else {
  573.             close (fd);
  574.         }
  575.  
  576.         /*
  577.          *  signal for update for any utilities that support it.
  578.          */
  579.         {
  580.             struct MsgPort
  581.                 *port;
  582.  
  583.             Forbid ();
  584.             if ((port = FindPort ("T:MailRdy")) && port->mp_SigTask)
  585.                 Signal (port->mp_SigTask, 1 << port->mp_SigBit);
  586.             Permit ();
  587.         }
  588.     }
  589.  
  590.     return 0;
  591. }
  592.  
  593. void
  594. myexit (void)
  595. {
  596.     PROC ("myexit");
  597.  
  598.     UnLockFiles ();
  599.  
  600.     if (OwnDevUnitBase) {
  601.         CloseLibrary (OwnDevUnitBase);
  602.         OwnDevUnitBase = NULL;
  603.     }
  604.  
  605.     D (("exit\n"));
  606.     return;
  607. }
  608.  
  609. void
  610. Usage (void)
  611. {
  612.     fprintf (stderr,
  613.         "Sendmail [-f user] [-t addr] [-c addr] [-b addr] [-s subj] [-r] [-raw] <file\n"
  614.         "RMail user... <file\n"
  615.     );
  616.  
  617.     exit (20);
  618. }
  619.  
  620. int
  621. brk (void)
  622. {
  623.     UnLockFiles ();
  624.     return 0;
  625. }
  626.  
  627. /*
  628.  *  Strips string and creates named node which is appended to the
  629.  *  given list.
  630.  */
  631.  
  632. struct Node *
  633. MakeNode (struct List *list, char *str)
  634. {
  635.     struct Node
  636.         *node;
  637.     char
  638.         *ptr;
  639.  
  640.     PROC ("MakeNode");
  641.     D (("str '%s'\n", str));
  642.  
  643.     while (*str == ' ' || *str == '\t')
  644.         ++str;
  645.     for (ptr = str + strlen (str) - 1; ptr >= str && (*ptr == ' ' || *ptr == '\t'); --ptr)
  646.         ;
  647.     ++ptr;
  648.     *ptr = 0;
  649.     node = malloc (sizeof (struct Node) + strlen (str) + 1);
  650.     if (!node) {
  651.         ulog (-1, "MakeNode: no memory!");
  652.         exit (20);
  653.     }
  654.     node->ln_Pri = 0;
  655.     node->ln_Name = (char *) (node + 1);
  656.     strcpy (node->ln_Name, str);
  657.     AddTail (list, node);
  658.  
  659.     D (("exit\n"));
  660.     return node;
  661. }
  662.  
  663. /*
  664.  *  Ultimate to field , handles basic user security and expands aliases.
  665.  */
  666.  
  667. void
  668. MakeToFixNode (struct List *list, char *str, char *send)
  669. {
  670.     char
  671.         *ptr;
  672.     int
  673.         len,
  674.         c;
  675.  
  676.     PROC ("MakeToFixNode");
  677.     D (("str '%s', send '%s'\n", str ? str : "<none>", send ? send : "<none>"));
  678.  
  679.     while (str < send && (*str == ' ' || *str == '\t'))
  680.         ++str;
  681.     for (ptr = send - 1; ptr >= str && (*ptr == ' ' || *ptr == '\t'); --ptr)
  682.         ;
  683.     ++ptr;
  684.  
  685.     len = ptr - str;
  686.     if (len < 0) {
  687.         D (("exit, len < 0\n"));
  688.         return;
  689.     }
  690.  
  691.     /*
  692.      *  str [0..len-1]
  693.      */
  694.  
  695.     c = str [len];
  696.     str [len] = 0;
  697.  
  698.     if (ROpt) {    /*  disallow remote asking for special options */
  699.         ulog (-1, "Received mail for %s", str);
  700.         if (str [0] == '>' || str [0] == '<' || str [0] == '|') {
  701.             ulog (-1, "bad user %s", str);
  702.             D (("exit, bad user\n"));
  703.             return;
  704.         }
  705.     }
  706.  
  707.     /*
  708.      *  expand aliases.  If the str exists as an alias and the special
  709.      *  :: (do not expand alias in To: field) is used, then the name of
  710.      *  the alias is placed in the To: field.
  711.      */
  712.  
  713.     if (AliasExists (str))
  714.         ForceNoBounce = 1;
  715.  
  716.     if (UserAliasList (str, fixCallBack, list, 1)) {
  717.         struct Node
  718.             *node;
  719.  
  720.         sprintf (ScrBuf, "%s@%s%s", str, NodeName, DomainName);
  721.  
  722.         node = malloc (sizeof (struct Node) + strlen (ScrBuf) + 1);
  723.         if (!node) {
  724.             ulog (-1, "MakeToFixNode: no memory!");
  725.             exit (30);
  726.         }
  727.         node->ln_Pri = 0;
  728.         node->ln_Name = (char *) (node + 1);
  729.         strcpy (node->ln_Name, ScrBuf);
  730.         AddTail (list, node);
  731.         D (("List 0x%lx, added '%s'\n", (long) list, ScrBuf));
  732.     }
  733.  
  734.     ForceNoBounce = 0;
  735.     str [len] = c;
  736.  
  737.     D (("exit\n"));
  738.     return;
  739. }
  740.  
  741. int
  742. fixCallBack (const char *user, struct List *list, int showto)
  743. {
  744.     struct Node
  745.         *node;
  746.  
  747.     PROC ("fixCallBack");
  748.     D (("user '%s', showto %ld\n", user, showto));
  749.  
  750.     if (user [0] == '<') {
  751.         FILE
  752.             *fi = fopen (user + 1, "r");
  753.         char
  754.             *buf = malloc (256);
  755.  
  756.         if (fi == NULL) {
  757.             ulog (-1, "Unable to open < file %s", user + 1);
  758.             D (("exit, can't open '%s'\n", user + 1));
  759.  
  760.             return 0;
  761.         }
  762.         if (!buf) {
  763.             ulog (-1, "fixCallBack: no memory!");
  764.             exit (30);
  765.         }
  766.  
  767.         while (fgets (buf, 256, fi)) {
  768.             int
  769.                 i = 0,
  770.                 j;
  771.  
  772.             while (buf [i] == ' ' || buf [i] == '\t')
  773.                 ++i;
  774.             if (buf [i] == 0 || buf [i] == '\n')
  775.                 continue;
  776.             for (j = i; buf [j] && buf [j] != '\n' && buf [j] != ' ' && buf [j] != '\t'; ++j)
  777.                 ;
  778.             buf [j] = 0;
  779.             UserAliasList (buf, fixCallBack, list, showto);
  780.         }
  781.  
  782.         fclose (fi);
  783.         free (buf);
  784.         D (("exit, read from file\n"));
  785.  
  786.         return 0;
  787.     }
  788.  
  789.     if (showto)
  790.         ulog (-1, "Sending mail to %s", user);
  791.  
  792.     if (user [0] == '\\')
  793.         ++user;
  794.  
  795.     /*
  796.      *  add to Xcc (actual send list).  If showto < 0 then the alias was
  797.      *  given to us for display (To: field display) purposes only and
  798.      *  should NOT be added to the Xcc list
  799.      */
  800.  
  801.     if (showto >= 0) {
  802.         node = malloc (sizeof (struct Node) + strlen (user) + 1);
  803.         if (!node) {
  804.             ulog (-1, "fixCallBack: no memory!");
  805.             exit (30);
  806.         }
  807.         node->ln_Name = (char *) (node + 1);
  808.         node->ln_Pri = ForceNoBounce;
  809.         strcpy (node->ln_Name, user);
  810.         AddTail (&XccList, node);
  811.         D (("List 0x%lx (XccList) added '%s'\n", (long) &XccList, user));
  812.     }
  813.  
  814.     /*
  815.      *  If an alias element is to be shown in the To: field of the
  816.      *  message, do so.  If it is a local user with no qualifications,
  817.      *  then append our full domain name.
  818.      *
  819.      *  do not show any > or | redirections
  820.      */
  821.  
  822.     if (showto && *user != '|' && *user != '>') {
  823.         int
  824.             localFix = 1;
  825.         char
  826.             *ptr;
  827.  
  828.         for (ptr = user; *ptr; ++ptr) {
  829.             if (*ptr == '!' || *ptr == '@' || *ptr == '%' || *ptr == ':') {
  830.                 localFix = 0;
  831.                 break;
  832.             }
  833.         }
  834.         if (localFix)
  835.             sprintf (ScrBuf, "%s@%s%s", user, NodeName, DomainName);
  836.         else
  837.             strcpy (ScrBuf, user);
  838.  
  839.         node = malloc (sizeof (struct Node) + strlen (ScrBuf) + 1);
  840.         if (!node) {
  841.             ulog (-1, "fixCallBack: No memory!");
  842.             exit (30);
  843.         }
  844.         node->ln_Pri = 0;
  845.         node->ln_Name = (char *) (node + 1);
  846.         strcpy (node->ln_Name, ScrBuf);
  847.         AddTail (list, node);
  848.         D (("List 0x%lx added '%s'\n", (long) list, ScrBuf));
  849.     }
  850.  
  851.     D (("exit\n"));
  852.     return 0;
  853. }
  854.  
  855. /*
  856.  *  Integrates a header
  857.  */
  858.  
  859. void
  860. IntegrateHeader (char *hdr, int len)
  861. {
  862.     PROC ("IntegrateHeader");
  863.  
  864.     if (hdr [len - 1] == '\n')     /*  strip trailing newline  */
  865.         hdr [len - 1] = 0;
  866.     D (("header '%s', len %ld\n", hdr, len));
  867.  
  868.     if (strnicmp (hdr, "From:", 5) == 0) {
  869.         MakeNode (&FromList, hdr + 5);
  870.         D (("exit, From\n"));
  871.         return;
  872.     }
  873.  
  874.     if (strnicmp (hdr, "To:", 3) == 0) {
  875.         MakeNode (&ToList, hdr + 3);
  876.         D (("exit, To\n"));
  877.         return;
  878.     }
  879.  
  880.     if (strnicmp (hdr, "Cc:", 3) == 0) {
  881.         MakeNode (&CcList, hdr + 3);
  882.         D (("exit, CC\n"));
  883.         return;
  884.     }
  885.  
  886.     if (strnicmp (hdr, "Bcc:", 4) == 0) {
  887.         MakeNode (&BccList, hdr + 4);
  888.         D (("exit, BCC\n"));
  889.         return;
  890.     }
  891.  
  892.     if (strnicmp (hdr, "Subject:", 8) == 0) {
  893.         MakeNode (&SubjList, hdr + 8);
  894.         D (("exit, Subject\n"));
  895.         return;
  896.     }
  897.  
  898.     if (strnicmp (hdr, "Received:", 9) == 0) {
  899.         MakeNode (&RecvList, hdr + 9);
  900.         D (("exit, Received\n"));
  901.         return;
  902.     }
  903.  
  904.     MakeNode (&HdrList, hdr);
  905.  
  906.     D (("exit\n"));
  907.     return;
  908. }
  909.  
  910. /*
  911.  *  Adds (personal info) to FromList based on passwd entry or, if
  912.  *  that is not available, from the Config entry 'RealName' or
  913.  *  ENV:REALNAME (env:REALNAME takes precedence)
  914.  */
  915.  
  916. void
  917. FromFixup (struct List *list)
  918. {
  919.     struct Node
  920.         *node,
  921.         *nn;
  922.     struct List
  923.         tmpList;
  924.  
  925.     PROC ("FromFixup");
  926.  
  927.     NewList (&tmpList);
  928.  
  929.     while (node = RemHead (list)) {
  930.         /*
  931.          *  FIXME.  use pw_gecos/pw_real_name entry.
  932.          */
  933.         nn = malloc (sizeof (struct Node) + strlen (node->ln_Name) + strlen (RealName) + 16);
  934.         if (!nn) {
  935.             ulog (-1, "FromFixUp: no memory!");
  936.             exit (30);
  937.         }
  938.         nn->ln_Name = (char *) (nn + 1);
  939.         if (strlen (RealName) == 0)
  940.             sprintf (nn->ln_Name, "%s", node->ln_Name);
  941.         else
  942.             sprintf (nn->ln_Name, "%s (%s)", node->ln_Name, RealName);
  943.         free (node);
  944.         AddTail (&tmpList, nn);
  945.     }
  946.  
  947.     while (node = RemHead (&tmpList)) {
  948.         AddTail (list, node);
  949.         D (("List 0x%lx added '%s'\n", list, node->ln_Name));
  950.     }
  951.  
  952.     D (("exit\n"));
  953.     return;
  954. }
  955.  
  956. /*
  957.  *  Converts an unparsed list of names into a list of single address
  958.  *  fields, removing any personal idents from the entries.  These will
  959.  *  be recombined after processing when the data file is written out.
  960.  *
  961.  *  Also expands sendmail aliases (UULib:Aliases) (HACK)
  962.  */
  963.  
  964. void
  965. ToFixup (struct List *list)
  966. {
  967.     struct Node
  968.         *node;
  969.     struct List
  970.         tmpList;
  971.  
  972.     PROC ("ToFixup");
  973.  
  974.     NewList (&tmpList);
  975.  
  976.     while (node = RemHead (list)) {
  977.         char
  978.             *ptr,
  979.             *str = node->ln_Name;
  980.  
  981.         while (*str) {        /*    breakup fields by newline or comma */
  982.             for (ptr = str; *ptr && *ptr != '\n' && *ptr != ','; ++ptr)
  983.                 ;
  984.             MakeToAddrNode (&tmpList, str);
  985.             str = ptr;
  986.             while (*str == '\n' || *str == ',' || *str == ' ' || *str == '\t')
  987.                 ++str;
  988.         }
  989.         free (node);
  990.     }
  991.  
  992.     while (node = RemHead (&tmpList)) {
  993.         AddTail (list, node);
  994.         D (("List 0x%lx added '%s'\n", list, node->ln_Name));
  995.     }
  996.  
  997.     D (("exit\n"));
  998.     return;
  999. }
  1000.  
  1001. /*
  1002.  *  Extracts a single name / address (comma or newline delimited)
  1003.  *  field and creates a new node.
  1004.  */
  1005.  
  1006. void
  1007. MakeToAddrNode (struct List *list, char *str)
  1008. {
  1009.     char
  1010.         *p1,
  1011.         *p2;
  1012.     int
  1013.         ns = 0;       /*  non-whitespace encountered */
  1014.  
  1015.     PROC ("MakeToAddrNode");
  1016.  
  1017.     for (p1 = str; *p1 && *p1 != ',' && *p1 != '\n'; ++p1) {
  1018.         if (*p1 == '(') {   /*  addr (name) OR (name) addr */
  1019.             if (ns) {    /*  addr (name) */
  1020.                 MakeToFixNode (list, str, p1);
  1021.             }
  1022.             else {
  1023.                 while (*p1 && *p1 != ',' && *p1 != '\n' && *p1 != ')')
  1024.                     ++p1;
  1025.                 if (*p1 == ')') {
  1026.                     for (p2 = p1 + 1; *p2 && *p2 != ',' && *p2 != '\n'; ++p2)
  1027.                         ;
  1028.                     MakeToFixNode (list, p1 + 1, p2);
  1029.                 }
  1030.             }
  1031.  
  1032.             D (("exit, '('\n"));
  1033.             return;
  1034.         }
  1035.  
  1036.         if (*p1 == '<') {   /*  <addr>  */
  1037.             for (p2 = p1 + 1; *p2 && *p2 != ',' && *p2 != '\n' && *p2 != '>'; ++p2)
  1038.                 ;
  1039.             if (*p2 == '>')
  1040.                 MakeToFixNode (list, p1 + 1, p2);
  1041.  
  1042.             D (("exit, '<'\n"));
  1043.             return;
  1044.         }
  1045.  
  1046.         if (*p1 != ' ' && *p1 != '\t')
  1047.             ns = 1;
  1048.     }
  1049.  
  1050.     MakeToFixNode (list, str, p1);
  1051.  
  1052.     D (("exit\n"));
  1053.     return;
  1054. }
  1055.  
  1056. /*
  1057.  *  Send mail to <recipiants>
  1058.  *
  1059.  *    -Local mail
  1060.  *    -Machine path (UUCP)
  1061.  */
  1062.  
  1063. FILE *
  1064. SendMailTo (struct List *list, FILE *fi)
  1065. {
  1066.     struct Node
  1067.         *node;
  1068.  
  1069.     PROC ("SendMailTo");
  1070.  
  1071.     for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  1072.         D (("List 0x%lx processing '%s'\n", (long) list, node->ln_Name));
  1073.         fi = OneMailTo (node->ln_Name, fi, node->ln_Pri);
  1074.     }
  1075.  
  1076.     fi = TermMailToUUCP (fi);
  1077.  
  1078.     D (("exit\n"));
  1079.     return fi;
  1080. }
  1081.  
  1082. FILE *
  1083. OneMailTo (char *toaddr, FILE *rfi, int nobounce)
  1084. {
  1085.     int
  1086.         i;
  1087.     char
  1088.         c;
  1089.     static char
  1090.         ToAddr [512],
  1091.         Buf [512],
  1092.         typeBuf [16],
  1093.         classBuf [16],
  1094.         addrBuf [128];
  1095.  
  1096.     PROC ("OneMailTo");
  1097.     D (("toaddr '%s', nobounce %ld\n", toaddr ? toaddr : "<none>", nobounce));
  1098.  
  1099.     if (toaddr [0] == '|') {      /*  pipe through command    */
  1100.         rfi = OneMailToPipe (toaddr + 1, rfi);
  1101.         D (("exit, Pipe\n"));
  1102.         return rfi;
  1103.     }
  1104.  
  1105.     if (toaddr [0] == '>') {      /*  copy to file            */
  1106.         rfi = OneMailToFile (toaddr + 1, rfi);
  1107.         D (("exit, File\n"));
  1108.         return rfi;
  1109.     }
  1110.  
  1111.     strncpy (ToAddr, toaddr, sizeof (ToAddr));
  1112.     ToAddr [sizeof (ToAddr) - 1] = 0;
  1113.  
  1114. loop:
  1115.     for (i = 0; c = ToAddr [i]; ++i) {
  1116.         if (c == '!' || c == '%' || c == '@' || c == ':')
  1117.             break;
  1118.     }
  1119.  
  1120.     if (c == 0) {             /*  local name  */
  1121.         rfi = OneMailToUser (ToAddr, rfi);
  1122.         D (("exit, User\n"));
  1123.         return rfi;
  1124.     }
  1125.  
  1126.     /*
  1127.      *  Non-Local mail
  1128.      */
  1129.  
  1130.     i = ParseAddress (ToAddr, Buf, strlen (ToAddr));
  1131.     /*
  1132.      *  Buf now contains ToAddr converted to a bang-path.
  1133.      *  'i' is the offset in Buf to the first bang (strlen (first-element))
  1134.      */
  1135.  
  1136.     if (DomainLookup (Buf, strlen (Buf), typeBuf, classBuf, addrBuf, nobounce)) {
  1137.         printf ("type %s class %s addr %s ROUTE %s\n", typeBuf, classBuf, addrBuf, Buf);
  1138.  
  1139.         /*
  1140.          *  Note: the distinction between Mail Destination and
  1141.          *      Mail Forwarder is:
  1142.          *
  1143.          *      MD removes the first machine from the rmail line.
  1144.          *
  1145.          *      MF does NOT.
  1146.          */
  1147.  
  1148.         if (stricmp (classBuf, "UU") == 0) {
  1149.             if (stricmp (typeBuf, "MD") == 0) {
  1150.                 rfi = OneMailToUUCP (addrBuf, Buf + i + 1, rfi);
  1151.                 D (("exit, UUCP MD (address '%s', isRMail %ld)\n", Buf + i + 1, isRMail));
  1152.                 return rfi;
  1153.             }
  1154.             else {
  1155.                 /* should be MF - Mail Forwarder */
  1156.                 rfi = OneMailToUUCP (addrBuf, Buf, rfi);
  1157.                 D (("exit, UUCP, type should be MF (is '%s')\n", typeBuf));
  1158.                 return rfi;
  1159.             }
  1160.         }
  1161.         else
  1162.         if (stricmp (classBuf, "LL") == 0) {  /*  local mail, loop */
  1163.             for (i = 0; Buf [i] && Buf [i] != '!'; ++i)
  1164.                 ;
  1165.  
  1166.             if (Buf [i] == 0) {
  1167.                 strcpy (Buf + i, "postmaster");
  1168.                 --i;
  1169.             }
  1170.             strcpy (ToAddr, Buf + i + 1);
  1171.  
  1172.             D (("local loop, addr '%s'\n", ToAddr));
  1173.             goto loop;
  1174.         }
  1175.         else
  1176.         if (stricmp (classBuf, "NOHOST") == 0) { /* negative match */
  1177.             BounceMail(rfi, "Host Unknown", "No known path to host", Buf);
  1178.             return rfi;
  1179.         }
  1180.         else {
  1181.             ulog (-1, "Unsupported domain class: %s", classBuf);
  1182.             fprintf (stderr, "Unsupported domain class: %s\n", classBuf);
  1183.         }
  1184.  
  1185.         D (("exit, unknown domain class for destination\n"));
  1186.         return rfi;
  1187.     }
  1188.  
  1189.     /*
  1190.      *  handle bounced mail here.  We only reach this point if BounceMode
  1191.      *  was enabled (only way the DomainLookup() could return 0)
  1192.      *
  1193.      *  Include the headers and first few lines of the message in the
  1194.      *  bounced mail.  Do not bounce mail from mailer-daemon
  1195.      */
  1196.  
  1197.     if (!BounceMail (rfi, "Host Unknown", "No known path to host", Buf)) {
  1198.         ulog (-1, "Could not find domain for %s, no mail sent", Buf);
  1199.         fprintf (stderr, "Unable to send mail to %s\n", Buf);
  1200.     }
  1201.  
  1202.     D (("exit\n"));
  1203.     return rfi;
  1204. }
  1205.  
  1206. char *
  1207. BounceMail (FILE *rfi, char *errsubj, char *errtxt, char *name)
  1208. {
  1209.     char
  1210.         *from;
  1211.  
  1212.     if (from = FindHeader ("From:")) {
  1213.         if (stristr (from, "mailer-daemon")) {
  1214.             /* prevent loops */
  1215.             ulog (-1, "Received mailer-daemon bounce: %s", from);
  1216.         }
  1217.         else {
  1218.             DoBounceMail(rfi, errsubj, errtxt, name, FALSE);
  1219.  
  1220.             if (CcPmBounceOpt) {
  1221.                 /* Postmaster copy */
  1222.                 DoBounceMail(rfi, errsubj, errtxt, name, TRUE);
  1223.             }
  1224.         }
  1225.     }
  1226.  
  1227.     return from;
  1228. }
  1229.  
  1230. void
  1231. DoBounceMail (FILE *rfi, char *errsubj, char *errtxt, char *name, int ispmcopy)
  1232. {
  1233.     char
  1234.         *from;
  1235.  
  1236.     if ((from = FindHeader ("Sender:")) || (from = FindHeader ("From:"))) {
  1237.         FILE
  1238.             *fo;
  1239.         long
  1240.             pos = ftell (rfi);
  1241.  
  1242.         /*
  1243.          *  return mail to sender
  1244.          */
  1245.  
  1246.         strcpy (ScrBuf2, TmpFileName ("t:bounce"));
  1247.         if (fo = fopen (ScrBuf2, "w")) {
  1248.             fprintf (fo, "From: MAILER-DAEMON@%s%s\n", NodeName, DomainName);
  1249.  
  1250.             if (ispmcopy) {
  1251.                 fprintf (fo, "To: postmaster@%s%s\n", NodeName, DomainName);
  1252.             }
  1253.             else {
  1254.                 fprintf (fo, "To: %s\n", from);
  1255.             }
  1256.  
  1257.             fprintf (fo, "Subject: Returned mail: %s\n", errsubj);
  1258.             fprintf (fo, "Precedence: junk\n");
  1259.  
  1260.             if (ispmcopy) {
  1261.                 fprintf (fo, "Sender: %s\n", from);
  1262.             }
  1263.             else {
  1264.                 fprintf (fo, "Sender: postmaster@%s%s\n", NodeName, DomainName);
  1265.             }
  1266.  
  1267.             fprintf (fo, "\n   ----- Error summary follows -----\n");
  1268.             fprintf (fo, "%s... %s\n", name, errtxt);
  1269.             fprintf (fo, "Message returned to sender.\n\n");
  1270.  
  1271.             if (ispmcopy) {
  1272.                 fprintf (fo, "   ----- Message headers follow -----\n");
  1273.  
  1274.                 DumpHeaderInfo (fo, RCVR_SENDMAIL, 0, 0, "");
  1275.             }
  1276.             else {
  1277.                 fprintf(fo, "   ----- Unsent message follows -----\n");
  1278.  
  1279.                 DumpHeaderInfo (fo, RCVR_SENDMAIL, 0, 0, "");
  1280.  
  1281.                 while (fgets (ScrBuf, sizeof (ScrBuf), rfi)) {
  1282.                     fputs (ScrBuf, fo);
  1283.                 }
  1284.             }
  1285.             fclose (fo);
  1286.             sprintf (ScrBuf, "sendmail -R \"Mail Delivery Subsystem\" <%s", ScrBuf2);
  1287.             system (ScrBuf);
  1288.         }
  1289.  
  1290.         fseek (rfi, pos, 0);
  1291.         remove (ScrBuf2);
  1292.     }
  1293.  
  1294.     return;
  1295. }
  1296.  
  1297. FILE *
  1298. OneMailToPipe (char *toaddr, FILE *rfi)
  1299. {
  1300.     FILE
  1301.         *fi;
  1302.     char
  1303.         *ptr;
  1304.     static long
  1305.         pos = 0;
  1306.  
  1307.     PROC ("OneMailToPipe");
  1308.     D (("toaddr '%s'\n", toaddr ? toaddr : "<none>"));
  1309.  
  1310.     if (TempFileBuf [0] == 0) {
  1311.         strcpy (TempFileBuf, TmpFileName ("T:pipe"));
  1312.         fi = fopen (TempFileBuf, "w");
  1313.         if (fi == NULL) {
  1314.             ulog (-1, "Unable to open temp file %s for command: %s", TempFileBuf, toaddr);
  1315.             D (("exit, can't open '%s'\n", TempFileBuf));
  1316.             return rfi;
  1317.         }
  1318.         DumpHeaderInfo (fi, RCVR_SENDMAIL, 0, 1, "");
  1319.         pos = ftell (fi);
  1320.  
  1321.         while (fgets (ScrBuf, sizeof (ScrBuf), rfi)) {
  1322.             if (ScrBuf [0] == 'F' && strncmp (ScrBuf, "From ", 5) == 0)
  1323.                 strins (ScrBuf, ">");
  1324.             fputs (ScrBuf, fi);
  1325.         }
  1326.         if (LogMail)
  1327.             MailSize = ftell (fi);
  1328.         fclose (fi);
  1329.     }
  1330.     strcpy (ScrBuf, toaddr);
  1331.  
  1332.     ptr = toaddr;
  1333.     if (strnicmp (toaddr, "run", 3) == 0) {
  1334.         ptr += 3;
  1335.         while (*ptr == ' ' || *ptr == '\t')
  1336.             ++ptr;
  1337.     }
  1338.     while (*ptr && *ptr != ' ' && *ptr != '\t')
  1339.         ++ptr;
  1340.  
  1341.     if (*ptr == 0)
  1342.         strcat(ScrBuf, " ");
  1343.  
  1344.     sprintf (ScrBuf + (ptr - toaddr + 1), "<%s %s", TempFileBuf, ptr);
  1345.     D (("Command: '%s'\n", ScrBuf));
  1346.  
  1347.     if (Execute (ScrBuf, 0, 0) == 0)
  1348.         ulog (-1, "Couldn't execute %s", ScrBuf);
  1349.  
  1350.     fi = fopen (TempFileBuf, "r");
  1351.     if (fi) {
  1352.         if (rfi != stdin)
  1353.             fclose (rfi);
  1354.         rfi = fi;
  1355.         fseek (rfi, pos, 0);
  1356.     }
  1357.     else {
  1358.         ulog (-1, "Couldn't reopen temp '%s', mail failed!", TempFileBuf);
  1359.         rfi = stdin;
  1360.     }
  1361.  
  1362.     D (("exit\n"));
  1363.     return rfi;
  1364. }
  1365.  
  1366. FILE *
  1367. OneMailToUser (char *toaddr, FILE *rfi)
  1368. {
  1369.     char
  1370.         filename [512],
  1371.         mybuf [512],
  1372.         mybuf2 [512],
  1373.         *p;
  1374.  
  1375.     PROC ("OneMailToUser");
  1376.     D (("toaddr '%s'\n", toaddr ? toaddr : "<none>"));
  1377.  
  1378.     for (p = toaddr; *p; p++) {
  1379.         if (strchr ("`'\"/: <>", *p)) {
  1380.             if (UserBounceOpt)
  1381.                 BounceMail (rfi, "Invalid address", "Illegal character in username", toaddr);
  1382.             else
  1383.                 ulog (-1, "%s: invalid character in name", toaddr);
  1384.             return (rfi);
  1385.         }
  1386.     }
  1387.  
  1388.     ++Notify;
  1389.  
  1390.     if (CheckUser) {
  1391.         FILE
  1392.             *fi;
  1393.         int
  1394.             retcode;
  1395.  
  1396.         strcpy (filename, TmpFileName ("T:pipe"));
  1397.         sprintf (mybuf, "%s \"%s\" >%s", CheckUser, toaddr, filename);
  1398.         if (retcode = system (mybuf)) {
  1399.             if (UserBounceOpt) {
  1400.                 fi = fopen (filename, "r");
  1401.                 if (fi == NULL) {
  1402.                     ulog (-1, "Unable to open temp file %s for command: %s", filename, CheckUser);
  1403.                     return rfi;
  1404.                 }
  1405.  
  1406.                 fgets (mybuf2, sizeof (mybuf2), fi);
  1407.                 fclose (fi);
  1408.                 unlink (filename);
  1409.  
  1410.                 sprintf (mybuf, "CheckUser failed: %s", mybuf2);
  1411.                 mybuf [strlen (mybuf) - 1] = '\0'; /* kill that darned newline */
  1412.                 BounceMail (rfi, "Delivery failure", mybuf, toaddr);
  1413.                 return rfi;
  1414.             }
  1415.             else {
  1416.                 ulog (-1, "%s (Config file CheckUser command) returned %d", CheckUser, retcode);
  1417.                 unlink (filename);
  1418.                 return rfi;
  1419.             }
  1420.         }
  1421.  
  1422.         fi = fopen (filename, "r");
  1423.         if (fi == NULL) {
  1424.             ulog (-1, "Unable to open temp file %s for command '%s'", filename, CheckUser);
  1425.             return rfi;
  1426.         }
  1427.  
  1428.         fgets (mybuf, sizeof (mybuf), fi);
  1429.         fclose (fi);
  1430.         unlink (filename);
  1431.  
  1432.         mybuf [strlen (mybuf) - 1] = '\0'; /* kill that darned newline */
  1433.         toaddr = mybuf;
  1434.     }
  1435.     else {
  1436.         strcpy (ScrBuf, MakeConfigPath (UUMAIL, toaddr));
  1437.         toaddr = ScrBuf;
  1438.     }
  1439.  
  1440.     if (toaddr [0] != '*') {
  1441.         return OneMailToFile (toaddr, rfi);
  1442.     }
  1443.  
  1444.     /* error */
  1445.     if (UserBounceOpt)
  1446.         BounceMail (rfi, "User unknown", "User unknown", toaddr + 1);
  1447.     else
  1448.         ulog (-1, "No such user '%s', no mail sent", toaddr + 1);
  1449.  
  1450.  
  1451.     D (("exit, error from CheckUser '%s'\n", toaddr));
  1452.     return rfi;
  1453. }
  1454.  
  1455. FILE *
  1456. OneMailToFile (char *tofile, FILE *rfi)
  1457. {
  1458.     FILE
  1459.         *fo;
  1460.     static char
  1461.         DataFile [128];
  1462.     long
  1463.         pos;
  1464.  
  1465.     PROC ("OneMailToFile");
  1466.     D (("tofile '%s'\n", tofile ? tofile : "<none>"));
  1467.  
  1468.     strcpy (DataFile, tofile);
  1469.  
  1470.     LockFile (DataFile);
  1471.  
  1472.     fo = fopen (DataFile, "a");
  1473.     if (fo == NULL) {
  1474.         D (("couldn't open '%s'\n", DataFile));
  1475.         strcpy (DataFile, "T:MailOverflow");
  1476.         fo = fopen (DataFile, "a");
  1477.         if (fo)
  1478.             ulog (-1, "Could not append to %s, appending to %s", tofile, DataFile);
  1479.         else
  1480.             ulog (-1, "Can't append to anywhere! (%s)", tofile);
  1481.     }
  1482.  
  1483.     if (fo) {
  1484.         DumpHeaderInfo (fo, RCVR_SENDMAIL, 0, 1, "");
  1485.         pos = ftell (fo);
  1486.         while (fgets (ScrBuf, sizeof (ScrBuf), rfi)) {
  1487.             if (ScrBuf [0] == 'F' && strncmp (ScrBuf, "From ", 5) == 0)
  1488.                 strins (ScrBuf, ">");
  1489.             if (LogMail)
  1490.                 MailSize = ftell (fo);
  1491.             fputs (ScrBuf, fo);
  1492.         }
  1493.  
  1494.         if (ScrBuf [0] != '\n')
  1495.             fputs ("\n", fo);
  1496.         fclose (fo);
  1497.         if (rfi != stdin)
  1498.             fclose (rfi);
  1499.         rfi = fopen (DataFile, "r");
  1500.         fseek (rfi, pos, 0);
  1501.     }
  1502.  
  1503.     UnLockFile (DataFile);
  1504.  
  1505.     D (("exit\n"));
  1506.     return rfi;
  1507. }
  1508.  
  1509. /*
  1510.  *  UUCP MAILER.  Generate a control node for each destination.  When the
  1511.  *  mail is terminated, a batch file will be created for each destination
  1512.  *  host.
  1513.  */
  1514.  
  1515. FILE *
  1516. OneMailToUUCP (char *toaddr, char *skipaddr, FILE *rfi)
  1517. {
  1518.     UUHostNode
  1519.         *uh;
  1520.     struct Node
  1521.         *node;
  1522.     int
  1523.         i,
  1524.         j,
  1525.         hostLen,
  1526.         maxRMailLen = atoi (GetConfig (MAXRMAILLEN, "0"));
  1527.  
  1528.     PROC ("OneMailToUUCP");
  1529.     D (("toaddr '%s', skipaddr '%s'\n", toaddr ? toaddr : "<none>", skipaddr ? skipaddr : "<none>"));
  1530.  
  1531.     /*
  1532.      *  find host, first element of 'toaddr'
  1533.      */
  1534.  
  1535. loop:
  1536.     if (Strip_UUCP) {
  1537.         for (i = 0; toaddr [i] && toaddr [i] != '!'; ++i)
  1538.         /*for (i = 0; toaddr [i] && toaddr [i] != '!' && i != 7; ++i) CUTNODENAME */
  1539.             ;
  1540.         j = strlen (toaddr);
  1541.         if (j > 5 && toaddr [j - 5] == '.' && strnicmp (&toaddr [j - 4], "uucp", 4) == 0)
  1542.             i = j;
  1543.     }
  1544.     else
  1545.         for (i = 0; toaddr [i] && toaddr [i] != '!' && toaddr [i] != '.'; ++i)
  1546.         /*for (i = 0; toaddr [i] && toaddr [i] != '!' && toaddr [i] != '.' && i != 7; ++i) CUTNODENAME */
  1547.             ;
  1548.  
  1549.     D (("after search, i %ld, toaddr [i] = 0x%lx\n", i, (toaddr [i] & 0xff)));
  1550.  
  1551.     /*
  1552.      *  search for UUHostNode in UUHostList, append to node list for
  1553.      *  rmail line.
  1554.      */
  1555.  
  1556.     uh = NULL;
  1557.     for (node = UUHostList.lh_Head; node->ln_Succ; node = node->ln_Succ) {
  1558.         if (strlen (node->ln_Name) == i && strnicmp (node->ln_Name, toaddr, i) == 0) {
  1559.             uh = (UUHostNode *) node;
  1560.             break;
  1561.         }
  1562.     }
  1563.  
  1564.     D (("after HostList scan, uh = 0x%lx\n", uh));
  1565.  
  1566.     if (uh == NULL) {
  1567.         uh = malloc (sizeof (UUHostNode) + i + 1);
  1568.         if (!uh) {
  1569.             ulog (-1, "OneMailToUUCP: no memory!");
  1570.             exit (30);
  1571.         }
  1572.         uh->uh_Node.ln_Name = (char *) (uh + 1);
  1573.         uh->uh_Len = 10;    /*    'C rmail \0' == 9  */
  1574.         uh->uh_NAddr = 0;
  1575.         strncpy (uh->uh_Node.ln_Name, toaddr, i);
  1576.         uh->uh_Node.ln_Name [i] = 0;
  1577.         AddTail (&UUHostList, &uh->uh_Node);
  1578.         NewList (&uh->uh_List);
  1579.         D (("List 0x%lx (UUHostList) added '%s'\n", &UUHostList, uh->uh_Node.ln_Name));
  1580.     }
  1581.  
  1582.     while (toaddr [i] && toaddr [i] != '!')
  1583.         ++i;
  1584.     if (toaddr [i] == '!')
  1585.         ++i;
  1586.  
  1587.     hostLen = strlen (toaddr + i) + strlen (skipaddr) + 3;
  1588.     D (("hostLen %ld\n", hostLen));
  1589.  
  1590.     if (uh->uh_NAddr > 0 && uh->uh_Len + hostLen > maxRMailLen) {
  1591.         rfi = TermMailToUUCP (rfi);
  1592.         goto loop;
  1593.     }
  1594.  
  1595.     node = malloc (sizeof (struct Node) + hostLen + 1);
  1596.     if (!node) {
  1597.         ulog (-1, "OneMailToUUCP: no memory!");
  1598.         exit (30);
  1599.     }
  1600.     node->ln_Pri = 0;
  1601.     node->ln_Name = (char *) (node + 1);
  1602.     AddTail (&uh->uh_List, node);
  1603.  
  1604.     if (toaddr [i]) {
  1605.         sprintf (node->ln_Name, "%s!%s", toaddr + i, skipaddr);
  1606.     }
  1607.     else {
  1608.         sprintf (node->ln_Name, "%s", skipaddr);
  1609.     }
  1610.     D (("List 0x%lx (uh_List) added '%s'\n", &uh->uh_List, node->ln_Name));
  1611.  
  1612.     uh->uh_NAddr++;
  1613.     uh->uh_Len += strlen (node->ln_Name) + 1;    /*  inc space */
  1614.  
  1615.     D (("exit\n"));
  1616.     return rfi;
  1617. }
  1618.  
  1619.  
  1620. FILE *
  1621. TermMailToUUCP (FILE *rfi)
  1622. {
  1623.     UUHostNode
  1624.         *uh;
  1625.     int
  1626.         pos;
  1627.     char
  1628.         *uux = GetConfigProgram (UUX),
  1629.         *receivers = NULL,
  1630.         *tmp;
  1631.     static FILE
  1632.         *ml = NULL;
  1633.  
  1634.     PROC ("TermMailToUUCP");
  1635.  
  1636.     /*
  1637.     ** build copy of file
  1638.     */
  1639.  
  1640.     if (TempFileBuf [0] == '\0') {
  1641.         FILE
  1642.             *fi;
  1643.  
  1644.         tmp = TmpFileName ("T:Mail");
  1645.         strcpy (TempFileBuf, tmp);
  1646.  
  1647.         fi = fopen (tmp, "w");
  1648.         if (!fi) {
  1649.             ulog (-1, "Error, Can't open %s", tmp);
  1650.             D (("exit, can't open '%s'\n", tmp));
  1651.             return rfi;
  1652.         }
  1653.  
  1654.         DumpHeaderInfo (fi, RCVR_UUCP, 1, 0, "");
  1655.         pos = ftell (fi);
  1656.  
  1657.         while (fgets (ScrBuf, sizeof (ScrBuf), rfi)) {
  1658.             if (ScrBuf [0] == 'F' && strncmp (ScrBuf, "From ", 5) == 0)
  1659.                 strins (ScrBuf, ">");
  1660.             fputs (ScrBuf, fi);
  1661.         }
  1662.         if (LogMail)
  1663.             MailSize = ftell (fi);
  1664.         fclose (fi);
  1665.         if (rfi != stdin)
  1666.             fclose (rfi);
  1667.         fi = fopen (tmp, "r");
  1668.         fseek (fi, pos, 0);
  1669.         rfi = fi;
  1670.     }
  1671.     else
  1672.         tmp = TempFileBuf;
  1673.  
  1674.     if (LogMail && !ml) {
  1675.         ml = fopen (MailLog, "a");
  1676.         if (!ml)
  1677.             ulog (-1, "Could not open MailLog file '%s'", MailLog);
  1678.     }
  1679.  
  1680.     /*
  1681.     ** spool to deliver file
  1682.     */
  1683.  
  1684.     while (uh = (struct UUHostNode *) RemHead ((struct List *) &UUHostList)) {
  1685.         struct List
  1686.             *list;
  1687.         struct Node
  1688.             *node;
  1689.         char
  1690.             *sys,
  1691.             *cmd;
  1692.         int
  1693.             rslt,
  1694.             totlen = 0;
  1695.  
  1696.         sys = uh->uh_Node.ln_Name;
  1697.         D (("scanning for system '%s'\n", sys));
  1698.  
  1699.         list = &uh->uh_List;
  1700.  
  1701.         for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  1702.             D (("looking at space for '%s'\n", node->ln_Name ? node->ln_Name : "<beats me>"));
  1703.             totlen += strlen (node->ln_Name) + 1;
  1704.         }
  1705.  
  1706.         totlen += strlen (uux) + strlen (sys) + strlen (tmp) + 50;
  1707.         D (("total calculated cmd length %ld\n", totlen));
  1708.  
  1709.         cmd = malloc (totlen);
  1710.         if (!cmd) {
  1711.             ulog (-1, "TermMailToUUCP: Failed, No memory for UUX!");
  1712.             return rfi;
  1713.         }
  1714.  
  1715.         if (ml) {
  1716.             receivers = malloc (totlen);
  1717.             if (!receivers) {
  1718.                 ulog (-1, "TermMailToUUCP: No memory to log!");
  1719.             }
  1720.         }
  1721.  
  1722.         sprintf (cmd, "%s -g A %s \"%s!rmail", uux, tmp, sys);
  1723.  
  1724.         if (receivers)
  1725.             strcpy (receivers, "");
  1726.  
  1727.         for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  1728.             strcat (cmd, " ");
  1729.             strcat (cmd, node->ln_Name);
  1730.             if (receivers) {
  1731.                 strcat (receivers, " ");
  1732.                 strcat (receivers, node->ln_Name);
  1733.             }
  1734.         }
  1735.         strcat (cmd, "\"");
  1736.  
  1737.         D (("actual command length %ld\n", strlen (cmd)));
  1738.         D (("actual command '%s'\n", cmd));
  1739.         ulog (2, "UUX command '%s'", cmd);
  1740.  
  1741.         rslt = system (cmd);
  1742.  
  1743.         D (("command result %ld\n", rslt));
  1744.         ulog (2, "UUX command result %ld", rslt);
  1745.  
  1746.         free (cmd);
  1747.         if (receivers) {
  1748.             /* LogMail and ml will also be set */
  1749.             fprintf (ml, "%s %s %s %ld %s%s\n",
  1750.                 Feed,
  1751.                 FromSystem,
  1752.                 FromUser,
  1753.                 MailSize,
  1754.                 sys,
  1755.                 receivers
  1756.             );
  1757.             fflush (ml);
  1758.             free (receivers);
  1759.             receivers = NULL;
  1760.         }
  1761.     }
  1762.  
  1763.     D (("exit\n"));
  1764.     return rfi;
  1765. }
  1766.  
  1767. void
  1768. DumpHeaderInfo (FILE *fi, int rcvr, int resend, int local, char *prestr)
  1769. {
  1770.     PROC ("DumpHeaderInfo");
  1771.     D (("rcvr %ld, resend %ld, local %ld, prestr '%s'\n",
  1772.         rcvr, resend, local, prestr ? prestr : "<none>"));
  1773.     /*
  1774.      *  Write header info
  1775.      */
  1776.  
  1777.     if (ROpt && FromLine [0]) {
  1778.         if (resend && SmartUUCP == 0)
  1779.             fprintf (fi, "%s%s %s remote from %s%s\n", prestr, FromLine, atime(&T), NodeName, DomainPath);
  1780.         else
  1781.             fprintf (fi, "%s%s %s\n", prestr, FromLine, atime (&T));
  1782.     }
  1783.     else {
  1784.         if (local)
  1785.             fprintf (fi, "%sFrom %s %s\n", prestr, UserName, atime (&T));
  1786.         else
  1787.             if (SmartUUCP)
  1788.                 fprintf (fi, "%sFrom %s@%s%s %s\n", prestr, UserName, NodeName, DomainName, atime (&T));
  1789.             else
  1790.                 fprintf (fi, "%sFrom %s %s remote from %s%s\n", prestr, UserName, atime (&T), NodeName, DomainPath);
  1791.     }
  1792.  
  1793.     fprintf (fi, "%sReceived: by %s%s ("
  1794.              VERSION
  1795.              "/Amiga)\n\t  id <%s@%s%s>; %s\n",
  1796.         prestr, NodeName, DomainName, SeqToName (TopSeq),
  1797.         NodeName, DomainName, atime (&T)
  1798.     );
  1799.  
  1800.     DumpHeader (fi, "Received:", &RecvList, prestr);
  1801.  
  1802.     if (ROpt == 0) {
  1803.         if (FindHeader ("Date:") == NULL) {
  1804.             D (("Added Date: header\n"));
  1805.             fprintf (fi, "%sDate: %s\n", prestr, atime (&T));
  1806.         }
  1807.  
  1808.         if (FindHeader ("Message-Id:") == NULL) {
  1809.             time_t
  1810.                 t2 = T + 3600 * GetHourOffset (TimeZoneName);
  1811.             struct tm
  1812.                 *ut;
  1813.  
  1814.             D (("Added Message-ID header\n"));
  1815.             ut = localtime (&t2);
  1816.  
  1817.             fprintf (fi, "%sMessage-Id: <%02d%02d%02d%02d%02d.%s@%s%s>\n",
  1818.                 prestr,
  1819.                 ut->tm_year % 100, ut->tm_mon + 1, ut->tm_mday,
  1820.                 ut->tm_hour, ut->tm_min,
  1821.                 SeqToName (TopSeq), NodeName, DomainName
  1822.             );
  1823.         }
  1824.     }
  1825.  
  1826.     /*
  1827.      *  From:, To:, Cc:, Subject: (Bcc: never written to header),
  1828.      *  and any other header fields
  1829.      */
  1830.  
  1831.     DumpHeader (fi, NULL, &HdrList, prestr);
  1832.     DumpHeaderLast (fi, "From:", &FromList, prestr);
  1833.     DumpCombineHeader (fi, "To:", &ToList, prestr);
  1834.  
  1835.     if (!IsListEmpty (&CcList))
  1836.         DumpCombineHeader (fi, "Cc:", &CcList, prestr);
  1837.  
  1838.     DumpHeaderLast (fi, "Subject:", &SubjList, prestr);
  1839.  
  1840.     fprintf (fi, "\n");
  1841.  
  1842.     D (("exit\n"));
  1843.     return;
  1844. }
  1845.  
  1846. void
  1847. DumpHeader (FILE *fi, char *field, struct List *list, char *prestr)
  1848. {
  1849.     struct Node
  1850.         *node;
  1851.  
  1852.     PROC ("DumpHeader");
  1853.     D (("field '%s', prestr '%s'\n", field ? field : "<none>", prestr ? prestr : "<none>"));
  1854.  
  1855.     if (IsListEmpty (list)) {
  1856.         D (("exit, empty list\n"));
  1857.         return;
  1858.     }
  1859.  
  1860.     for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  1861.         if (field)
  1862.             fprintf (fi, "%s%s %s\n", prestr, field, node->ln_Name);
  1863.         else
  1864.             fprintf (fi, "%s%s\n", prestr, node->ln_Name);
  1865.     }
  1866.  
  1867.     D (("exit\n"));
  1868.     return;
  1869. }
  1870.  
  1871. void
  1872. DumpHeaderLast (FILE *fi, char *field, struct List *list, char *prestr)
  1873. {
  1874.     struct Node
  1875.         *node;
  1876.  
  1877.     PROC ("DumpHeaderLast");
  1878.     D (("field '%s', prestr '%s'\n", field ? field : "<none>", prestr ? prestr : "<none>"));
  1879.  
  1880.     if (IsListEmpty (list)) {
  1881.         D (("exit, empty list\n"));
  1882.         return;
  1883.     }
  1884.  
  1885.     if (node = list->lh_TailPred) {
  1886.         if (field)
  1887.             fprintf (fi, "%s%s %s\n", prestr, field, node->ln_Name);
  1888.         else
  1889.             fprintf (fi, "%s%s\n", prestr, node->ln_Name);
  1890.         D (("exit, returned %s\n", field ? field : "<none>"));
  1891.     }
  1892. #ifdef PROCDEBUG
  1893.     else {
  1894.         D (("exit, empty node for field %s\n", field));
  1895.     }
  1896. #endif
  1897.  
  1898.     return;
  1899. }
  1900.  
  1901. char *
  1902. FindHeader (char *field)
  1903. {
  1904.     struct Node
  1905.         *node;
  1906.     char
  1907.         *ptr = NULL;
  1908.     int
  1909.         len = strlen (field);
  1910.  
  1911.     PROC ("FindHeader");
  1912.     D (("field '%s'\n", field ? field : "<none>"));
  1913.  
  1914.     for (node = HdrList.lh_Head; node->ln_Succ; node = node->ln_Succ) {
  1915.         if (strnicmp (node->ln_Name, field, len) == 0) {
  1916.             ptr = node->ln_Name;
  1917.             break;
  1918.         }
  1919.     }
  1920.  
  1921.     if (ptr == NULL && !IsListEmpty (&FromList)) {
  1922.         node = FromList.lh_TailPred;
  1923.         if (strnicmp ("From:", field, len) == 0)
  1924.             ptr = node->ln_Name - len;
  1925.     }
  1926.  
  1927.     if (ptr == NULL && !IsListEmpty (&SubjList)) {
  1928.         node = SubjList.lh_TailPred;
  1929.         if (strnicmp ("Subject:", field, len) == 0)
  1930.             ptr = node->ln_Name - len;
  1931.     }
  1932.  
  1933.     if (ptr) {
  1934.         ptr += len;
  1935.         while (*ptr == ' ' || *ptr == '\t')
  1936.             ++ptr;
  1937.     }
  1938.  
  1939. #ifdef PROCDEBUG
  1940.     if (!ptr) {
  1941.         D (("exit, returning NULL ptr\n"));
  1942.     }
  1943.     else {
  1944.         D (("exit, returning '%s'\n", ptr));
  1945.     }
  1946. #endif
  1947.     return ptr;
  1948. }
  1949.  
  1950. void
  1951. DumpCombineHeader (FILE *fi, char *field, struct List *list, char *prestr)
  1952. {
  1953.     struct Node
  1954.         *node;
  1955.     int
  1956.         ci = 0;
  1957.  
  1958.     PROC ("DumpCombineHeader");
  1959.     D (("field '%s', prestr '%s'\n", field ? field : "<none>", prestr ? prestr : "<none>"));
  1960.  
  1961.     fprintf (fi, "%s%s ", prestr, field);
  1962.  
  1963.     if (IsListEmpty (list)) {
  1964.         fprintf (fi, "\n");
  1965.         D (("exit, empty list\n"));
  1966.         return;
  1967.     }
  1968.  
  1969.     for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  1970.         if (ci && ci + strlen (node->ln_Name) > 70) {
  1971.             fprintf (fi, ",\n%s\t", prestr);
  1972.             ci = 0;
  1973.         }
  1974.         if (ci)
  1975.             fprintf (fi, ", ");
  1976.         fprintf (fi, "%s", node->ln_Name);
  1977.         ci += strlen (node->ln_Name) + 2;
  1978.     }
  1979.     fprintf (fi, "\n");
  1980.  
  1981.     D (("exit\n"));
  1982.     return;
  1983. }
  1984.  
  1985. int
  1986. GetHourOffset (char *tz)
  1987. {
  1988.     int
  1989.         i;
  1990.  
  1991.     static struct {
  1992.         char *Name;
  1993.         int Hours;
  1994.     } TZAry [] = {
  1995.         "GMT",  0,
  1996.         "UT",   0,
  1997.         "UTC",  0,
  1998.         "PST",  8,
  1999.         "MST",  7,
  2000.         "CST",  6,
  2001.         "EST",  5,
  2002.         "AST",  4,
  2003.         "PDT",  7,
  2004.         "MDT",  6,
  2005.         "CDT",  5,
  2006.         "EDT",  4,
  2007.         "ADT",  3,
  2008.         "CET",  -1,
  2009.         "MET",  -1,     /*  alternate, please use CET   */
  2010.         "MEZ",  -1,     /*  alternate, please use CET   */
  2011.         "CED",  -2,     /*  central european daylight saving time   */
  2012.         "CEDT", -2,     /*  alternate                   */
  2013.         "MED",  -2,     /*  alternate, please use CED   */
  2014.         "CEST", -2,     /*  alternate, please use CED   */
  2015.         "MESZ", -2,     /*  alternate, please use CED   */
  2016.         "EET",  -2,     /*  ??                          */
  2017.         "JST",  -9,
  2018.         "HST",  -10,    /*  Hawaiian Sandard Time       */
  2019.         NULL, 0
  2020.     };
  2021.  
  2022.     PROC ("GetHourOffset");
  2023.     D (("tz = '%s'\n", tz));
  2024.  
  2025.     if (tz [0] == '+' || tz [0] == '-') {
  2026.         int
  2027.             i = ((tz [1] - '0') * 10) + (tz [2] - '0');
  2028.  
  2029.         /* Unfortunately, we don't deal with partial timezones - FIXME */
  2030.         if (tz [0] == '-')
  2031.             i = 0 - i;
  2032.  
  2033.         D (("exit, i %ld\n", i));
  2034.         return i;
  2035.     }
  2036.  
  2037.     for (i = 0; TZAry [i].Name; ++i) {
  2038.         if (strncmp (tz, TZAry [i].Name, 3) == 0) {
  2039.             D (("exit, %ld\n", TZAry [i].Hours));
  2040.             return TZAry [i].Hours;
  2041.         }
  2042.     }
  2043.  
  2044.     ulog (-1, "Unknown Timezone: %s", tz);
  2045.     fprintf (stderr, "Unknown Timezone: %s\n", tz);
  2046.  
  2047.     D (("exit, unknown, returning 6\n"));
  2048.     return 6;
  2049. }
  2050.  
  2051. void
  2052. PostPend (char *str, int frend)
  2053. {
  2054.     char
  2055.         *ptr;
  2056.  
  2057.     PROC ("PostPend");
  2058.     D (("str '%s', frend %ld\n", str, frend));
  2059.  
  2060.     if (frend) {
  2061.         ptr = str + strlen(str);
  2062.         while (ptr > str && *ptr != ' ' && *ptr != '\t') {
  2063.             if (*ptr == '\n')
  2064.                 *ptr = 0;
  2065.             --ptr;
  2066.         }
  2067.         str = ptr + 1;
  2068.     }
  2069.  
  2070.     for (ptr = str; *ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '\n'; ++ptr)
  2071.         ;
  2072.  
  2073.     if (frend)
  2074.         *ptr++ = '!';
  2075.     *ptr = 0;
  2076.     for (ptr = FromLine + 5; *ptr && *ptr != ' ' && *ptr != '\t'; ++ptr)
  2077.         ;
  2078.     strins (ptr, str);
  2079.  
  2080.     D (("exit\n"));
  2081.     return;
  2082. }
  2083.  
  2084. /*
  2085.  *    Parse the from line and figure out Feed, FromSystem, FromUser.
  2086.  */
  2087.  
  2088. void
  2089. FindSource (const char *line)
  2090. {
  2091.     char
  2092.         *path,
  2093.         *p,
  2094.         *templine,
  2095.         buf [256];
  2096.  
  2097.     templine = strdup (line);
  2098.     (void) strtok (templine, " ");
  2099.     path = strtok (NULL, " ");
  2100.     ParseAddress (path, buf, strlen (path));
  2101.     p = strrchr (buf, (int) '!');
  2102.     if (p == NULL) {
  2103.         strcpy (FromSystem, NodeName);
  2104.         strcpy (Feed, NodeName);
  2105.         strcpy (FromUser, path);
  2106.     }
  2107.     else {
  2108.         *p = '\0';
  2109.         strcpy (FromUser, p + 1);
  2110.         p = strrchr (buf, (int) '!');
  2111.         if (p == NULL)
  2112.             p = buf;
  2113.         else
  2114.             p++;
  2115.         strcpy (FromSystem, p);
  2116.         strcpy (Feed, strtok (buf, "! "));
  2117.     }
  2118.  
  2119.     free (templine);
  2120.  
  2121.     return;
  2122. }
  2123.