home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Chans / uucp / rmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  29.1 KB  |  1,287 lines

  1. /* rmail.c: */ 
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/uucp/RCS/rmail.c,v 6.0 1991/12/18 20:13:06 jpo Rel $";
  5. static char sccsid[] = "@(#)rmail.c    1.4 (UKNET Altered by pb/pc) 7/23/91";
  6. # endif
  7.  
  8. /*
  9.  * $Header: /xtel/pp/pp-beta/Chans/uucp/RCS/rmail.c,v 6.0 1991/12/18 20:13:06 jpo Rel $
  10.  *
  11.  * $Log: rmail.c,v $
  12.  * Revision 6.0  1991/12/18  20:13:06  jpo
  13.  * Release 6.0
  14.  *
  15.  */
  16.  
  17.  
  18.  
  19. /*
  20.  *                              R M A I L . C
  21.  *
  22.  *      Developed from the Berkeley mail program of the same name
  23.  *      by Mike Obrien at RAND to run with the MMDF mail system.
  24.  *      Rewritten by Doug Kingston, US Army Ballistics Research Laboratory
  25.  *      Hacked a lot by Steve Bellovin (smb@unc)
  26.  *
  27.  *      This program runs SETUID to Opr so that it can set effective and
  28.  *      real [ug]ids to mmdflogin.
  29.  *
  30.  *      Steve Kille -  Aug 84
  31.  *              Take machete to it.  Use protocol mode,
  32.  *              and always go thru submit - phew
  33.  *      Lee McLoughlin Oct 84.
  34.  *              Address munges some header lines into 822 format.
  35.  *    Peter Collinson Dec 85.
  36.  *        Lee's version was dependent on
  37.  *         (a) the uucp channel
  38.  *         (b) the domain tables associated with the uucp channel
  39.  *        This version costs more cycles (but there is generally
  40.  *        only one of these running on a machine at a time) and
  41.  *        uses mmdf's tables to dis-assemble bang routes converting
  42.  *        them into a domain address.
  43.  *    Peter Cowen Sept 89
  44.  *        PP'ised
  45.  *    Julian Onions July 90
  46.  *        Choked to death on it!
  47.  *    Piete Brooks June 90
  48.  *        converted ! recipient addresses to % and @
  49.  *    Peter Collinson July 1991
  50.  *        put things back to where they were when the mmdf version
  51.  *        was done. Make a number of comments true again.
  52.  */
  53. #undef  RUNALON
  54.  
  55. #include "util.h"
  56. #include "head.h"
  57. #include "q.h"
  58. #include "prm.h"
  59. #include "ap.h"
  60. #include "adr.h"
  61. #include "chan.h"
  62. #include "table.h"
  63. #include "retcode.h"
  64. #include <pwd.h>
  65. #include <signal.h>
  66. #include <sys/stat.h>
  67. #include <varargs.h>
  68.  
  69. #define VERSION "3.0"
  70. #define NAMESZ  256        /* Limit on component name size.
  71.                  * LMCL was 64 */
  72. #define ungetline(s)    ((void) strcpy (tmpline,s),usetmp=1)
  73. #define MAXADRS 6        /* Max no. of adrs to output on a
  74.                  * single line. */
  75.  
  76. #define NEED_QUOTE    ": "    /* chars in mailbox name that need `"'ing */
  77.  
  78. char    debug = 0;
  79.  
  80. extern char *loc_dom_site, *pplogin, *supportaddr, *hdr_822_bp, *ia5_bp, *cont_822;
  81.  
  82.  
  83. extern char *index ();
  84. extern char *rindex ();
  85. extern char *getenv ();        /* get the Accounting system from
  86.                  * the environment */
  87. extern char *strdup ();
  88. extern char *malloc ();
  89. extern char *compress ();
  90.  
  91. static char * canon_name();
  92.  
  93. FILE   *rm_msgf;        /* temporary out for message text */
  94. CHAN   *chanptr;
  95. int     Tmpmode = 0600;
  96. char    Msgtmp[LINESIZE];
  97. char    rm_date[LINESIZE];    /* date of origination from uucp
  98.                  * header */
  99. char    rm_from[LINESIZE];    /* accumulated path of sender */
  100. char    origsys[NAMESZ];    /* originating system */
  101. char    origpath[LINESIZE];    /* path from us to originating
  102.                  * system */
  103. char    Mailsys[LINESIZE];    /* Mail system signature */
  104. char    tmpline[LINESIZE];    /* Temporary buffer for
  105.                  * continuations and such */
  106. char    usetmp = 0;        /* Wether tmpline should be used */
  107. char    linebuf[LINESIZE];    /* scratchpad */
  108. char    nextdoor[LINESIZE];    /* The site nextdoor who sent the
  109.                  * mail */
  110. char    uchan[LINESIZE];    /* Channel to use for submission */
  111.  
  112. main (argc, argv)
  113. char  **argv;
  114. int     argc;
  115. {
  116.     char    fromwhom[NAMESZ];    /* user on remote system */
  117.     char   *fromptr;
  118.     char    sys[NAMESZ];    /* an element in the uucp path */
  119.     char   *cp, *d;
  120.     int     fd;
  121.  
  122.     sys_init (argv[0]);
  123.  
  124.     while (argc > 2 && strcmp (argv[1], "-d") == 0) {
  125.         debug ++;
  126.         argc--;
  127.         argv++;
  128.     }
  129.  
  130.     if (argc < 2) {
  131.         fprintf (stderr, "Usage: rmail user [user ...]\n");
  132.         exit (1);
  133.     }
  134.     (void) umask (0);
  135.  
  136.     pp_setuserid ();
  137.     (void) sprintf (Mailsys, "<%s@%s>", pplogin, loc_dom_site);
  138.  
  139.     /* Create temp file for body of message */
  140.     (void) strcpy (Msgtmp, "/tmp/rmail.XXXXXX");
  141.     (void) mktemp (Msgtmp);
  142.     if ((fd = creat (Msgtmp, Tmpmode)) < 0)
  143.         bomb ("Can't create %s\n", Msgtmp);
  144.     (void) close (fd);
  145.  
  146.     if ((rm_msgf = fopen (Msgtmp, "r+")) == NULL)
  147.         bomb ("Can't reopen %s\n", Msgtmp);
  148.  
  149.     (void) unlink (Msgtmp);
  150.  
  151.     /*
  152.      * Unravell the From and >From lines at the head of the
  153.      * message to work who sent it, the path it took to get
  154.      * here and when it was sent. Some or all of this info may
  155.      * be ignore depending on the 822 header info given.
  156.      */
  157.     /* Zero fromwhom to stop channel crashing later on if no
  158.      * From or >From
  159.      */
  160.     (void) strcpy(fromwhom, "");
  161.     for (;;) {
  162.         if (fgets (linebuf, sizeof linebuf, stdin) == NULL)
  163.             break;
  164.         if (strncmp (linebuf, "From ", 5)
  165.             && strncmp (linebuf, ">From ", 6))
  166.             break;
  167.  
  168.         cp = index (linebuf, ' ');    /* start of name */
  169.         fromptr = ++cp;
  170.         cp = index (cp, ' ');    /* cp at end of name */
  171.         *cp++ = 0;    /* term. name, cp at date */
  172.         (void) strcpy (fromwhom, fromptr);
  173.         while (isspace (*cp))
  174.             cp++;    /* Skip any ws */
  175.  
  176.         /*
  177.          * The date is the rest of the line ending at \0 or
  178.          * remote
  179.          */
  180.         d = rm_date;
  181.         while (*cp && strncmp (cp, " remote from ", 13))
  182.             *d++ = *cp++;
  183.         *d = '\0';
  184.  
  185.         for (;;) {
  186.             cp = index (cp + 1, 'r');
  187.             if (cp == NULL) {
  188.                 cp = rindex (fromwhom, '!');
  189.                 if (cp != NULL) {
  190.                     char   *p;
  191.  
  192.                     *cp = '\0';
  193.                     p = rindex (fromwhom, '!');
  194.                     if (p != NULL)
  195.                         (void) strcpy (origsys, p + 1);
  196.                     else
  197.                         (void) strcpy (origsys, fromwhom);
  198.                     (void) strcat (rm_from, fromwhom);
  199.                     (void) strcat (rm_from, "!");
  200.                     (void) strcpy (fromwhom, cp + 1);
  201.                     goto out;
  202.                 }
  203.  
  204.                 /*
  205.                  * Nothing coherent found - so look
  206.                  * in environment for ACCTSYS
  207.                  */
  208.                 if ((cp = getenv ("ACCTSYS")) && *cp) {
  209.                     (void) strcpy (origsys, cp);
  210.                     (void) strcat (rm_from, cp);
  211.                     (void) strcat (rm_from, "!");
  212.                     goto out;
  213.                 }
  214.                 (void) strcpy(cp = sys, "remote from somewhere");
  215.             }
  216.             if (strncmp (cp, "remote from ", 12) == 0)
  217.                 break;
  218.         }
  219.  
  220.         (void) sscanf (cp, "remote from %s", sys);
  221.         (void) strcat (rm_from, sys);
  222.         (void) strcpy (origsys, sys);    /* Save for quick ref. */
  223.         (void) strcat (rm_from, "!");
  224. out:        ;
  225.     }
  226.     if (fromwhom[0] == '\0')/* No from line, illegal */
  227.         bomb ("%s", "No 'from' lines in message\n");
  228.  
  229.     ungetline (linebuf);
  230.  
  231.     /* Complete the from field */
  232.     (void) strcat (rm_from, fromwhom);
  233.  
  234.     /*
  235.      * A uk special - see if the first two components of the
  236.      * constructed bang address are in fact the same site.
  237.      * If so replace by their official name */
  238.     domain_cross (rm_from);
  239.  
  240.     /*
  241.      * Save a copy of the path to the original site. This is
  242.      * all the the path we were given - the user name after the
  243.      * last !.  NOTE: We keep the trailing !, hence the +1.
  244.      */
  245.     (void) strcpy (origpath, rm_from);
  246.     *(rindex (origpath, '!') + 1) = '\0';
  247.  
  248.     /* Savepath is given a copy of the immediate neighbour */
  249.     if ((d = index (rm_from, '!')) != NULL) {
  250.         *d = '\0';
  251.         (void) strcpy (nextdoor, rm_from);
  252.         *d = '!';
  253.     }
  254.     else
  255.         (void) strcpy (nextdoor, rm_from);
  256.  
  257.     /* find the channel depending in the nextdoor site */
  258.     set_channel (nextdoor);
  259.  
  260.     /* Convert the from to Arpa format and leave it in from */
  261.     fromcvt (rm_from, fromwhom);
  262.     (void) strcpy (rm_from, fromwhom);
  263.  
  264.     if (debug)
  265.         printf ("from=%s, origpath=%s, date=%s\n",
  266.             rm_from, origpath, rm_date);
  267.  
  268.     msgfix (rm_from, rm_date);
  269.  
  270.     exit (xsubmit (rm_from, argv, argc));
  271.     /* NOTREACHED */
  272. }
  273.  
  274. /*
  275.  * Munge the message header.
  276.  * All header lines with addresses in are munged into 822 format.
  277.  * If no "From:" line is given supply one based on the UUCP Froms, do the
  278.  * same if no "Date:".
  279.  */
  280. typedef struct {
  281.     char   *hname;
  282.     int     hfound;
  283. }       Hdrselect;
  284.  
  285. Hdrselect hdrselect[] = {
  286.     "date", 0,        /* this is a little naughty - we
  287.                  * need */
  288.     /* to register that we have had this */
  289.     /* but not address munge it */
  290.     /* so it has token 0 */
  291.     "from", 0,
  292.     "to", 0,
  293.     "cc", 0,
  294.     "bcc", 0,
  295.     "sender", 0,
  296.     "reply-to", 0,
  297.     "resent-from", 0,
  298.     "resent-sender", 0,
  299.     "resent-to", 0,
  300.     0, 0
  301.  
  302. #define HDATE    0
  303. #define HFROM    1
  304. #define HTO    2
  305. #define HCC    3
  306. #define HBCC    4
  307. #define HSENDER    5
  308. #define HREPLY    6
  309. #define HRFROM    7
  310. #define HRSENDER    8
  311. #define HRTO    9
  312. };
  313.  
  314. /* Is this header in the list of those to have their addresses munged? */
  315. /* return header value offset value */
  316. /* notice that it returns 0 for the date header */
  317. shouldmunge (name)
  318. char   *name;
  319. {
  320.     register Hdrselect *h;
  321.  
  322.     if (debug > 1)
  323.         printf ("in shouldmunge with %s\n", name);
  324.  
  325.     for (h = hdrselect; h->hname != NULL; h++)
  326.         if (!lexequ (h->hname, name)) {
  327.             h->hfound++;
  328.             return (h - hdrselect);
  329.         }
  330.     return (0);
  331. }
  332.  
  333. /* If this is a header line then grab the name of the header and stuff it
  334.  * into name then return a pointer to the actually body of the line.
  335.  * Otherwise return NULL.
  336.  * NOTE: A header is a line that begins with a word formed of alphanums and
  337.  * dashes (-) then possibly some whitespace then a colon (:).
  338.  */
  339. char   *
  340.         grabheader (s, name)
  341. register char *s, *name;
  342. {
  343.     char    *sanitise();
  344.     char    tmpbuf[LINESIZE];
  345.  
  346.     /* Copy the name into name */
  347.     while (isalpha (*s) || isdigit (*s) || *s == '-')
  348.         *name++ = *s++;
  349.     *name = '\0';
  350.  
  351.     /* Skip any whitespace */
  352.     while (isspace (*s))
  353.         s++;
  354.  
  355.     /* This is a header if the next char is colon */
  356.     if (*s == ':') {
  357.         s++;
  358.  
  359.         /*
  360.          * This is probably illegal but we fail horribly if
  361.          * it happens - so we will guard against it
  362.          */
  363.         if (*s != ' ' && *s != '\t' && *s != '\0') {    /* we need to add a
  364.                                  * space */
  365.             (void) strcpy (tmpbuf, s);
  366.             (void) sprintf (s, " %s", tmpbuf);
  367.         }
  368.         return (sanitise(s));    /* Return a pointer to the rest of
  369.                  * the line */
  370.     }
  371.     else
  372.         return (NULL);
  373. }
  374.  
  375. msgfix (from, date)
  376. char   *from, *date;
  377. {
  378.     register char *s;
  379.     char   *rest;
  380.     char   *lkp;
  381.     char    name[LINESIZE];
  382.     char    tmpbuf[LINESIZE];
  383.     int     haveheader = 0;    /* Do I have a header? */
  384.     int     headertoken;
  385.     char   *grabline ();
  386.  
  387.     /* Loop through all the headers */
  388.     while (1) {
  389.         if (debug > 1)
  390.             printf ("in msgfix about to grabline\n");
  391.  
  392.         s = grabline ();
  393.  
  394.         if (debug > 2)
  395.             printf ("got %s", s);
  396.  
  397.         /* Is this the end of the header? */
  398.         if (*s == '\0' || *s == '\n' || feof (stdin))
  399.             break;
  400.  
  401.  
  402.         /* Is this a continuation line? */
  403.         if (haveheader && isspace (*s)) {
  404.  
  405.             /*
  406.              * Note: Address munged headers handled
  407.              * specially
  408.              */
  409.             fputs (s, rm_msgf);
  410.         }
  411.         else {
  412.  
  413.             /* Grab the header name from the line */
  414.             if ((rest = grabheader (s, name)) == NULL)
  415.  
  416.                 /*
  417.                  * Not a header therefore all
  418.                  * headers done
  419.                  */
  420.                 break;
  421.  
  422.             haveheader = 1;
  423.  
  424.             /* Should I address munge this? */
  425.             if (headertoken = shouldmunge (name)) {
  426.                 char   *finalstr;
  427.  
  428.                 finalstr = "\n";
  429.                 fprintf (rm_msgf, "%s: ", name);
  430.  
  431.                 /*
  432.                  * deal specially with From lines
  433.                  * the parser loses comments so we
  434.                  * retain them specially here
  435.                  */
  436.                 if (headertoken == HFROM
  437.                     || headertoken == HRFROM) {
  438.                     if (lkp = index (rest, '<')) {
  439.                         *lkp = '\0';
  440.                         if (*rest == ' ')
  441.                             fprintf (rm_msgf, "%s<", rest + 1);
  442.                         else
  443.                             fprintf (rm_msgf, "%s<", rest);
  444.                         *lkp = '<';
  445.                         finalstr = ">\n";
  446.                         (void) strcpy (tmpbuf, lkp);
  447.  
  448.                         /*
  449.                          * notice that we
  450.                          * copy from the <
  451.                          * to start with
  452.                          * a space
  453.                          */
  454.                         tmpbuf[0] = ' ';
  455.                         rest = tmpbuf;
  456.                         lkp = rindex (rest, '>');
  457.                         if (lkp)
  458.                             *lkp = '\0';
  459.  
  460.                     }
  461.                     if (lkp = index (rest, '(')) {
  462.                         *lkp = '\0';
  463.                         (void) sprintf (tmpbuf, " (%s", lkp + 1);
  464.                         finalstr = tmpbuf;
  465.                     }
  466.                 }
  467.                 hadr_munge (rest);
  468.                 fputs (finalstr, rm_msgf);
  469.             }
  470.             else
  471.                 fputs (s, rm_msgf);
  472.         }
  473.     }
  474.  
  475.     /* No From: line was given, create one based on the From's */
  476.     if (hdrselect[HFROM].hfound == 0) {
  477.         fprintf (rm_msgf, "From: %s\n", from);
  478.     }
  479.  
  480.     /* No Date: line was given, create one based on the From's */
  481.     if (hdrselect[HDATE].hfound == 0) {
  482.         datecvt (date, tmpbuf);    /* Convert from uucp ->
  483.                      * Arpa */
  484.         fprintf (rm_msgf, "Date: %s\n", tmpbuf);
  485.     }
  486.  
  487.     /* Copy the rest of the file, if there is any more */
  488.     if (!feof (stdin)) {
  489.  
  490.         /*
  491.          * If the first line of the message isn't blank
  492.          * output the blank separator line.
  493.          */
  494.         if (*s && *s != '\n')
  495.             (void) putc ('\n', rm_msgf);
  496.         do {
  497.             (void) fputs (s, rm_msgf);
  498.             s = grabline ();
  499.         } while (!feof (stdin));
  500.     }
  501. }
  502.  
  503. char   *
  504.         grabline ()
  505. {
  506.     if (debug > 2)
  507.         printf ("in grabline ");
  508.  
  509.     /*
  510.      * Grab the next line. Remembering this might be the
  511.      * tmpline
  512.      */
  513.     if (usetmp) {
  514.         if (debug > 2)
  515.             printf ("using tmpline ");
  516.         (void) strcpy (linebuf, tmpline);
  517.         usetmp = 0;
  518.     }
  519.     else
  520.         fgets (linebuf, sizeof linebuf, stdin);
  521.  
  522.     /* Anything wrong? */
  523.     if (ferror (stdin))
  524.         fputs ("\n  *** Problem during receipt from UUCP ***\n", rm_msgf);
  525.  
  526.     if (debug > 2)
  527.         printf ("returning %s\n ", linebuf);
  528.  
  529.     return (linebuf);
  530.  
  531. }
  532.  
  533. char   *next = NULL;        /* Where nextchar gets the next
  534.                  * char from */
  535. char    adrs[LINESIZE];        /* Partly munged addresses go here */
  536.  
  537. nextchar ()
  538. {
  539.     register char *s;    /* scratch pointer. */
  540.  
  541.     if (next != NULL && *next != '\0') {
  542.         if (debug > 5)
  543.             printf ("<%c>", *next);
  544.         return (*next++);
  545.     }
  546.  
  547.     /* The last buffer is now empty, fill 'er up */
  548.     next = grabline ();
  549.  
  550.     if (feof (stdin) || !isspace (*next) || 
  551.         *next == '\n' || *next == '\0') {
  552.  
  553.         /*
  554.          * Yipee! We've reached the end of the address
  555.          * list.
  556.          */
  557.         ungetline (next);
  558.         next = NULL;    /* Force it to read buffer */
  559.         return (-1);
  560.     }
  561.  
  562.     /* Zap excess whitespace */
  563.     (void) compress (next, adrs);
  564.  
  565.     /*
  566.      * This may be a slightly duff list generated by some of
  567.      * the UNIX mailers eg: "x y z" rather than "x,y,z" If it
  568.      * is in this ^^^^^^^ convert to  ^^^^^^^ NOTE: This won't
  569.      * handle list: "x<x@y> y<y@z>" conversions!
  570.      */
  571.     if (index (adrs, ' ') != NULL &&
  572.         index (adrs, ',') == NULL &&
  573.         index (adrs, '<') == NULL &&
  574.         index (adrs, '(') == NULL &&
  575.         index (adrs, '"') == NULL) {
  576.         for (s = adrs; *s; s++)
  577.             if (*s == ' ')
  578.                 *s = ',';
  579.     }
  580.     next = adrs;
  581.  
  582.     /*
  583.      * This a continuation line so return in a seperator just
  584.      * in case
  585.      */
  586.     return (',');
  587. }
  588.  
  589.  
  590. /* Munge and address list thats part of a header line.
  591.  * Try and get the ap_* (MMDF) routines to do as much as possible for
  592.  * us.
  593.  */
  594. hadr_munge (list)
  595. char   *list;
  596. {
  597.     AP_ptr  the_addr;    /* ---> THE ADDRESS <--- */
  598.     int     adrsout = 0;    /* How many address have been
  599.                  * output */
  600.  
  601.     ungetline (list);
  602.  
  603.     while (1) {
  604.         AP_ptr  ap_pinit ();
  605.  
  606.         the_addr = ap_pinit (nextchar);
  607.  
  608.         if (the_addr == (AP_ptr) NOTOK)
  609.             bomb ("%s", "cannot initialise address parser!");
  610.  
  611.         ap_clear ();
  612.  
  613.         switch (ap_1adr ()) {
  614.             case NOTOK:
  615.             /* Something went wrong!! */
  616.             ap_sqdelete (the_addr, (AP_ptr) 0);
  617.             ap_free (the_addr);
  618.  
  619.             /*
  620.              * Emergency action in case of parser break
  621.              * down: print out the rest of the line (I
  622.              * hope).
  623.              */
  624.             fprintf (rm_msgf, "%s", tmpline);
  625.             continue;
  626.             case OK:
  627.             /* I've got an address to output! */
  628.  
  629.             /*
  630.              * output a comma seperator between the
  631.              * addresses and a newline every once in a
  632.              * while to make sure the lines aren't too
  633.              * long
  634.              */
  635.             if (adrsout++)
  636.                 fprintf (rm_msgf, ",%s ", adrsout % MAXADRS ? "" : "\n");
  637.  
  638.             /* Munge will do all the work to output it */
  639.             munge (the_addr);
  640.  
  641.             /* Reclaim the space */
  642.             ap_sqdelete (the_addr, (AP_ptr) 0);
  643.             ap_free (the_addr);
  644.  
  645.             if (debug > 4)
  646.                 printf ("munged and space freed\n");
  647.             break;
  648.             case DONE:
  649.             if (debug > 2)
  650.                 printf ("hadr_munge all done\n");
  651.  
  652.             /* Reclaim the space */
  653.             ap_sqdelete (the_addr, (AP_ptr) 0);
  654.             ap_free (the_addr);
  655.  
  656.             return;
  657.  
  658.         }
  659.     }
  660. }
  661.  
  662. /* We now have a single address in the_addr to output.
  663.  */
  664. munge (the_addr)
  665. AP_ptr  the_addr;
  666. {
  667.     char    adr[LINESIZE];
  668.     char   *s, *frees;
  669.     AP_ptr  local, domain, route;
  670.  
  671.     if (debug > 1)
  672.         printf ("in munge with: ");
  673.  
  674.     /* Find where the important bits begin in the tree */
  675.     ap_t2p (the_addr, (AP_ptr *) 0, (AP_ptr *) 0,
  676.         &local, &domain, &route);
  677.  
  678.     /* Convert from the tree back into a string */
  679.     frees = s = ap_p2s_nc ((AP_ptr) 0, (AP_ptr) 0, local, domain, route);
  680.  
  681.     if (debug > 1)
  682.         printf ("%s\n", s);
  683.  
  684.     /* Is it a uucp style address? */
  685.     if (domain == (AP_ptr) 0 && index (s, '!') != (char *) 0) {
  686.         char    adr2[LINESIZE];
  687.  
  688.         (void) strcpy (adr, s);
  689.  
  690.         /*
  691.          * Stick the path it took to get here at the start.
  692.          * But try to avoid any duplicates by overlapping
  693.          * the matching parts of the address. Eg: adr =
  694.          * 'x!y!z'  path = 'a!b!x!y!' adr2 = 'a!b!x!y!z'
  695.          */
  696.         for (s = origpath; *s; s++) {
  697.             /* Does it match? */
  698.             if (strncmp (adr, s, strlen (s)) == 0) {
  699.                 char    c = *s;
  700.  
  701.                 *s = '\0';
  702.                 (void) strcpy (adr2, origpath);
  703.                 (void) strcat (adr2, adr);
  704.                 *s = c;
  705.                 break;
  706.             }
  707.         }
  708.  
  709.         /*
  710.          * Did I just scan the whole path without finding a
  711.          * match!
  712.          */
  713.         if (*s == '\0') {
  714.             /* Append the adr to the path */
  715.             (void) strcpy (adr2, origpath);
  716.             (void) strcat (adr2, adr);
  717.         }
  718.  
  719.         /*
  720.          * Munge the address into its shortest form and
  721.          * print it
  722.          */
  723.         fromcvt (adr2, adr);
  724.         fprintf (rm_msgf, "%s", adr);
  725.  
  726.         if (debug > 1)
  727.             printf ("uucp munge gives %s\n", adr);
  728.     }
  729.     else {
  730.         char   *p;
  731.         char   *at;
  732.         char   *official = NULL;
  733.         char   *fmt;
  734.         char   *brace;
  735.         AP_ptr  norm;
  736.         extern int ap_outtype;
  737.  
  738.         /* Normalise the address */
  739.         ap_outtype = AP_PARSE_733;    /* Hmm. Maybe should be
  740.                          * from channel */
  741.         norm = ap_normalize (the_addr, CH_USA_PREF);
  742.  
  743.         /* Convert it back in to a string and output it */
  744.         ap_t2s (norm, &p);
  745.         if (debug > 1)
  746.             printf ("Normalised address: %s\n", p);
  747.  
  748.         /*
  749.          * Look for the last address component and re-write
  750.          * to the
  751.          */
  752.  
  753.         /*
  754.          * official form. There are probably better ways of
  755.          * doing this
  756.          */
  757.         at = rindex (p, '@');
  758.         fmt = "%s";
  759.         if (at) {
  760.             brace = index (at + 1, '>');
  761.             if (brace)
  762.                 *brace = '\0';
  763.             official = canon_name (at + 1);
  764.             if (official) {
  765.                 *at = '\0';
  766.                 fmt = brace ? "%s@%s>" : "%s@%s";
  767.             }
  768.             else if (brace)
  769.                 *brace = '>';
  770.         }
  771.         fprintf (rm_msgf, fmt, p, official);
  772.  
  773.         if (debug > 1) {
  774.             printf ("arpa munge gives ");
  775.             printf (fmt, p, official);
  776.             printf ("\n");
  777.         }
  778.         if (official) free (official);
  779.         free (p);
  780.     }
  781.     free (frees);
  782. }
  783.  
  784.  
  785.  
  786. /*
  787.  *      datecvt()  --  convert UNIX ctime() style date to ARPA style
  788.  *                      (change done in place)
  789.  */
  790. datecvt (date, newdate)
  791. char   *date;
  792. char   *newdate;
  793. {
  794.  
  795.     /*
  796.      * LMCL: Changed the default timezone, when none given.
  797.      */
  798.  
  799.     if (isdigit (date[0]) || date[3] == ',' || isdigit (date[5]))
  800.         (void) strcpy (newdate, date); /* Probably already ARPA */
  801.     else if (isdigit (date[20]))
  802.         (void) sprintf (newdate,
  803.                 "%.3s, %.2s %.3s %.2s %.2s:%.2s:%.2s GMT",
  804.                 date, date + 8, date + 4, date + 22,
  805.                 date + 11, date + 14, date + 17);
  806.     else if (isalpha (date[17])) /* LMCL. Bum Unix format */
  807.         (void) sprintf (newdate,
  808.                 "%.3s, %.2s %.3s %.2s %.2s:%.2s:00 GMT",
  809.                 date, date + 8, date + 4, date + 23,
  810.                 date + 11, date + 14);
  811.     else
  812.         (void) sprintf (newdate,
  813.                 "%.3s, %.2s %.3s %.2s %.2s:%.2s:%.2s %.3s",
  814.                 date, date + 8, date + 4, date + 26,
  815.                 date + 11, date + 14, date + 17, date + 20);
  816. }
  817.  
  818.  
  819. msg_failure (addr, rp, reason)
  820. char   *addr;
  821. RP_Buf *rp;
  822. char   *reason;
  823. {
  824.     extern char    *getpostmaster();
  825.     char    buf[BUFSIZ];
  826.  
  827.     if (rp)
  828.         (void) sprintf (buf, "%s: %s [%s]",
  829.                 reason, rp->rp_line,
  830.                 rp_valstr ((int)rp->rp_val));
  831.     else
  832.         (void) sprintf (buf, "%s", reason);
  833.  
  834.     PP_LOG (LLOG_EXCEPTIONS, ("Message failure: %s", buf));
  835.  
  836.     return msg_return (getpostmaster(AD_822_TYPE), addr, buf);
  837. }
  838.  
  839.  
  840. msg_return (addr, dest, reason)
  841. char   *addr, *dest, *reason;
  842. {
  843.     RP_Buf  rp;
  844.  
  845.     io_end (NOTOK);
  846.  
  847.     if (rp_isbad (pps_1adr ("UUCP (rmail) Failed Message", addr, &rp)))
  848.         bomb ("pps_1adr failed [%s]", rp.rp_line);
  849.     if (rp_isbad (pps_txt ("Your message was not delivered to:\n    ", &rp)))
  850.         bomb ("pps_txt failed [%s]", rp.rp_line);
  851.     if (rp_isbad (pps_txt (dest, &rp)))
  852.         bomb ("pps_txt failed [%s]", rp.rp_line);
  853.     if (rp_isbad (pps_txt ("\nFor the following reason:\n    ", &rp)))
  854.         bomb ("pps_txt failed [%s]", rp.rp_line);
  855.     if (rp_isbad (pps_txt (reason, &rp)))
  856.         bomb ("pps_txt failed [%s]", rp.rp_line);
  857.     if (rp_isbad (pps_txt ("\n\n--------------- Returned Mail ---------------\n\n", &rp)))
  858.         bomb ("pps_txt failed [%s]", rp.rp_line);
  859.     rewind (rm_msgf);
  860.     if (rp_isbad (pps_file (rm_msgf, &rp)))
  861.         bomb ("pps_file failed [%s]", rp.rp_line);
  862.  
  863.     if (rp_isbad (pps_txt ("--------------- End of Returned Mail -------------\n", &rp)))
  864.         bomb ("pps_txt failed [%s]", rp.rp_line);
  865.     if (rp_isbad (pps_end (OK, &rp)))
  866.         bomb ("pps_end failed [%s]", rp.rp_line);
  867.     return 0;
  868. }
  869.  
  870. /*   */
  871.  
  872. static char *
  873. pling2norm(to, from)
  874. char *to;
  875. char *from;
  876. {
  877.     char temp[1024];
  878.     char *pling;
  879.     char *c;
  880.     int quote_it;
  881.  
  882.     (void) strcpy(temp, from);
  883.     *to = '\0';
  884.  
  885.     /* copy over all (?) the hosts on the path */
  886.     while (pling = rindex(temp, '!'))
  887.     {
  888.         quote_it = 0;
  889.         *(pling++) = '\0';
  890.         if (*to)
  891.             (void) strcat(to, "%");
  892.         else if (*pling != '"')
  893.             for ( c = NEED_QUOTE; *c; c++)
  894.                 if (index(pling, *c)) {
  895.                     quote_it = 1;
  896.                     break;
  897.                 }
  898.         if (quote_it)
  899.             (void) strcat (to, "\"");
  900.         (void) strcat(to, pling);
  901.         if (quote_it)
  902.             (void) strcat (to, "\"");
  903.     }
  904.  
  905.     quote_it = 0;
  906.     if (*to)
  907.         (void) strcat(to, "%");
  908.     else if (*temp != '"')
  909.             for ( c = NEED_QUOTE; *c; c++)
  910.                 if (index(temp, *c)) {
  911.                     quote_it = 1;
  912.                     break;
  913.                 }
  914.     if (quote_it)
  915.         (void) strcat (to, "\"");
  916.     (void) strcat(to, temp);
  917.     if (quote_it)
  918.         (void) strcat (to, "\"");
  919.     if (pling = rindex(to, '%')) *pling = '@';
  920.     if (debug > 1) printf("%s -> %s\n", from, to);
  921.     return to;
  922. }
  923. /*   */
  924.  
  925. xsubmit (from, argv, argc)
  926. char   *from;
  927. char  **argv;
  928. int     argc;
  929. {
  930.     char    buf[LINESIZE];
  931.     RP_Buf  rp;
  932.     struct prm_vars prm;
  933.     LIST_BPT *new;
  934.     ADDR   *orig = NULL;
  935.     Q_struct que;
  936.     char   *name = NULL;
  937.     int     i;
  938.     int     first_bp = TRUE;
  939.  
  940.     PP_NOTICE((">>> UUCP incoming message from %s", from));
  941.     prm_init (&prm);
  942.     q_init (&que);
  943.     /* inbound channel, inbound host, contenttype */
  944.  
  945.     prm.prm_opts = PRM_ACCEPTALL;
  946.     que.msgtype = MT_UMPDU;
  947.     que.encodedinfo.eit_types = NULLIST_BPT;
  948.     new = list_bpt_new (hdr_822_bp);
  949.     list_bpt_add (&que.encodedinfo.eit_types, new);
  950.     new = list_bpt_new (ia5_bp);
  951.     list_bpt_add (&que.encodedinfo.eit_types, new);
  952.  
  953.     que.inbound = list_rchan_new (origsys, chanptr->ch_name);
  954.  
  955.     rewind (rm_msgf);
  956.  
  957.     if (debug > 0) {
  958.         char buff[1024];
  959.  
  960.         printf("From %s, ", from);
  961.         for (argv++; --argc > 0; argv++)
  962.             printf ("arg = %s (%s)\n",
  963.                 pling2norm(buff, *argv), *argv);
  964.         while (fgets (buf, LINESIZE - 1, rm_msgf) != NULL)
  965.             printf ("T=%s", buf);
  966.         if (ferror (rm_msgf))
  967.             bomb ("%s", "Error reading messge file");
  968.  
  969.         exit (0);
  970.     }
  971.  
  972.     if (rp_isbad (io_init (&rp)))
  973.         return msg_failure (from, &rp, "io_init failed");
  974.  
  975.     if (rp_isbad (io_wprm (&prm, &rp)))
  976.         return msg_failure (from, &rp, "io_wprm failed");
  977.     if (rp_isbad (io_wrq (&que, &rp)))
  978.         return msg_failure (from, &rp, "io_wrq failed");
  979.  
  980.     orig = adr_new (from, AD_822_TYPE, 0);
  981.     if (rp_isbad (io_wadr (orig, AD_ORIGINATOR, &rp)))
  982.         return msg_failure (from, &rp,
  983.                     "Sender address unacceptable");
  984.  
  985.     adr_free (orig);
  986.  
  987.     for (i = 1; i < argc; i++) {
  988.         ADDR   *adr;
  989.         char buff[1024];
  990.  
  991.         name = pling2norm(buff, argv[i]);
  992.         adr = adr_new (name, AD_822_TYPE, i);
  993.         if (rp_isbad (io_wadr (adr, AD_RECIPIENT, &rp)))
  994.             return msg_failure (name, &rp,
  995.                      "Recipient address bad");
  996.         PP_NOTICE(("valid recipient %s", argv[i]));
  997.         adr_free (adr);
  998.     }
  999.  
  1000.     if (rp_isbad (io_adend (&rp)))
  1001.         return msg_failure (name, &rp, "Address end failed");
  1002.  
  1003.     if (rp_isbad (io_tinit (&rp)))
  1004.         return msg_failure (name, &rp, "body initialisation failed");
  1005.     if (rp_isbad (io_tpart (hdr_822_bp, FALSE, &rp)))
  1006.         return msg_failure (name, &rp,
  1007.                     "822 header initialisation failed");
  1008.  
  1009.     rewind (rm_msgf);
  1010.     first_bp = TRUE;
  1011.     while (fgets (buf, LINESIZE - 1, rm_msgf) != NULL) {
  1012.         if (first_bp == TRUE
  1013.             && buf[0] == '\n') {
  1014.             first_bp = FALSE;
  1015.             if (rp_isbad (io_tdend (&rp)))
  1016.                 return msg_failure (name, &rp,
  1017.                             "header end failed");
  1018.             if (rp_isbad (io_tpart ("1.ia5", FALSE, &rp)))
  1019.                 return msg_failure (name, &rp,
  1020.                             "body initialisation failed");
  1021.         }
  1022.  
  1023.         if (rp_isbad (io_tdata (buf, strlen (buf))))
  1024.             return msg_failure (name, (RP_Buf *)0,
  1025.                         "data copied failed");
  1026.     }
  1027.     if (ferror (rm_msgf))
  1028.         return msg_failure (name, (RP_Buf *)0, "Data copy failed");
  1029.  
  1030.     if (rp_isbad (io_tdend (&rp)))
  1031.         return msg_failure (name, &rp, "Text termination problem");
  1032.  
  1033.     if (rp_isbad (io_tend (&rp)))
  1034.         return msg_failure (name, &rp, "Termination problem");
  1035.     (void) io_end (OK);
  1036.     PP_NOTICE(("Message successfully submitted"));
  1037.     return 0;
  1038. }
  1039.  
  1040.  
  1041. /*VARARGS1*/
  1042. #ifdef lint
  1043. bomb (fmt)
  1044. char   *fmt;
  1045. {
  1046.     bomb (fmt);
  1047. }
  1048.  
  1049. #else
  1050. bomb (va_alist)
  1051. va_dcl
  1052. {
  1053.     va_list ap;
  1054.     char    buf[BUFSIZ];
  1055.  
  1056.     va_start (ap);
  1057.  
  1058.     _asprintf (buf, NULLCP, ap);
  1059.     PP_LOG (LLOG_EXCEPTIONS, ("uucp bombing: %s", buf));
  1060.     va_end (ap);
  1061.  
  1062.     exit (99);
  1063. }
  1064. #endif
  1065.  
  1066. /*
  1067.  *      fromcvt()  --  trys to convert the UUCP style path into
  1068.  *                      an ARPA style name.
  1069.  */
  1070. fromcvt (from, newfrom)
  1071. char   *from, *newfrom;
  1072. {
  1073.     register char *cp;
  1074.     register char *sp;
  1075.     register char *off;
  1076.     char   *at;
  1077.     char   *atoff;
  1078.     char    buf[LINESIZE];
  1079.  
  1080.     if (debug > 1)
  1081.         printf ("fromcvt on %s\n", from);
  1082.  
  1083.     (void) strcpy (buf, from);
  1084.     cp = rindex (buf, '!');
  1085.     if (cp == 0) {
  1086.         (void) strcpy (newfrom, from);
  1087.         return;
  1088.     }
  1089.  
  1090.     /*
  1091.      * look for @site at the end of the name
  1092.      */
  1093.     atoff = NULL;
  1094.     if ((at = index (cp, '@')) != NULL) {
  1095.         /* got one - is it followed by a ! ? */
  1096.         if (index (at + 1, '!') != NULL)
  1097.             at = NULL;
  1098.         else {
  1099.             /* look up the official name of the at site */
  1100.             atoff = canon_name (at + 1);
  1101.         }
  1102.     }
  1103.     *cp = 0;
  1104.     while (sp = rindex (buf, '!')) {
  1105.  
  1106.         /*
  1107.          * scan the path backwards looking for hosts that
  1108.          * we know about
  1109.          */
  1110.         if (off = canon_name (sp + 1)) {
  1111.             if (atoff && !lexequ (atoff, off))
  1112.                 (void) strcpy (newfrom, cp + 1);
  1113.             else
  1114.                 (void) sprintf (newfrom, "%s@%s", cp + 1, off);
  1115.             if (atoff) free (atoff);
  1116.             return;
  1117.         }
  1118.         else if (at && !lexequ (at + 1, sp + 1)) {
  1119.             (void) strcpy (newfrom, cp + 1);
  1120.             if (atoff) free(atoff);
  1121.             return;
  1122.         }
  1123.         *cp = '!';
  1124.         cp = sp;
  1125.         *cp = 0;
  1126.     }
  1127.     if (atoff) free(atoff);
  1128.     if (off = canon_name (buf)) {
  1129.         (void) sprintf (newfrom, "%s@%s", cp + 1, off);
  1130.         free (off);
  1131.     }
  1132.     else
  1133.         (void) sprintf (newfrom, "%s@%s", cp + 1, buf);
  1134. }
  1135.  
  1136. /*
  1137.  *    This piece added by Peter Collinson (UKC)
  1138.  *    rather than just making rmail submit into the uucp channel which
  1139.  *    is hard coded. First look up in a table 'rmail.chans' for entries
  1140.  *    of the form
  1141.  *    nextdoor:channel
  1142.  *    If the name exists then use that channel otherwise just default to
  1143.  *    the uucp channel. This is for authorisation purposes really
  1144.  *
  1145.  *    It seems to me to be much less confusing if we use the canonical
  1146.  *    name of the site in the channel lookup. This means that aliasing
  1147.  *    at the uucp level should map onto the correct site without
  1148.  *    having to install redundant names into the rmail table
  1149.  *    
  1150.  *    If we do this, then there's a good chance that canon_name will
  1151.  *    be called twice with the same key. So add a modicum of caching into
  1152.  *    canon_name()
  1153.  */
  1154. extern char *uucpin_chan;
  1155.  
  1156. set_channel (nxt)
  1157. char   *nxt;
  1158. {
  1159.     char    *canon;
  1160.     char    *uucpc;
  1161.  
  1162.     uucpc = uucpin_chan;
  1163.     
  1164.     canon = canon_name(nxt);
  1165.     if (canon == NULL)
  1166.         canon = nxt;
  1167.     if ((chanptr = ch_mta2struct (uucpc, canon)) == NULLCHAN)
  1168.         bomb ("Cannot look up channel '%s'\n", uucpc);
  1169. }
  1170.  
  1171. /*
  1172.  *    Check if the from machine which we have constructed actually
  1173.  *    contains two references to the same machine of the form
  1174.  *    site.uucp!site.??.uk!something
  1175.  *    if so replace by the single official name
  1176.  */
  1177. domain_cross (route)
  1178. char   *route;
  1179. {
  1180.     char   *second;
  1181.     char   *endsecond;
  1182.     char   *official;
  1183.     char   *host_equal ();
  1184.  
  1185.     second = index (route, '!');
  1186.     if (second == (char *) 0)
  1187.         return;
  1188.     second++;
  1189.     endsecond = index (second, '!');
  1190.     if (endsecond == (char *) 0)
  1191.         return;
  1192.     second[-1] = '\0';
  1193.     *endsecond = '\0';
  1194.     if (official = host_equal (route, second)) {
  1195.         char buf[LINESIZE];
  1196.  
  1197.         /* Construct things in a seperate buffer to avoid problems
  1198.          * caused by the overlap of route and endsecond.
  1199.          * i.e. if len(official) > len(route!second)
  1200.          */
  1201.         (void) strcpy (buf, official);
  1202.         free (official);
  1203.         *endsecond = '!';
  1204.         (void) strcat (buf, endsecond);
  1205.         (void) strcpy(route, buf);
  1206.     }
  1207.     else {
  1208.         second[-1] = '!';
  1209.         *endsecond = '!';
  1210.     }
  1211. }
  1212.  
  1213. /*
  1214.  *    host_equal
  1215.  *    a routine to see whether the strings which are input
  1216.  *    are in fact the same host
  1217.  *    Returns the official name if they are and a null pointer if not
  1218.  */
  1219. char   *
  1220. host_equal(n1, n2)
  1221.     char   *n1, *n2;
  1222. {
  1223.     char    *o1, *o2;
  1224.     char    *canon_name();
  1225.  
  1226.     if ((o1 = canon_name(n1)) == NULLCP)
  1227.         return NULLCP;
  1228.     if ((o2 = canon_name(n2)) == NULLCP) {
  1229.         free (o1);
  1230.         return(NULLCP);
  1231.     }
  1232.     if (lexequ (o1, o2) == 0) {
  1233.         free (o2);
  1234.         return o1;
  1235.     }
  1236.     free (o1);
  1237.     free (o2);
  1238.     return NULLCP;
  1239. }
  1240.  
  1241. /* This procedure takes a string and converts all control characters
  1242.  * to spaces. This is necessary to protect against the depradations
  1243.  * of various out of spec mailers (HP-UX for example) which allow
  1244.  * spurious control characters in headers.
  1245.  */
  1246. char    *
  1247. sanitise(s)
  1248.     char    *s;
  1249. {
  1250.     char    *t;
  1251.  
  1252.     /* Scan along string and convert all control characters except
  1253.      * white space into space.
  1254.      */
  1255.     for (t = s; *t; t++)
  1256.         *t = (iscntrl(*t) && !isspace(*t)) ? ' ' : *t;
  1257.     return (s);
  1258. }
  1259.  
  1260. /* UUCP MUST work on USA order but we will be charitable */
  1261. static int    dmnorder = CH_USA_PREF;
  1262.  
  1263. static char *
  1264. canon_name(host)
  1265.     char    *host;
  1266. {
  1267.     static char official[LINESIZE];
  1268.     static char lasthost[LINESIZE];
  1269.     char    *ptr;
  1270.  
  1271.     if (lasthost[0])
  1272.     {    if (lexequ(host, lasthost) == 0)
  1273.         {    if (debug > 0)
  1274.                 printf("canon_name cache hit: %s -> %s\n",
  1275.                     host, official);
  1276.             return strdup(official);
  1277.         }
  1278.     }
  1279.     if (rp_isbad(tb_getdomain(host, (char *)0, official, dmnorder, &ptr))) {
  1280.         official[0] = lasthost[0] = '\0';
  1281.         /* must clear the cache, as official is now "(ERROR)" */
  1282.         return (char *) 0;
  1283.     }
  1284.     (void) strcpy(lasthost, host);
  1285.     return strdup(official);
  1286. }
  1287.