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