home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / aux / arpa.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-19  |  13.8 KB  |  705 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *    This product includes software developed by the University of
  17.  *    California, Berkeley and its contributors.
  18.  * 4. Neither the name of the University nor the names of its contributors
  19.  *    may be used to endorse or promote products derived from this software
  20.  *    without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34.  
  35. #ifndef lint
  36. char copyright[] =
  37. "@(#) Copyright (c) 1988 Regents of the University of California.\n\
  38.  All rights reserved.\n";
  39. #endif /* not lint */
  40.  
  41. #ifndef lint
  42. static char sccsid[] = "@(#)arpa.c    5.4 (Berkeley) 6/1/90";
  43. #endif /* not lint */
  44.  
  45. # include    <stdio.h>
  46. # include    <ctype.h>
  47. # include    <signal.h>
  48. # include    <sysexits.h>
  49. # include    <whoami.h>
  50. # include    <useful.h>
  51.  
  52. char Version[] = "@(#)Arpa-mailer version 5.4 of 6/1/90";
  53.  
  54. # define void    int
  55.  
  56. /*
  57. **  ARPA MAILER -- Queue ARPANET mail for eventual delivery
  58. **
  59. **    The standard input is stuck away in the outgoing arpanet
  60. **    mail queue for delivery by the true arpanet mailer.
  61. **
  62. **        CUSTOMIZED FOR THE C/70
  63. **
  64. **    Usage:
  65. **        /usr/lib/mailers/arpa from host user
  66. **
  67. **    Positional Parameters:
  68. **        from -- the person sending the mail.
  69. **        host -- the host to send the mail to.
  70. **        user -- the user to send the mail to.
  71. **
  72. **    Flags:
  73. **        -T -- debug flag.
  74. **
  75. **    Files:
  76. **        /usr/spool/netmail/* -- the queue file.
  77. **
  78. **    Return Codes:
  79. **        0 -- all messages successfully mailed.
  80. **        2 -- user or host unknown.
  81. **        3 -- service unavailable, probably temporary
  82. **            file system condition.
  83. **        4 -- syntax error in address.
  84. **
  85. **    Compilation Flags:
  86. **        SPOOLDIR -- the spool directory
  87. **
  88. **    Compilation Instructions:
  89. **        cc -n -O -s arpa-mailer.c -o arpa-mailer -lX
  90. **        chmod 755 arpa-mailer
  91. **        mv arpa-mailer /usr/lib/mailers/arpa
  92. **
  93. **    Author:
  94. **        Eric Allman, UCB/INGRES (eric@berkeley)
  95. */
  96.  
  97. # ifdef C70
  98. # define SPOOLDIR    "/usr/netmail"
  99. # else
  100. # define SPOOLDIR    "/usr/spool/netmail"
  101. # endif
  102.  
  103.  
  104.  
  105.  
  106. char    *From;            /* person sending this mail */
  107. char    *To;            /* current "To:" person */
  108. int    State;            /* the current state (for exit codes) */
  109. # ifdef DEBUG
  110. bool    Tflag;            /* -T given */
  111. # endif DEBUG
  112. char    FromHost[200];        /* string to prepend to addresses */
  113. /*
  114. **  MAIN -- Main program for arpa mailer
  115. **
  116. **    Processes arguments, and calls sendmail successively on
  117. **    the To: list.
  118. **
  119. **    Algorithm:
  120. **        Scan for debug flag.
  121. **        Catch interrupt signals.
  122. **        Collect input file name and from person.
  123. **        If more than one person in the to list, and
  124. **            if the input file is not a real file,
  125. **            collect input into a temp file.
  126. **        For each person in the to list
  127. **            Send to that person.
  128. **
  129. **    Parameters:
  130. **        argc
  131. **        argv -- as usual
  132. **
  133. **    Returns:
  134. **        via exit
  135. **
  136. **    Side Effects:
  137. **        Mail gets sent.
  138. **
  139. **    Author:
  140. **        Eric Allman UCB/INGRES.
  141. */
  142.  
  143. main(argc, argv)
  144.     int argc;
  145.     char **argv;
  146. {
  147.     register int i;
  148.     register char *p;
  149.     register int ifd;
  150.     char buf[512];
  151.     extern int done();
  152.     extern char *locv();
  153.     register char *q;
  154.     char *lastmark;
  155.  
  156.     State = 3;
  157.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  158.         (void) signal(SIGINT, done);
  159.     
  160.     /* process flags */
  161.     argv[argc] = 0;
  162. # ifdef DEBUG
  163.     if (strcmp(argv[1], "-T") == 0)
  164.     {
  165.         Tflag++;
  166.         argv++;
  167.         argc--;
  168.         printf("%s\n", Version);
  169.     }
  170. # endif DEBUG
  171.  
  172.     if (argc != 4)
  173.     {
  174.         rexit(EX_SOFTWARE);
  175.     }
  176.     
  177.     /* decode parameters */
  178.     From = argv[1];
  179.     lastmark = &FromHost[-1];
  180.     for (p = From, q = FromHost; (*q = *p) != '\0'; p++, q++)
  181.     {
  182.         if (*p == ':')
  183.             *q = *p = '.';
  184.         if (*q == '.' || *q == '!' || *q == '@')
  185.             lastmark = q;
  186.     }
  187.     lastmark[1] = '\0';
  188.  
  189.     /* start sending mail */
  190.     State = sendmail(argv[2], argv[3]);
  191.  
  192.     /* all done, clean up */
  193.     done();
  194. }
  195. /*
  196. **  DONE -- Finish up, remove temp files, etc.
  197. **
  198. **    This does basic cleanup on interrupt, error, or
  199. **    normal termination.  It uses "State" to tell which
  200. **    is happening.
  201. **
  202. **    Parameters:
  203. **        none
  204. **
  205. **    Returns:
  206. **        none
  207. **
  208. **    Side Effects:
  209. **        Exit(State).
  210. */
  211.  
  212. done()
  213. {
  214.     rexit(State);
  215. }
  216.  
  217. /*
  218. ** REXIT -- exit, reporting error code if -T given
  219. **
  220. **    Parameters:
  221. **        e -- error code to exit with; see sysexits.h
  222. **
  223. **    Returns:
  224. **        none
  225. **
  226. **    Side Effects:
  227. **        Exit(e).
  228. */
  229. rexit(e)
  230. {
  231.  
  232. # ifdef DEBUG
  233.     if (Tflag)
  234.         fprintf(stderr, "arpa-mail: return code %d\n", e);
  235. # endif
  236.     exit(e);
  237. }
  238. /*
  239. **  SENDMAIL -- Queue up mail for the arpanet mailer.
  240. **
  241. **    The mail is inserted with proper headers into the
  242. **    arpanet queue directory.
  243. **
  244. **    Algorithm:
  245. **        decode "to" address
  246. **            if error, exit.
  247. **        create a spool file name.
  248. **        output the header information to spool file,
  249. **          separate names in To:, CC: fields with commas.
  250. **        copy the mail to the spool file.
  251. **
  252. **    Parameters:
  253. **        host -- the host to send to.
  254. **        user -- the user to send to.
  255. **
  256. **    Returns:
  257. **        none
  258. **
  259. **    Side Effects:
  260. **        the mail is copied into a file in the network
  261. **            queue directory (/usr/spool/netmail).
  262. */
  263.  
  264. sendmail(host, user)
  265.     char *host;
  266.     char *user;
  267. {
  268.     char spoolfile[50];    /* gets the spool file name */
  269.     register int i;
  270.     register char *p;
  271.     static int callnum;    /* for the final letter on spoolfile */
  272.     char buf[512];
  273.     register FILE *sfp;    /* spool file */
  274.     register int c;
  275.     extern char *matchhdr();
  276.  
  277.     /* verify that the host exists */
  278.     (void) strcpy(buf, "/dev/net/");
  279.     (void) strcat(buf, host);
  280. # ifndef C70
  281. #ifdef DEBUG
  282.     if (!Tflag)
  283. #endif DEBUG
  284.     if (host[0] == '\0' || access(buf, 0) < 0)
  285.         return (EX_NOHOST);
  286. # endif C70
  287.  
  288.     /*
  289.     **  Create spool file name.
  290.     **    Format is "username000nnX", where username is
  291.     **    padded on the right with zeros and nn (the process
  292.     **    id) is padded on the left with zeros; X is a unique
  293.     **    sequence character.
  294.     */
  295.  
  296. # ifdef DEBUG
  297.     if (Tflag)
  298.         (void) strcpy(spoolfile, "arpa.out");
  299.     else
  300. # endif DEBUG
  301.         (void) sprintf(spoolfile, "%s/arpamail%05d%c", SPOOLDIR, getpid(), 'a' + callnum++);
  302.  
  303.     /* create spool file */
  304.     sfp = fopen(spoolfile, "w");
  305.     if (sfp == NULL)
  306.     {
  307.     spoolerr:
  308.         return (EX_OSERR);
  309.     }
  310. # ifdef DEBUG
  311.     if (!Tflag)
  312. # endif DEBUG
  313.         (void) chmod(spoolfile, 0400);
  314.  
  315.     /*
  316.     ** Output mailer control lines.
  317.     **    These lines are as follows:
  318.     **        /dev/net/<hostname> {target host}
  319.     **        user-name {at target host}
  320.     **        /mnt/eric {pathname of sender; not used}
  321.     **        eric {name of user who is sending}
  322.     **    These are different (but close) on the C/70.
  323.     */
  324.  
  325. # ifdef C70
  326.      fputs(host, sfp);
  327.      fputs(":", sfp);
  328.      fputs(user, sfp);
  329.      fputs(":", sfp);
  330.      fputs(From, sfp);
  331.      fputs(":\n", sfp);
  332. # else
  333.     fputs(buf, sfp);
  334.     fputs("\n", sfp);
  335.     fputs(user, sfp);
  336.     fputs("\n\n", sfp);
  337.     fputs(From, sfp);
  338.     fputs("\n", sfp);
  339. # endif
  340.  
  341.     /*
  342.     **  Output the mail
  343.     **    Check the first line for the date.  If not found,
  344.     **    assume the message is not in arpanet standard format
  345.     **    and output a "Date:" and "From:" header.
  346.     */
  347.  
  348.     if (fgets(buf, sizeof buf, stdin) == NULL)
  349.     {
  350.         /* no message */
  351.         (void) unlink(spoolfile);
  352.         return (EX_OK);
  353.     }
  354.     if (strncmp("From ", buf, 5) == 0)
  355.     {
  356.         /* strip Unix "From" line */
  357.         /* should save the date here */
  358.         (void) fgets(buf, sizeof buf, stdin);
  359.     }
  360.     while (matchhdr(buf, "mail-from") != NULL ||
  361.            matchhdr(buf, "sender-path") != NULL ||
  362.            matchhdr(buf, "received") != NULL ||
  363.            matchhdr(buf, "via") != NULL)
  364.     {
  365.         fputs(buf, sfp);
  366.         (void) fgets(buf, sizeof buf, stdin);
  367.     }
  368.     if (matchhdr(buf, "date") == NULL)
  369.         putdate(sfp);
  370.     else
  371.     {
  372.         fputs(buf, sfp);
  373.         (void) fgets(buf, sizeof buf, stdin);
  374.     }
  375.     if (matchhdr(buf, "from") == NULL)
  376.         putfrom(sfp);
  377.     else
  378.     {
  379.         /* hack to support sendmail -- for a while */
  380.         if (index(buf, '@') == NULL)
  381.             putfrom(sfp);
  382.         else
  383.             fputs(buf, sfp);
  384.         (void) fgets(buf, sizeof buf, stdin);
  385.     }
  386.     if (!ishdr(buf))
  387.     {
  388.         if (buf[0] != '\n')
  389.             putc('\n', sfp);
  390.         goto hdrdone;
  391.     }
  392.  
  393.     /*
  394.     ** At this point, we have a message with REAL headers.
  395.     ** We look at each head line and insert commas if it
  396.     ** is a To: or Cc: field.
  397.     */
  398.  
  399.     do
  400.     {
  401.         if (!ishdr(buf))
  402.             break;
  403.         if (!matchhdr(buf, "to") && !matchhdr(buf, "cc"))
  404.         {
  405.             fputs(buf, sfp);
  406.             continue;
  407.         }
  408.         /* gotcha! */
  409.         fixaddr(buf, 1, sfp);
  410.         while (isspace(c = peekc(stdin)) && c != '\n')
  411.         {
  412.             (void) fgets(buf, BUFSIZ, stdin);
  413.             fixaddr(buf, 0, sfp);
  414.         }
  415.     } while (fgets(buf, BUFSIZ, stdin) != NULL);
  416.  
  417. hdrdone:
  418.     /* output the rest of the header & the body of the letter */
  419.     do
  420.     {
  421.         fputs(buf, sfp);
  422.         if (ferror(sfp))
  423.             goto spoolerr;
  424.     } while (fgets(buf, sizeof buf, stdin) != NULL);
  425.  
  426.     /* all done! */
  427.     (void) fclose(sfp);
  428.     return (EX_OK);
  429. }
  430. /*
  431. **  FIXADDR -- Output header line with needed commas.
  432. **
  433. **    Parameters:
  434. **        buf -- header line
  435. **        first -- true if this is not a continuation
  436. **
  437. **    Returns:
  438. **        none
  439. **
  440. **    Side effects:
  441. **        The contents of buf is copied onto the spool file with
  442. **        with the right commas interlaced
  443. **
  444. **    Called by:
  445. **        sendmail
  446. */
  447.  
  448. fixaddr(buf, first, spf)
  449.     char buf[];
  450.     register FILE *spf;
  451. {
  452.     register char *cp;
  453.     register int c;
  454.     char word[BUFSIZ], word2[BUFSIZ];
  455.     char *gword();
  456.     static char wsep[] = ", ";
  457.  
  458.     cp = buf;
  459.     if (first)
  460.     {
  461.         while (*cp != ':' && *cp)
  462.             putc(*cp++, spf);
  463.         if (*cp == ':')
  464.         {
  465.             fputs(": ", spf);
  466.             cp++;
  467.         }
  468.     }
  469.     else
  470.         while (*cp && isspace(*cp))
  471.             putc(*cp++, spf);
  472.     cp = gword(word, cp);
  473.     if (strlen(word) == 0)
  474.     {
  475.         putc('\n', spf);
  476.         goto test;
  477.     }
  478.     for (;;)
  479.     {
  480.         cp = gword(word2, cp);
  481.         if (strlen(word2) == 0)
  482.         {
  483.             putaddr(word, spf);
  484.             break;
  485.         }
  486.         if (strcmp(word2, "%") == 0)
  487.             word2[0] = '@';
  488.         if (strcmp(word2, "@") && strcmp(word2, "at"))
  489.         {
  490.             putaddr(word, spf);
  491.             fputs(wsep, spf);
  492.             (void) strcpy(word, word2);
  493.             continue;
  494.         }
  495.         fputs(word, spf);
  496.         if (word2[0] == '@')
  497.             putc('@', spf);
  498.         else
  499.             fputs(" at ", spf);
  500.         cp = gword(word, cp);
  501.         fputs(word, spf);
  502.         cp = gword(word, cp);
  503.         if (strlen(word))
  504.             fputs(wsep, spf);
  505.     }
  506.  
  507. test:
  508.     c = peekc(stdin);
  509.     if (isspace(c) && c != '\n')
  510.         fputs(",\n", spf);
  511.     else
  512.         putc('\n', spf);
  513. }
  514. /*
  515. **  PUTADDR -- output address onto file
  516. **
  517. **    Putaddr prepends the network header onto the address
  518. **    unless one already exists.
  519. **
  520. **    Parameters:
  521. **        name -- the name to output.
  522. **        fp -- the file to put it on.
  523. **
  524. **    Returns:
  525. **        none.
  526. **
  527. **    Side Effects:
  528. **        name is put onto fp.
  529. */
  530.  
  531. putaddr(name, fp)
  532.     char *name;
  533.     FILE *fp;
  534. {
  535.     register char *p;
  536.  
  537.     if (strlen(name) == 0)
  538.         return;
  539.     for (p = name; *p != '\0' && *p != ':' && *p != '.' && *p != '@' &&
  540.          *p != '!' && *p != '^'; p++)
  541.         continue;
  542.     if (*p == ':')
  543.         *p = '.';
  544.     else if (*p == '\0')
  545.         fputs(FromHost, fp);
  546.     fputs(name, fp);
  547.     if (*p != '@')
  548.         fputs("@Berkeley", fp);
  549. }
  550. /*
  551. **  PEEKC -- peek at next character in input file
  552. **
  553. **    Parameters:
  554. **        fp -- stdio file buffer
  555. **
  556. **    Returns:
  557. **        the next character in the input or EOF
  558. **
  559. **    Side effects:
  560. **        None.
  561. */
  562. peekc(fp)
  563.     register FILE *fp;
  564. {
  565.     register int c;
  566.  
  567.     c = getc(fp);
  568.     (void) ungetc(c, fp);
  569.     return(c);
  570. }
  571.  
  572. /*
  573. **  GWORD -- get the next liberal word from a string
  574. **
  575. **    Parameters:
  576. **        buf -- place to put scanned word
  577. **        p -- place to start looking for word
  578. **
  579. **    Returns:
  580. **        updated value of p or 0 if no more left after this
  581. **
  582. **    Side effects:
  583. **        buf gets the liberal word scanned.
  584. **        buf will be length 0 if there is no more input,
  585. **        or if p was passed as 0
  586. */
  587. char *
  588. gword(buf, p)
  589.     char buf[];
  590.     register char *p;
  591. {
  592.     register char *sp, *dp;
  593.     int    atfound = 0;            /* weither or not a '@' found in the scan */
  594.  
  595.     (void) strcpy(buf, "");
  596.     if (p == 0)
  597.         return(0);
  598.     sp = p;
  599.     while (*sp && (isspace(*sp) || *sp == ','))
  600.         sp++;
  601.     dp = buf;
  602.     if (*sp != '%' && *sp != '@')
  603.     {
  604.         while (*sp && !isspace(*sp) && *sp != ',' )
  605.         {
  606.             if ( *sp == '@' || *sp == '%' )
  607.                 atfound++;
  608.             *dp++ = *sp++;
  609.         }
  610.         if ( atfound )
  611.         {
  612.             dp--;
  613.             while ( *dp != '@' && *dp != '%' )
  614.                 dp--,sp--;
  615.             sp--;
  616.         }
  617.             
  618.     }
  619.     else
  620.         *dp++ = *sp++;
  621.     *dp = 0;
  622.     if (*sp == 0)
  623.         return(0);
  624.     return(sp);
  625. }
  626. /*
  627. **  ISHDR -- see if the passed line is a ARPA style header line
  628. **
  629. **    Parameters:
  630. **        buf -- header line
  631. **
  632. **    Returns:
  633. **        non-zero if the line is a header line, else zero
  634. **
  635. **    Side effects:
  636. **        none
  637. **
  638. **    Called by:
  639. **        sendmail
  640. */
  641. ishdr(buf)
  642.     char buf[];
  643. {
  644.     register char *p;
  645.  
  646.     p = buf;
  647.  
  648.     /* check for continuation lines */
  649.     if (isspace(*p))
  650.         return (1);
  651.     else
  652.     {
  653.         while (*p != ':' && !isspace(*p))
  654.             p++;
  655.         while (isspace(*p))
  656.             p++;
  657.         if (*p != ':')
  658.             p = 0;
  659.     }
  660.     return(p != 0);
  661. }
  662. /*
  663. **  PUTDATE -- Put the date field into the message.
  664. **
  665. **    Parameters:
  666. **        fp -- file to put it onto.
  667. **
  668. **    Returns:
  669. **        none
  670. **
  671. **    Side Effects:
  672. **        output onto fp.
  673. */
  674.  
  675. putdate(fp)
  676.     register FILE *fp;
  677. {
  678.     extern char *arpadate();
  679.  
  680.     fputs("Date: ", fp);
  681.     fputs(arpadate(NULL), fp);
  682.     fputs("\n", fp);
  683. }
  684. /*
  685. **  PUTFROM -- Put the from field into the message.
  686. **
  687. **    Parameters:
  688. **        fp -- file to put it onto.
  689. **
  690. **    Returns:
  691. **        none
  692. **
  693. **    Side Effects:
  694. **        output onto fp.
  695. */
  696.  
  697. putfrom(fp)
  698.     register FILE *fp;
  699. {
  700.  
  701.     fputs("From: ", fp);
  702.     fputs(From, fp);
  703.     fputs("@Berkeley\n", fp);
  704. }
  705.