home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume11 / smail3 / part02 < prev    next >
Text File  |  1987-09-21  |  55KB  |  2,449 lines

  1. Subject:  v11i070:  Smail, UUCP domain mailer, Part02/03
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: Larry Auton <clyde.ATT.COM!lda>
  7. Posting-number: Volume 11, Issue 70
  8. Archive-name: smail3/Part02
  9.  
  10. # This is a shell archive.  Remove anything before this line, then
  11. # unpack it by saving it in a file and typing "sh file".  (Files
  12. # unpacked will be owned by you and have default permissions.)
  13. #
  14. # This archive contains:
  15. # Makefile alias.c defs.h deliver.c getopt.c getpath.c headers.c
  16.  
  17. echo x - Makefile
  18. cat > "Makefile" << '//E*O*F Makefile//'
  19. # Makefile for smail (not a installation makefile)
  20.  
  21. # @(#)Makefile    2.5 (smail) 9/15/87
  22.  
  23. CFLAGS    =    -O
  24. #
  25. # System V Release 2.0 sites can use -lmalloc for a faster malloc
  26. #
  27. #LIBS    =    -lmalloc
  28.  
  29. OBJECTS =    main.o map.o resolve.o deliver.o misc.o alias.o pw.o headers.o getpath.o str.o getopt.o
  30.  
  31. all: smail svbinmail lcasep pathproc mkfnames nptx
  32.  
  33. smail:        $(OBJECTS)
  34.         cc $(CFLAGS) $(OBJECTS) -o smail $(LIBS)
  35.  
  36. $(OBJECTS):    defs.h
  37.         cc $(CFLAGS) -c $<
  38.  
  39. svbinmail:    svbinmail.c defs.h
  40.         cc $(CFLAGS) svbinmail.c -o svbinmail
  41.  
  42. lcasep:        lcasep.c
  43.         cc $(CFLAGS) lcasep.c -o lcasep
  44.  
  45. pathproc:    pathproc.sh
  46.         cp pathproc.sh pathproc
  47.         chmod 755 pathproc
  48.  
  49. mkfnames:    mkfnames.sh
  50.         cp mkfnames.sh mkfnames
  51.         chmod 755 mkfnames
  52.  
  53. nptx:        nptx.o pw.o str.o
  54.         cc $(CFLAGS) nptx.o pw.o str.o -o nptx $(LIBS)
  55.  
  56. nptx.o:        nptx.c
  57.         cc $(CFLAGS) -c nptx.c
  58.  
  59. install:    all
  60.         @echo read doc/Install
  61.  
  62. clean:
  63.         rm -f *.o *.ln a.out core
  64.  
  65. clobber:    clean
  66.         rm -f smail rmail lcasep pathproc mkfnames svbinmail nptx
  67. //E*O*F Makefile//
  68.  
  69. echo x - alias.c
  70. cat > "alias.c" << '//E*O*F alias.c//'
  71. #ifndef lint
  72. static char *sccsid = "@(#)alias.c    2.5 (smail) 9/15/87";
  73. #endif
  74.  
  75. #include <stdio.h>
  76. #include <sys/types.h>
  77. #include <sys/stat.h>
  78. #include <pwd.h>
  79. #include "defs.h"
  80. #include <ctype.h>
  81.  
  82. extern enum edebug debug;    /* verbose and debug modes        */
  83. extern char hostdomain[];
  84. extern char hostname[];
  85. extern char *aliasfile;
  86.  
  87. /*
  88. **
  89. ** Picture of the alias graph structure
  90. **
  91. **    head
  92. **       |
  93. **       v
  94. **    maps -> mark -> gjm -> mel -> NNULL
  95. **       |
  96. **       v
  97. **    sys ->  root -> ron -> NNULL
  98. **       |
  99. **       v
  100. **    root -> mark -> chris -> lda -> NNULL
  101. **       |
  102. **       v
  103. **      NNULL
  104. */
  105.  
  106. typedef struct alias_node node;
  107.  
  108. static struct alias_node {
  109.     char *string;
  110.     node *horz;
  111.     node *vert;
  112. };
  113.  
  114. #ifndef SENDMAIL
  115. static node aliases = {"", 0, 0}; /* this is the 'dummy header' */
  116. #endif /* not SENDMAIL */
  117.  
  118. /*
  119. ** lint free forms of NULL
  120. */
  121.  
  122. #define NNULL    ((node   *) 0)
  123. #define CNULL    ('\0')
  124.  
  125. /*
  126. ** string parsing macros
  127. */
  128. #define SKIPWORD(Z)  while(*Z!=' ' && *Z!='\t' && *Z!='\n' && *Z!=',') Z++;
  129. #define SKIPSPACE(Z) while(*Z==' ' || *Z=='\t' || *Z=='\n' || *Z==',') Z++;
  130.  
  131. static int nargc = 0;
  132. static char *nargv[MAXARGS];
  133.  
  134. void    add_horz();
  135. void    load_alias(), strip_comments();
  136. int    recipients();
  137. node    *pop();
  138. #ifndef SENDMAIL
  139. node    *v_search(), *h_search();
  140. char    *tilde();
  141. #endif    /* not SENDMAIL */
  142.  
  143. /* our horizontal linked list looks like a stack */
  144. #define push        add_horz
  145.  
  146. #define escape(s)    ((*s != '\\') ? (s) : (s+1))
  147.  
  148. char **
  149. alias(pargc, argv)
  150. int *pargc;
  151. char **argv;
  152. {
  153. /*
  154. **  alias the addresses
  155. */
  156.     int    i;
  157.     char    domain[SMLBUF], ubuf[SMLBUF], *user;
  158.     node    *addr, addrstk;
  159.     node    *flist,  fliststk, *u;
  160.  
  161. #ifndef SENDMAIL
  162.     FILE    *fp;
  163.     node    *a;
  164.     char    *home, buf[SMLBUF];
  165.     int    aliased;
  166.     struct    stat st;
  167. #endif /* not SENDMAIL */
  168.  
  169. #ifdef FULLNAME
  170.     char *res_fname();    /* Does fullname processing */
  171. #endif
  172.  
  173.     addr  = &addrstk;
  174.     flist = &fliststk;
  175.     user  = ubuf;
  176.  
  177.     addr->horz = NNULL;
  178.     flist->horz  = NNULL;
  179.  
  180.     /*
  181.     ** push all of the addresses onto a stack
  182.     */
  183.     for(i=0; i < *pargc; i++) {
  184.         push(addr, argv[i]);
  185.     }
  186.  
  187.     /*
  188.     ** for each adress, check for included files, aliases,
  189.     ** full name mapping, and .forward files
  190.     */
  191.  
  192.     while((nargc < MAXARGS) && ((u = pop(addr)) != NNULL)) {
  193. #ifndef SENDMAIL
  194.         if(strncmpic(u->string, ":include:", 9) == 0) {
  195.             /*
  196.             ** make sure it's a full path name
  197.             ** don't allow multiple sourcing
  198.             ** of a given include file
  199.             */
  200.             char *p = u->string + 9;
  201.  
  202.             if((*p == '/')
  203.             && (h_search(flist, p) == NULL)) {
  204.                 push(flist, p);
  205.                 if((stat(p, &st) >= 0)
  206.                 &&((st.st_mode & S_IFMT) == S_IFREG)
  207.                 &&((fp = fopen(p, "r")) != NULL)) {
  208.                     while(fgets(buf, sizeof buf, fp)) {
  209.                         (void) recipients(addr, buf);
  210.                     }
  211.                     (void) fclose(fp);
  212.                 }
  213.             }
  214.             continue;
  215.         }
  216. #endif /* not SENDMAIL */
  217.         /*
  218.         ** parse the arg to see if it's to be aliased
  219.         */
  220.  
  221.         if(islocal(u->string, domain, ubuf) == 0) {
  222.             goto aliasing_complete;
  223.         }
  224.  
  225.         /*
  226.         ** local form - try to alias user
  227.         ** aliases file takes precedence over ~user/.forward
  228.         ** since that's the way that sendmail does it.
  229.         */
  230.  
  231. #ifdef LOWERLOGNAME
  232.         /* squish 'user' into lower case */
  233.         for(user = ubuf; *user ; user++) {
  234.             *user = lower(*user);
  235.         }
  236. #endif
  237.         user = escape(ubuf);
  238.  
  239.         (void) strcpy(u->string, user);    /* local => elide domain */
  240. #ifndef SENDMAIL
  241.         /*
  242.         ** check for alias - all this complication is necessary
  243.         ** to handle perverted aliases like these:
  244.         ** # mail to 's' resolves to 't' 'm' and 'rmt!j'
  245.         ** s    t,g,j,m
  246.         ** g    j,m
  247.         ** j    rmt!j
  248.         ** # mail to 'a' resolves to 'rmt!d'
  249.         ** a    b c
  250.         ** b    c
  251.         ** c    rmt!d
  252.         ** # mail to x resolves to 'x'
  253.         ** x    local!x
  254.         ** # mail to 'y' resolves to 'y' and 'z'
  255.         ** y    \y z
  256.         */
  257.         if(((a = v_search(user)) != NNULL)) {
  258.             char dtmpb[SMLBUF], utmpb[SMLBUF], *ut;
  259.             int user_inalias = 0;
  260.             node *t = a;
  261.  
  262.             for(a = a->horz; a != NNULL; a=a->horz) {
  263.                 if(islocal(a->string, dtmpb, utmpb)) {
  264. #ifdef LOWERLOGNAME
  265.                     /* squish 'utmpb' into lower case */
  266.                     for(ut = utmpb; *ut ; ut++) {
  267.                         *ut = lower(*ut);
  268.                     }
  269. #endif
  270.  
  271.                     ut = escape(utmpb);
  272. #ifdef CASEALIAS
  273.                     if(strcmp(ut, user) == 0)
  274. #else
  275.                     if(strcmpic(ut, user) == 0)
  276. #endif
  277.                     {
  278.                         user_inalias = 1;
  279.                     } else {
  280.                         push(addr, a->string);
  281.                     }
  282.                 } else {
  283.                     push(addr, a->string);
  284.                 }
  285.             }
  286.             t->horz = NNULL; /* truncate horz list of aliases */
  287.             if(user_inalias == 0) {
  288.                 continue;
  289.             }
  290.         }
  291.  
  292.         if((home = tilde(user)) != NULL) {
  293.             /* don't allow multiple sourcing
  294.             ** of a given .forward file
  295.             */
  296.  
  297.             if((h_search(flist, home) != NULL)) {
  298.                 continue;
  299.             }
  300.             push(flist, home);
  301.  
  302.             /*
  303.             ** check for ~user/.forward file
  304.             ** must be a regular, readable file
  305.             */
  306.  
  307.             (void) sprintf(buf, "%s/%s", home, ".forward");
  308.             if((stat(buf, &st) >= 0)
  309.             &&((st.st_mode & S_IFMT) == S_IFREG)
  310.             &&((st.st_mode & 0444)   == 0444)
  311.             &&((fp = fopen(buf, "r")) != NULL)) {
  312.                 aliased = 0;
  313.                 while(fgets(buf, sizeof buf, fp)) {
  314.                     aliased |= recipients(addr, buf);
  315.                 }
  316.                 (void) fclose(fp);
  317.                 if(aliased) {
  318.                     continue;
  319.                 }
  320.             }
  321.         }
  322. #endif /* not SENDMAIL */
  323.  
  324. #ifdef FULLNAME
  325.         /*
  326.         ** Do possible fullname substitution.
  327.         */
  328. #ifdef DOT_REQD
  329.         if (index(user, '.') != NULL)
  330. #endif
  331.         {
  332.             static char t_dom[SMLBUF], t_unam[SMLBUF];
  333.             char *t_user = res_fname(user);
  334.             if (t_user != NULL) {
  335.                 if(islocal(t_user, t_dom, t_unam) == 0) {
  336.                     /* aliased to non-local address */
  337.                     push(addr, t_user);
  338.                     continue;
  339.                 }
  340.                 if(strcmp(t_unam, user) != 0) {
  341.                     /* aliased to different local address */
  342.                     push(addr, t_unam);
  343.                     continue;
  344.                 }
  345.             }
  346.         }
  347. #endif
  348.  
  349. aliasing_complete:
  350.         user = escape(u->string);
  351.         for(i=0; i < nargc; i++) {
  352.             if(strcmpic(nargv[i], user) == 0) {
  353.                 break;
  354.             }
  355.         }
  356.  
  357.         if(i == nargc) {
  358.             nargv[nargc++] = user;
  359.         }
  360.     }
  361.     *pargc     = nargc;
  362.     return(nargv);
  363. }
  364.  
  365. #ifndef SENDMAIL
  366. /*
  367. ** v_search
  368. **    given an string, look for its alias in
  369. **    the 'vertical' linked list of aliases.
  370. */
  371. node *
  372. v_search(user)
  373. char *user;
  374. {
  375.     node *head;
  376.     node *a;
  377.     static int loaded = 0;
  378.  
  379.     head = &aliases;
  380.     if(loaded == 0) {
  381.         load_alias(head, aliasfile);
  382.         loaded = 1;
  383.     }
  384.  
  385.     for(a = head->vert; a != NNULL; a = a->vert) {
  386. #ifdef CASEALIAS
  387.         if(strcmp(a->string, user) == 0)
  388. #else
  389.         if(strcmpic(a->string, user) == 0)
  390. #endif
  391.         {
  392.             break;
  393.         }
  394.     }
  395.     if(a == NNULL) {        /* not in graph */
  396.         return(NNULL);
  397.     }
  398.     return(a);
  399. }
  400.  
  401. /*
  402. ** h_search
  403. **    given an string, look for it in
  404. **    a 'horizontal' linked list of strings.
  405. */
  406. node *
  407. h_search(head, str)
  408. node *head;
  409. char *str;
  410. {
  411.     node *a;
  412.     for(a = head->horz; a != NNULL; a = a->horz) {
  413. #ifdef CASEALIAS
  414.         if(strcmp(a->string, str) == 0)
  415. #else
  416.         if(strcmpic(a->string, str) == 0)
  417. #endif
  418.         {
  419.             break;
  420.         }
  421.     }
  422.     return(a);
  423. }
  424. #endif /* not SENDMAIL */
  425.  
  426. /*
  427. ** load_alias
  428. **    parse an 'aliases' file and add the aliases to the alias graph.
  429. **    Handle inclusion of other 'aliases' files.
  430. */
  431.  
  432. void
  433. load_alias(head, filename)
  434. node *head;
  435. char *filename;
  436. {
  437.     FILE *fp;
  438.     node *v, *h, *add_vert();
  439.     char domain[SMLBUF], user[SMLBUF];
  440.     char *p, *b, buf[SMLBUF];
  441.  
  442.     if((fp = fopen(filename,"r")) == NULL) {
  443. DEBUG("load_alias open('%s') failed\n", filename);
  444.         return;
  445.     }
  446.  
  447.     while(fgets(buf, sizeof buf, fp) != NULL) {
  448.         p = buf;
  449.         if((*p == '#') || (*p == '\n')) {
  450.             continue;
  451.         }
  452.  
  453.         /*
  454.         ** include another file of aliases
  455.         */
  456.  
  457.         if(strncmp(p, ":include:", 9) == 0) {
  458.             char *nl;
  459.             p += 9;
  460.             if((nl = index(p, '\n')) != NULL) {
  461.                 *nl = CNULL;
  462.             }
  463. DEBUG("load_alias '%s' includes file '%s'\n", filename, p);
  464.             load_alias(head, p);
  465.             continue;
  466.         }
  467.  
  468.         /*
  469.         **  if the first char on the line is a space or tab
  470.         **  then it's a continuation line.  Otherwise,
  471.         **  we start a new alias.
  472.         */
  473.         if(*p != ' ' && *p != '\t') {
  474.             b = p;
  475.             SKIPWORD(p);
  476.             *p++ = CNULL;
  477.             /*
  478.             ** be sure that the alias is in local form
  479.             */
  480.             if(islocal(b, domain, user) == 0) {
  481.                 /*
  482.                 ** non-local alias format - skip it
  483.                 */
  484.                 continue;
  485.             }
  486.             /*
  487.             ** add the alias to the (vertical) list of aliases
  488.             */
  489.             if((h = add_vert(head, user)) == NNULL) {
  490. DEBUG("load_alias for '%s' failed\n", b);
  491.                 return;
  492.             }
  493.         }
  494.         /*
  495.         **  Next on the line is the list of recipents.
  496.         **  Strip out each word and add it to the
  497.         **  horizontal linked list.
  498.         */
  499.         (void) recipients(h, p);
  500.     }
  501.     (void) fclose(fp);
  502.     /*
  503.     ** strip out aliases which have no members
  504.     */
  505.     for(v = head; v->vert != NNULL; ) {
  506.         if(v->vert->horz == NNULL) {
  507.             v->vert = v->vert->vert;
  508.         } else {
  509.             v = v->vert;
  510.         }
  511.     }
  512. }
  513.  
  514. /*
  515. ** add each word in a string (*p) of recipients
  516. ** to the (horizontal) linked list associated with 'h'
  517. */
  518.  
  519. recipients(h, p)
  520. node *h;
  521. char *p;
  522. {
  523.  
  524.     char *b, d[SMLBUF], u[SMLBUF];
  525.     int ret = 0;
  526.  
  527.     strip_comments(p);    /* strip out stuff in ()'s */
  528.  
  529.     SKIPSPACE(p);        /* skip leading whitespace on line */
  530.  
  531.     while((*p != NULL) && (*p != '#')) {
  532.         b = p;
  533.         if(*b == '"') {
  534.             if((p = index(++b, '"')) == NULL) {
  535.                 /* syntax error - no matching quote */
  536.                 /* skip the rest of the line */
  537.                 return(ret);
  538.             }
  539.         } else {
  540.             SKIPWORD(p);
  541.         }
  542.  
  543.         if(*p != CNULL) {
  544.             *p++ = CNULL;
  545.         }
  546.  
  547.         /* don't allow aliases of the form
  548.         ** a    a
  549.         */
  550.         if((islocal(b, d, u) == 0)
  551.         || (strcmpic(h->string, u) != 0)) {
  552.             add_horz(h, b);
  553.             ret = 1;
  554.         }
  555.         SKIPSPACE(p);
  556.     }
  557.     return(ret);
  558. }
  559.  
  560. /*
  561. ** some aliases may have comments on the line like:
  562. **
  563. ** moderators    moderator@somehost.domain    (Moderator's Name)
  564. **        moderator@anotherhost.domain    (Another Moderator's Name)
  565. **
  566. ** strip out the stuff in ()'s
  567. **
  568. */
  569.  
  570. void
  571. strip_comments(p)
  572. char *p;
  573. {
  574.     char *b;
  575.     while((p = index(p, '(')) != NULL) {
  576.         b = p++;    /*
  577.                 ** save pointer to open parenthesis
  578.                 */
  579.         if((p = index(p, ')')) != NULL) {/* look for close paren */
  580.             (void) strcpy(b, ++p);     /* slide string left    */
  581.         } else {
  582.             *b = CNULL;    /* no paren, skip rest of line  */
  583.             break;
  584.         }
  585.     }
  586. }
  587.  
  588. /*
  589. ** add_vert - add a (vertical) link to the chain of aliases.
  590. */
  591.  
  592. node *
  593. add_vert(head, str)
  594. node *head;
  595. char *str;
  596. {
  597.     char *p, *malloc();
  598.     void free();
  599.     node *new;
  600.  
  601.     /*
  602.     ** strip colons off the end of alias names
  603.     */
  604.     if((p = index(str, ':')) != NULL) {
  605.         *p = CNULL;
  606.     }
  607.     if((new = (node *) malloc(sizeof(node))) != NNULL) {
  608.         if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
  609.             free(new);
  610.             new = NNULL;
  611.         } else {
  612.             (void) strcpy(new->string, str);
  613.             new->vert   = head->vert;
  614.             new->horz   = NNULL;
  615.             head->vert  = new;
  616. /*DEBUG("add_vert %s->%s\n", head->string, new->string);/* */
  617.         }
  618.     }
  619.     return(new);
  620. }
  621.  
  622. /*
  623. ** add_horz - add a (horizontal) link to the chain of recipients.
  624. */
  625.  
  626. void
  627. add_horz(head, str)
  628. node *head;
  629. char *str;
  630. {
  631.     char *malloc();
  632.     node *new;
  633.  
  634.     if((new = (node *) malloc(sizeof(node))) != NNULL) {
  635.         if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
  636.             free(new);
  637.             new = NNULL;
  638.         } else {
  639.             (void) strcpy(new->string, str);
  640.             new->horz  = head->horz;
  641.             new->vert  = NNULL;
  642.             head->horz = new;
  643.         }
  644. /*DEBUG("add_horz %s->%s\n", head->string, new->string);/* */
  645.     }
  646. }
  647.  
  648. node *
  649. pop(head)
  650. node *head;
  651. {
  652.     node *ret = NNULL;
  653.  
  654.  
  655.     if(head != NNULL) {
  656.         ret = head->horz;
  657.         if(ret != NNULL) {
  658.             head->horz = ret->horz;
  659.         }
  660.     }
  661.     return(ret);
  662. }
  663. //E*O*F alias.c//
  664.  
  665. echo x - defs.h
  666. cat > "defs.h" << '//E*O*F defs.h//'
  667. /*
  668. **
  669. **  Defs.h:  header file for rmail/smail.
  670. **
  671. **  Configuration options for rmail/smail.
  672. **    default configuration is:
  673. **    full domain name is 'hostname.uucp' (get registered!)
  674. **    path file is /usr/lib/uucp/paths.
  675. **    no log, no record, use sendmail.
  676. ** 
  677. **  You can change these in the next few blocks.
  678. **
  679. */
  680.  
  681. /*
  682. **    @(#)defs.h    2.5 (smail) 9/15/87
  683. */
  684.  
  685. #ifndef VERSION
  686. #define    VERSION    "smail2.5"
  687. #endif
  688.  
  689. /*#define BSD                /* if system is a Berkeley system */
  690.  
  691. /*#define SENDMAIL "/usr/lib/sendmail"    /* Turn off to use /bin/(l)mail only */
  692.  
  693. #ifdef BSD
  694. #define GETHOSTNAME            /* use gethostname() */
  695. #else
  696. #define UNAME                 /* use uname() */
  697. #endif
  698.  
  699. /* if defined, HOSTNAME overrides UNAME and GETHOSTNAME */
  700. /*#define HOSTNAME    "host"        /* literal name */
  701.  
  702. /*#define HOSTDOMAIN    "host.dom"    /* overrides default HOSTNAME.MYDOM */
  703.  
  704. /*
  705.  * .UUCP here is just for testing, GET REGISTERED in COM, EDU, etc.
  706.  * See INFO.REGISTRY for details.
  707.  */
  708.  
  709. #define MYDOM        ".UUCP"        /* literal domain suffix */
  710.  
  711. /*
  712.  * WARNING: DOMGATE is only for qualified gateways - use caution.
  713.  * If you don't fully understand it - don't use it!
  714.  * If you are not completely sure you need it - don't use it!
  715.  * If you are not prepared to handle all addresses to MYDOM - don't use it!
  716.  *
  717.  * if defined, DOMGATE (DOMain GATEway) will cause addresses of the form
  718.  *
  719.  *    user@MYDOM or MYDOM!user
  720.  *
  721.  * (with and without the leading '.' on MYDOM)
  722.  * to be seen treated simply 'user' - a purely local address.
  723.  * Then, it is left to the aliasing code to map it back to a
  724.  * non-local address if necessary.
  725.  */
  726.  
  727. /*#define DOMGATE        /* Act as Domain Gateway */
  728.  
  729. /*
  730.  * HIDDENHOSTS allows hosts that serve as domain gateways to hide
  731.  * the subdomains beneath them.  Mail that originates at any of
  732.  * the hosts in the subdomain will appear to come from the gateway host.
  733.  * Hence, mail from
  734.  *
  735.  *         anything.hostdomain!user
  736.  *
  737.  * will appear to come from 
  738.  *
  739.  *         hostdomain!user
  740.  *
  741.  * A consequence is that return mail to hostdomain!user would need to
  742.  * be forwarded to the proper subdomain via aliases or other forwarding
  743.  * facilities.
  744.  *
  745.  * If you're using sendmail, then if defined here,
  746.  * it should be used in ruleset 4 of the sendmail.cf, too.
  747.  */
  748.  
  749. /*#define HIDDENHOSTS            /* hide subdomains of hostdomain */
  750.  
  751. /*
  752.  * Mail that would otherwise be undeliverable will be passed to the
  753.  * aliased SMARTHOST for potential delivery.
  754.  *
  755.  * Be sure that the host you specify in your pathalias input knows that you're
  756.  * using it as a relay, or you might upset somebody when they find out some
  757.  * other way.  If you're using 'foovax' as your relay, and below you have
  758.  * #define SMARTHOST "smart-host", then the pathalias alias would be:
  759.  *
  760.  *    smart-host = foovax
  761.  */
  762.  
  763. #define SMARTHOST  "smart-host"    /* pathalias alias for relay host */
  764.  
  765. /*
  766. **  ALIAS and CASEALIAS are used only if SENDMAIL is NOT defined.
  767. **  Sites using sendmail have to let sendmail do the aliasing.
  768. **  LOWERLOGNAME maps all local login names into lower case.  This
  769. **  helps sites who have only upper case send mail to mixed case sites.
  770. */
  771.  
  772. #define ALIAS    "/usr/lib/aliases"    /* location of mail aliases       */
  773. /*#define CASEALIAS            /* make aliases case sensitive    */
  774. /*#define LOWERLOGNAME            /* map local logins to lower case */
  775.  
  776. /*
  777.  * defining FULLNAME means that Full Name resolution
  778.  * will be attempted when necessary.
  779.  *
  780.  * the Full Name information will be taken from a
  781.  * list of {Full Name, address} pairs.
  782.  * The names in the list must be sorted
  783.  * without regard to upper/lower case.
  784.  *
  785.  * defining DOT_REQD says that the user name must contain a '.' for
  786.  * the Full Name search to be done.
  787.  *
  788.  * All full name searches are case insensitive.
  789.  *
  790.  */
  791.  
  792. #define FULLNAME    "/usr/lib/fullnames"
  793.                     /* list of Full Name, address pairs */
  794.  
  795. /*#define DOT_REQD            /* Must be George.P.Burdell@gatech.EDU
  796.                     ** not just  Burdell@gatech.EDU
  797.                     */
  798.  
  799. /*
  800. **    PATHS is name of pathalias file.  This is mandatory.
  801. **    Define LOG if you want a log of mail.  This can be handy for
  802. **    debugging and traffic analysis.
  803. **    Define RECORD for a copy of all mail.  This uses much time and
  804. **    space and is only used for extreme debugging cases.
  805. */
  806.  
  807. #ifndef PATHS
  808. #define PATHS    "/usr/lib/uucp/paths"    /* location of the path database */
  809. #endif
  810.  
  811. /*#define LOG    "/usr/spool/uucp/mail.log"    /* log of uucp mail */
  812. /*#define RECORD    "/tmp/mail.log"        /* record of uucp mail */
  813.  
  814. /*
  815. **  Mailer options:
  816. **    RMAIL is the command to invoke rmail on machine sys.
  817. **    RARG is how to insulate metacharacters from RMAIL. 
  818. **    LMAIL is the command to invoke the local mail transfer agent.
  819. **    LARG is how to insulate metacharacters from LMAIL. 
  820. **    RLARG is LARG with host! on the front - to pass a uux addr to sendmail.
  821. **    SENDMAIL selects one of two sets of defines below for either
  822. **    using sendmail or /bin/lmail.
  823. */    
  824.  
  825. #ifndef UUX
  826. #define UUX        "/usr/bin/uux"    /* location of uux command   */
  827. #endif
  828.  
  829. #ifndef SMAIL
  830. #define SMAIL        "/bin/smail"    /* location of smail command */
  831. #endif
  832.  
  833. /*
  834. ** command used to retry failed mail, flag is used to set the routing level.
  835. */
  836. #define VFLAG        ((debug == VERBOSE)?"-v":"")
  837. #define RETRY(flag)    "%s %s %s -f %s ", SMAIL, VFLAG, flag, spoolfile
  838.  
  839. /*
  840. ** use the -a if you have it.  This sometimes helps failed mail and warning
  841. ** messages get back to where the mail originated.
  842. **
  843. ** some versions of uux can't do '-a' - pick one of the next two definitions
  844. */
  845.  
  846. #define RMAIL(flags,from,sys) "%s -a%s %s - %s!rmail",UUX,from,flags,sys /* */
  847. /*#define RMAIL(flags,from,sys) "%s %s - %s!rmail",UUX,flags,sys /* */
  848.  
  849. #define RARG(user)        " '(%s)'",user
  850. #define RFROM(frm,now,host)     "From %s  %.24s remote from %s\n",frm,now,host
  851.  
  852. #ifdef SENDMAIL
  853.  
  854. #define HANDLE    JUSTUUCP    /* see HANDLE definition below */
  855. #define ROUTING JUSTDOMAIN    /* see ROUTING definition below */
  856.  
  857. #define LMAIL(frm,sys)     "%s -em -f%s",SENDMAIL,frm
  858. #define LARG(user)        " '%s'",postmaster(user)
  859. #define RLARG(sys,frm)        " '%s!%s'",sys,frm
  860. #define LFROM(frm,now,host)    "From %s %.24s\n",frm,now
  861.  
  862. #else
  863.  
  864. #define HANDLE    ALL
  865. #define ROUTING JUSTDOMAIN
  866.  
  867. #ifdef BSD
  868. #define LMAIL(frm,sys)        "/bin/mail"    /* BSD local delivery agent */
  869. #else
  870. #define LMAIL(frm,sys)        "/bin/lmail"    /* SV  local delivery agent */
  871. #endif
  872.  
  873. #define LARG(user)        " '%s'",postmaster(user)
  874. #define RLARG(sys,frm)        " '%s!%s'",sys,frm
  875. #define LFROM(frm,now,host)    "From %s %.24s\n",frm,now
  876.  
  877. #endif
  878.  
  879. /*
  880. **    The following definitions affect the queueing algorithm for uux.
  881. **
  882. **    DEFQUEUE    if defined the default is to queue uux mail
  883. **
  884. **    QUEUECOST    remote mail with a cost of less than QUEUECOST
  885. **            will be handed to uux for immediate delivery.
  886. **
  887. **    MAXNOQUEUE    don't allow more than 'n' immediate delivery
  888. **            jobs to be started on a single invocation of smail.
  889. **    
  890. **    GETCOST        if defined, the paths file will be searched for
  891. **            each address to discover the cost of the route.
  892. **            this allows informed decisions about whether to
  893. **            use the queue flags when calling uux.  The price
  894. **            is in the overhead of a paths file search for
  895. **            addresses that are not going to be routed.
  896. */
  897.  
  898. #define DEFQUEUE            /* default is to queue uux jobs */
  899.  
  900. #define QUEUECOST        100    /* deliver immediately if the cost
  901.                     /* is DEDICATED+LOW or better */
  902.  
  903. #define MAXNOQUEUE        2    /* max UUX_NOQUEUE jobs         */
  904.  
  905. #define GETCOST                /* search for cost        */
  906.  
  907. #define UUX_QUEUE        "-r"    /* uux flag for queueing    */
  908. #define UUX_NOQUEUE        ""    /* uux with immediate delivery    */
  909.  
  910. /*
  911. ** Normally, all mail destined for the local host is delivered with a single
  912. ** call to the local mailer, and all remote mail is delivered with one call
  913. ** to the remote mailer for each remote host.  This kind of 'batching' saves
  914. ** on the cpu overhead.
  915. **
  916. ** MAXCLEN is used to limit the length of commands that are exec'd by smail.
  917. ** This is done to keep other program's buffers from overflowing, or to
  918. ** allow for less intelligent commands which can take only one argument
  919. ** at a time (e.g., 4.1 /bin/mail).  To disable the batching, set MAXCLEN
  920. ** a small value (like 0).
  921. */
  922.  
  923. #define MAXCLEN            128    /* longest command allowed (approx.)
  924.                     /* this is to keep other's buffers
  925.                     ** from overflowing
  926.                     */
  927.  
  928. /*
  929. ** PLEASE DON'T TOUCH THE REST
  930. */
  931.  
  932. #define SMLBUF    512    /* small buffer (handle one item) */
  933. #define BIGBUF    4096    /* handle lots of items */
  934.  
  935. #define MAXPATH    32    /* number of elements in ! path */
  936. #define MAXDOMS    16    /* number of subdomains in . domain */
  937. #define MAXARGS    500    /* number of arguments */
  938. #ifndef NULL
  939. #define NULL    0
  940. #endif
  941.  
  942. #define DEBUG         if (debug==YES) (void) printf
  943. #define ADVISE         if (debug!=NO) (void) printf
  944. #define error(stat,msg,a)    { (void) fprintf(stderr, msg, a); exit(stat); }
  945. #define lower(c)         ( isupper(c) ? c-'A'+'a' : c )
  946.  
  947.  
  948. enum eform {    /* format of addresses */
  949.     ERROR,         /* bad or invalidated format */
  950.     LOCAL,         /* just a local name */
  951.     DOMAIN,     /* user@domain or domain!user */
  952.     UUCP,        /* host!address */
  953.     ROUTE,        /* intermediate form - to be routed */
  954.     SENT        /* sent to a mailer on a previous pass */
  955. };
  956.  
  957. enum ehandle {     /* what addresses can we handle? (don't kick to LMAIL) */
  958.     ALL,        /* UUCP and DOMAIN addresses */
  959.     JUSTUUCP,    /* UUCP only; set by -l  */
  960.     NONE        /* all mail is LOCAL; set by -L */
  961. };
  962.  
  963. enum erouting {    /* when to route A!B!C!D */
  964.     JUSTDOMAIN,    /* route A if A is a domain */
  965.     ALWAYS,        /* route A always; set by -r */
  966.     REROUTE        /* route C, B, or A (whichever works); set by -R */
  967. };
  968.  
  969. enum edebug {    /* debug modes */
  970.     NO,        /* normal deliver */
  971.     VERBOSE,    /* talk alot */
  972.     YES        /* talk and don't deliver */
  973. };
  974.  
  975. #ifdef BSD
  976.  
  977. #include <strings.h>
  978. #include <sysexits.h>
  979.  
  980. #else
  981.  
  982. #include <string.h>
  983. #include "sysexits.h"
  984. #define    index    strchr
  985. #define    rindex    strrchr
  986.  
  987. #endif
  988. extern void exit(), perror();
  989. extern unsigned sleep();
  990. //E*O*F defs.h//
  991.  
  992. echo x - deliver.c
  993. cat > "deliver.c" << '//E*O*F deliver.c//'
  994. /*
  995. **  Deliver.c
  996. **
  997. **  Routines to effect delivery of mail for rmail/smail. 
  998. **
  999. */
  1000.  
  1001. #ifndef lint
  1002. static char     *sccsid="@(#)deliver.c    2.5 (smail) 9/15/87";
  1003. #endif
  1004.  
  1005. # include    <stdio.h>
  1006. # include    <sys/types.h>
  1007. # include    <sys/stat.h>
  1008. # include    <ctype.h>
  1009. # include    <signal.h>
  1010. # include    "defs.h"
  1011.  
  1012. extern int  exitstat;        /* set if a forked mailer fails */
  1013. extern enum edebug debug;    /* how verbose we are         */ 
  1014. extern char hostname[];        /* our uucp hostname         */
  1015. extern char hostdomain[];    /* our host's domain         */
  1016. extern enum ehandle handle;    /* what we handle        */
  1017. extern enum erouting routing;    /* how we're routing addresses  */
  1018. extern char *uuxargs;        /* arguments given to uux       */
  1019. extern int  queuecost;        /* threshold for queueing mail  */
  1020. extern int  maxnoqueue;        /* max number of uucico's       */
  1021. extern char *spoolfile;        /* file name of spooled message */
  1022. extern FILE *spoolfp;        /* file ptr  to spooled message */
  1023. extern int spoolmaster;        /* set if creator of spoolfile  */
  1024. extern char nows[];        /* local time in ctime(3) format*/
  1025. extern char arpanows[];        /* local time in arpadate format*/
  1026. char stderrfile[20];        /* error file for stderr traping*/
  1027.  
  1028. /*
  1029. **
  1030. **  deliver():  hand the letter to the proper mail programs.
  1031. **
  1032. **  Issues one command for each different host of <hostv>,
  1033. **  constructing the proper command for LOCAL or UUCP mail.
  1034. **  Note that LOCAL mail has blank host names.
  1035. **
  1036. **  The <userv> names for each host are arguments to the command.
  1037. ** 
  1038. **  Prepends a "From" line to the letter just before going 
  1039. **  out, with a "remote from <hostname>" if it is a UUCP letter.
  1040. **
  1041. */
  1042.  
  1043. deliver(argc, hostv, userv, formv, costv)
  1044. int argc;                /* number of addresses        */
  1045. char *hostv[];                /* host names            */
  1046. char *userv[];                /* user names            */
  1047. enum eform formv[];            /* form for each address    */
  1048. int costv[];                /* cost vector             */
  1049. {
  1050.     FILE *out;            /* pipe to mailer        */
  1051.     FILE *popen();            /* to fork a mailer         */
  1052. #ifdef RECORD
  1053.     void record();            /* record all transactions    */
  1054. #endif
  1055. #ifdef LOG
  1056.     void log();
  1057. #endif
  1058.     char *mktemp();
  1059.     char from[SMLBUF];        /* accumulated from argument     */
  1060.     char lcommand[SMLBUF];        /* local command issued     */
  1061.     char rcommand[SMLBUF];        /* remote command issued    */
  1062.     char scommand[SMLBUF];        /* retry  command issued    */
  1063.     char *command;            /* actual command        */
  1064.     char buf[SMLBUF];        /* copying rest of the letter   */
  1065.     enum eform form;        /* holds form[i] for speed     */
  1066.     long size;            /* number of bytes of message     */
  1067.     char *flags;            /* flags for uux        */
  1068.     char *sflag;            /* flag  for smail        */
  1069.     int i, j, status, retrying;
  1070.     char *c, *postmaster();
  1071.     int failcount = 0;
  1072.     int noqcnt = 0;            /* number of uucico's started   */
  1073.     char *uux_noqueue = UUX_NOQUEUE;/* uucico starts immediately    */
  1074.     char *uux_queue   = UUX_QUEUE;    /* uucico job gets queued       */
  1075.     off_t message;
  1076.     struct stat st;
  1077.  
  1078. /*
  1079. ** rewind the spool file and read the collapsed From_ line
  1080. */
  1081.     (void) fseek(spoolfp, 0L, 0);
  1082.     (void) fgets(from, sizeof(from), spoolfp);
  1083.     if((c = index(from, '\n')) != 0) *c = '\0';
  1084.     message = ftell(spoolfp);
  1085.  
  1086. /*
  1087. **  We pass through the list of addresses.
  1088. */
  1089.     stderrfile[0] = '\0';
  1090.     for(i = 0; i < argc; i++) {
  1091.         char *lend = lcommand;
  1092.         char *rend = rcommand;
  1093.         char *send = scommand;
  1094.  
  1095. /*
  1096. **  If we don't have sendmail, arrange to trap standard error
  1097. **  for inclusion in the message that is returned with failed mail.
  1098. */
  1099.         (void) unlink(stderrfile);
  1100.         (void) strcpy(stderrfile, "/tmp/stderrXXXXXX");
  1101.         (void) mktemp(stderrfile);
  1102.         (void) freopen(stderrfile, "w", stderr);
  1103.         if(debug != YES) {
  1104.             (void) freopen(stderrfile, "w", stdout);
  1105.         }
  1106.  
  1107.         *lend = *rend = *send = '\0';
  1108.  
  1109. /*
  1110. **  If form == ERROR, the address was bad 
  1111. **  If form == SENT, it has been sent on a  previous pass.
  1112. */
  1113.         form = formv[i];
  1114.         if (form == SENT) {
  1115.             continue;
  1116.         }
  1117. /*
  1118. **  Build the command based on whether this is local mail or uucp mail.
  1119. **  By default, don't allow more than 'maxnoqueue' uucico commands to
  1120. **  be started by a single invocation of 'smail'.
  1121. */
  1122.         if(uuxargs == NULL) {    /* flags not set on command line */
  1123.             if(noqcnt < maxnoqueue && costv[i] <= queuecost) {
  1124.                 flags = uux_noqueue;
  1125.             } else {
  1126.                 flags = uux_queue;
  1127.             }
  1128.         } else {
  1129.             flags = uuxargs;
  1130.         }
  1131.  
  1132.         retrying = 0;
  1133.         if(routing == JUSTDOMAIN) {
  1134.             sflag = "-r";
  1135.         } else if(routing == ALWAYS) {
  1136.             sflag = "-R";
  1137.         } else {
  1138.             sflag = "";
  1139.         }
  1140.  
  1141.         (void) sprintf(lcommand, LMAIL(from, hostv[i]));
  1142.         (void) sprintf(rcommand, RMAIL(flags, from, hostv[i]));
  1143.  
  1144. /*
  1145. **  For each address with the same host name and form, append the user
  1146. **  name to the command line, and set form = ERROR so we skip this address
  1147. **  on later passes. 
  1148. */
  1149.         /* we initialized lend (rend) to point at the
  1150.          * beginning of its buffer, so that at
  1151.          * least one address will be used regardless
  1152.          * of the length of lcommand (rcommand).
  1153.          */
  1154.         for (j = i; j < argc; j++) {
  1155.             if ((formv[j] != form)
  1156.              || (strcmpic(hostv[i], hostv[j]) != 0)
  1157.              || ((lend - lcommand) > MAXCLEN)
  1158.              || ((rend - rcommand) > MAXCLEN)) {
  1159.                 continue;
  1160.             }
  1161.  
  1162.             /*
  1163.             ** seek to the end of scommand
  1164.             ** and add on a 'smail' command
  1165.             ** multiple commands are separated by ';'
  1166.             */
  1167.  
  1168.             send += strlen(send);
  1169.             if(send != scommand) {
  1170.                 *send++ = ';' ;
  1171.             }
  1172.  
  1173.             (void) sprintf(send, RETRY(sflag));
  1174.             send += strlen(send);
  1175.  
  1176.             lend += strlen(lend);
  1177.             rend += strlen(rend);
  1178.  
  1179.             if (form == LOCAL) {
  1180.                 (void) sprintf(lend, LARG(userv[j]));
  1181.                 (void) sprintf(send, LARG(userv[j]));
  1182.             } else {
  1183.                 (void) sprintf(lend, RLARG(hostv[i], userv[j]));
  1184.                 (void) sprintf(send, RLARG(hostv[i], userv[j]));
  1185.             }
  1186.  
  1187.             (void) sprintf(rend, RARG(userv[j]));
  1188.             formv[j] = SENT;
  1189.         }
  1190. retry:
  1191. /*
  1192. ** rewind the spool file and read the collapsed From_ line
  1193. */
  1194.         (void) fseek(spoolfp, message, 0);
  1195.  
  1196.         /* if the address was in a bogus form (usually DOMAIN),
  1197.         ** then don't bother trying the uux.
  1198.         **
  1199.         ** Rather, go straight to the next smail routing level.
  1200.         */
  1201.         if(form == ERROR) {
  1202.             static char errbuf[SMLBUF];
  1203.             (void) sprintf(errbuf,
  1204.                 "address resolution ('%s' @ '%s') failed",
  1205.                     userv[i], hostv[i]);
  1206.             command = errbuf;
  1207.             size    = 0;
  1208.             goto form_error;
  1209.         }
  1210.  
  1211.         if (retrying) {
  1212.             command = scommand;
  1213.         } else if (form == LOCAL) {
  1214.             command = lcommand;
  1215.         } else {
  1216.             command = rcommand;
  1217.             if(flags == uux_noqueue) {
  1218.                 noqcnt++;
  1219.             }
  1220.         }
  1221.         ADVISE("COMMAND: %s\n", command);
  1222.  
  1223. /*
  1224. ** Fork the mailer and set it up for writing so we can send the mail to it,
  1225. ** or for debugging divert the output to stdout.
  1226. */
  1227.  
  1228. /*
  1229. ** We may try to write on a broken pipe, if the uux'd host
  1230. ** is unknown to us.  Ignore this signal, since we can use the
  1231. ** return value of the pclose() as our indication of failure.
  1232. */
  1233.         (void) signal(SIGPIPE, SIG_IGN);
  1234.  
  1235.         if (debug == YES) {
  1236.             out = stdout;
  1237.         } else {
  1238.             failcount = 0;
  1239.             do {
  1240.                 out = popen(command, "w");
  1241.                 if (out) break;
  1242.                 /*
  1243.                  * Fork failed.  System probably overloaded.
  1244.                  * Wait awhile and try again 10 times.
  1245.                  * If it keeps failing, probably some
  1246.                  * other problem, like no uux or smail.
  1247.                  */
  1248.                 (void) sleep(60);
  1249.             } while (++failcount < 10);
  1250.         }
  1251.         if(out == NULL) {
  1252.             exitstat = EX_UNAVAILABLE;
  1253.             (void) printf("couldn't execute %s.\n", command);
  1254.             continue;
  1255.         }
  1256.  
  1257.         size = 0;
  1258.         if(fstat(fileno(spoolfp), &st) >= 0) {
  1259.             size = st.st_size - message;
  1260.         }
  1261. /*
  1262. **  Output our From_ line.
  1263. */
  1264.         if (form == LOCAL) {
  1265. #ifdef SENDMAIL
  1266.             (void) sprintf(buf, LFROM(from, nows, hostname));
  1267.             size += strlen(buf);
  1268.             (void) fputs(buf, out);
  1269. #else
  1270.             char *p;
  1271.             if((p=index(from, '!')) == NULL) {
  1272.                 (void) sprintf(buf,
  1273.                     LFROM(from, nows, hostname));
  1274.                 size += strlen(buf);
  1275.                 (void) fputs(buf, out);
  1276.             } else {
  1277.                 *p = NULL;
  1278.                 (void) sprintf(buf, RFROM(p+1, nows, from));
  1279.                 size += strlen(buf);
  1280.                 (void) fputs(buf, out);
  1281.                 *p = '!';
  1282.             }
  1283. #endif
  1284.         } else {
  1285.             (void) sprintf(buf, RFROM(from, nows, hostname));
  1286.             size += strlen(buf);
  1287.             (void) fputs(buf, out);
  1288.         }
  1289.  
  1290. #ifdef SENDMAIL
  1291. /*
  1292. **  If using sendmail, insert a Received: line only for mail
  1293. **  that is being passed to uux.  If not using sendmail, always
  1294. **  insert the received line, since sendmail isn't there to do it.
  1295. */
  1296.         if(command == rcommand && handle != ALL)
  1297. #endif
  1298.         {
  1299.             (void) sprintf(buf,
  1300.                 "Received: by %s (%s)\n\tid AA%05d; %s\n",
  1301.                     hostdomain, VERSION,
  1302.                     getpid(), arpanows);
  1303.             size += strlen(buf);
  1304.             (void) fputs(buf, out);
  1305.         }
  1306.  
  1307. /*
  1308. **  Copy input.
  1309. */
  1310.         while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
  1311.             (void) fputs(buf, out);
  1312.         }
  1313. /*
  1314. **  Get exit status and if non-zero, set global exitstat so when we exit
  1315. **  we can indicate an error.
  1316. */
  1317. form_error:
  1318.         if (debug != YES) {
  1319.             if(form == ERROR) {
  1320.                 exitstat = EX_NOHOST;
  1321.             } else if (status = pclose(out)) {
  1322.                 exitstat = status >> 8;
  1323.             }
  1324.             /*
  1325.              * The 'retrying' check prevents a smail loop.
  1326.              */
  1327.             if(exitstat != 0) {
  1328.                 /*
  1329.                 ** the mail failed, probably because the host
  1330.                 ** being uux'ed isn't in L.sys or local user
  1331.                 ** is unknown.
  1332.                 */
  1333.  
  1334.                 if((retrying == 0)    /* first pass */
  1335.                 && (routing != REROUTE)    /* have higher level */
  1336.                 && (form != LOCAL)) {    /* can't route local */
  1337.                     /*
  1338.                     ** Try again using a higher
  1339.                     ** level of routing.
  1340.                     */
  1341.                     ADVISE("%s failed (%d)\ntrying %s\n",
  1342.                         command, exitstat, scommand);
  1343.                     exitstat = 0;
  1344.                     retrying = 1;
  1345.                     form = SENT;
  1346.                     goto retry;
  1347.                 }
  1348.  
  1349.                 /*
  1350.                 ** if we have no other routing possibilities
  1351.                 ** see that the mail is returned to sender.
  1352.                 */
  1353.  
  1354.                 if((routing == REROUTE)
  1355.                     || (form == LOCAL)) {
  1356.  
  1357.                     /*
  1358.                     ** if this was our last chance,
  1359.                     ** return the mail to the sender.
  1360.                     */
  1361.  
  1362.                     ADVISE("%s failed (%d)\n",
  1363.                         command, exitstat);
  1364.                     
  1365.                     (void) fseek(spoolfp, message, 0);
  1366. #ifdef SENDMAIL
  1367.                     /* if we have sendmail, then it
  1368.                     ** was handed the mail, which failed.
  1369.                     ** sendmail returns the failed mail
  1370.                     ** for us, so we need not do it again.
  1371.                     */
  1372.                     if(form != LOCAL)
  1373. #endif
  1374.                     {
  1375.                         return_mail(from, command);
  1376.                     }
  1377.                     exitstat = 0;
  1378.                 }
  1379.             }
  1380. # ifdef LOG
  1381.             else {
  1382.                 if(retrying == 0) log(command, from, size); /* */
  1383.             }
  1384. # endif
  1385.         }
  1386.     }
  1387. /*
  1388. **  Update logs and records.
  1389. */
  1390. # ifdef RECORD
  1391.     (void) fseek(spoolfp, message, 0);
  1392.     record(command, from, size);
  1393. # endif
  1394.  
  1395. /*
  1396. **  close spool file pointer.
  1397. **  if we created it, then unlink file.
  1398. */
  1399.     (void) fclose(spoolfp);
  1400.     if(spoolmaster) {
  1401.         (void) unlink(spoolfile);
  1402.     }
  1403.     (void) unlink(stderrfile);
  1404. }
  1405.  
  1406. /*
  1407. ** return mail to sender, as determined by From_ line.
  1408. */
  1409. return_mail(from, fcommand)
  1410. char *from, *fcommand;
  1411. {
  1412.     char buf[SMLBUF];
  1413.     char domain[SMLBUF], user[SMLBUF];
  1414.     char *r;
  1415.     FILE *fp, *out, *popen();
  1416.     int i = 0;
  1417.  
  1418.     r = buf;
  1419.  
  1420.     (void) sprintf(r, "%s %s", SMAIL, VFLAG);
  1421.     r += strlen(r);
  1422.  
  1423.     if(islocal(from, domain, user)) {
  1424.         (void) sprintf(r, LARG(user));
  1425.     } else {
  1426.         (void) sprintf(r, RLARG(domain, user));
  1427.     }
  1428.  
  1429.     i = 0;
  1430.     do {
  1431.         out = popen(buf, "w");
  1432.         if (out) break;
  1433.         /*
  1434.          * Fork failed.  System probably overloaded.
  1435.          * Wait awhile and try again 10 times.
  1436.          * If it keeps failing, probably some
  1437.          * other problem, like no uux or smail.
  1438.          */
  1439.         (void) sleep(60);
  1440.     } while (++i < 10);
  1441.  
  1442.     if(out == NULL) {
  1443.         (void) printf("couldn't execute %s.\n", buf);
  1444.         return;
  1445.     }
  1446.  
  1447.     (void) fprintf(out, "Date: %s\n", arpanows);
  1448.     (void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain);
  1449.     (void) fprintf(out, "Subject: failed mail\n");
  1450.     (void) fprintf(out, "To: %s\n", from);
  1451.     (void) fprintf(out, "\n");
  1452.     (void) fprintf(out, "=======     command failed      =======\n\n");
  1453.     (void) fprintf(out, " COMMAND: %s\n\n", fcommand);
  1454.  
  1455.     (void) fprintf(out, "======= standard error follows  =======\n");
  1456.     (void) fflush(stderr);
  1457.     if((fp = fopen(stderrfile, "r")) != NULL) {
  1458.         while(fgets(buf, sizeof(buf), fp) != NULL) {
  1459.             (void) fputs(buf, out);
  1460.         }
  1461.     }
  1462.     (void) fclose(fp);
  1463.     (void) fprintf(out, "======= text of message follows =======\n");
  1464. /*
  1465. **  Copy input.
  1466. */
  1467.     (void) fprintf(out, "From %s\n", from);
  1468.     while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
  1469.         (void) fputs(buf, out);
  1470.     }
  1471.     (void) pclose(out);
  1472. }
  1473. //E*O*F deliver.c//
  1474.  
  1475. echo x - getopt.c
  1476. cat > "getopt.c" << '//E*O*F getopt.c//'
  1477. /*
  1478. **    @(#)getopt.c    2.5 (smail) 9/15/87
  1479. */
  1480.  
  1481. /*
  1482.  * Here's something you've all been waiting for:  the AT&T public domain
  1483.  * source for getopt(3).  It is the code which was given out at the 1985
  1484.  * UNIFORUM conference in Dallas.  I obtained it by electronic mail
  1485.  * directly from AT&T.  The people there assure me that it is indeed
  1486.  * in the public domain.
  1487.  * 
  1488.  * There is no manual page.  That is because the one they gave out at
  1489.  * UNIFORUM was slightly different from the current System V Release 2
  1490.  * manual page.  The difference apparently involved a note about the
  1491.  * famous rules 5 and 6, recommending using white space between an option
  1492.  * and its first argument, and not grouping options that have arguments.
  1493.  * Getopt itself is currently lenient about both of these things White
  1494.  * space is allowed, but not mandatory, and the last option in a group can
  1495.  * have an argument.  That particular version of the man page evidently
  1496.  * has no official existence, and my source at AT&T did not send a copy.
  1497.  * The current SVR2 man page reflects the actual behavor of this getopt.
  1498.  * However, I am not about to post a copy of anything licensed by AT&T.
  1499.  */
  1500.  
  1501. /* This include is needed only to get "index" defined as "strchr" on Sys V. */
  1502. #include "defs.h"
  1503.  
  1504. /*LINTLIBRARY*/
  1505. #define NULL    0
  1506. #define EOF    (-1)
  1507. #define ERR(s, c)    if(opterr){\
  1508.     extern int write();\
  1509.     char errbuf[2];\
  1510.     errbuf[0] = c; errbuf[1] = '\n';\
  1511.     (void) write(2, argv[0], (unsigned)strlen(argv[0]));\
  1512.     (void) write(2, s, (unsigned)strlen(s));\
  1513.     (void) write(2, errbuf, 2);}
  1514.  
  1515. extern char *index();
  1516.  
  1517. int    opterr = 1;
  1518. int    optind = 1;
  1519. int    optopt;
  1520. char    *optarg;
  1521.  
  1522. int
  1523. getopt(argc, argv, opts)
  1524. int    argc;
  1525. char    **argv, *opts;
  1526. {
  1527.     static int sp = 1;
  1528.     register int c;
  1529.     register char *cp;
  1530.  
  1531.     if(sp == 1)
  1532.         if(optind >= argc ||
  1533.            argv[optind][0] != '-' || argv[optind][1] == '\0')
  1534.             return(EOF);
  1535.         else if(strcmp(argv[optind], "--") == NULL) {
  1536.             optind++;
  1537.             return(EOF);
  1538.         }
  1539.     optopt = c = argv[optind][sp];
  1540.     if(c == ':' || (cp=index(opts, c)) == NULL) {
  1541.         ERR(": illegal option -- ", c);
  1542.         if(argv[optind][++sp] == '\0') {
  1543.             optind++;
  1544.             sp = 1;
  1545.         }
  1546.         return('?');
  1547.     }
  1548.     if(*++cp == ':') {
  1549.         if(argv[optind][sp+1] != '\0')
  1550.             optarg = &argv[optind++][sp+1];
  1551.         else if(++optind >= argc) {
  1552.             ERR(": option requires an argument -- ", c);
  1553.             sp = 1;
  1554.             return('?');
  1555.         } else
  1556.             optarg = argv[optind++];
  1557.         sp = 1;
  1558.     } else {
  1559.         if(argv[optind][++sp] == '\0') {
  1560.             sp = 1;
  1561.             optind++;
  1562.         }
  1563.         optarg = NULL;
  1564.     }
  1565.     return(c);
  1566. }
  1567. //E*O*F getopt.c//
  1568.  
  1569. echo x - getpath.c
  1570. cat > "getpath.c" << '//E*O*F getpath.c//'
  1571. #ifndef lint
  1572. static char     *sccsid="@(#)getpath.c    2.5 (smail) 9/15/87";
  1573. #endif
  1574.  
  1575. # include    <stdio.h>
  1576. # include    <sys/types.h>
  1577. # include    <ctype.h>
  1578. # include    "defs.h"
  1579.  
  1580. extern enum edebug debug;    /* how verbose we are         */ 
  1581. extern char *pathfile;        /* location of path database    */
  1582.  
  1583. /*
  1584. **
  1585. ** getpath(): look up key in ascii sorted path database.
  1586. **
  1587. */
  1588.  
  1589. getpath( key, path , cost)
  1590. char *key;        /* what we are looking for */
  1591. char *path;        /* where the path results go */
  1592. int *cost;        /* where the cost results go */
  1593. {
  1594.     long pos, middle, hi, lo;
  1595.     static long pathlength = 0;
  1596.     register char *s;
  1597.     int c;
  1598.     static FILE *file;
  1599.     int flag;
  1600.  
  1601. DEBUG("getpath: looking for '%s'\n", key);
  1602.  
  1603.     if(pathlength == 0) {    /* open file on first use */
  1604.         if((file = fopen(pathfile, "r")) == NULL) {
  1605.             (void) printf("can't access %s.\n", pathfile);
  1606.             pathlength = -1;
  1607.         } else {
  1608.             (void) fseek(file, 0L, 2);    /* find length */
  1609.             pathlength = ftell(file);
  1610.         }
  1611.     }
  1612.     if( pathlength == -1 )
  1613.         return( EX_OSFILE );
  1614.  
  1615.     lo = 0;
  1616.     hi = pathlength;
  1617.     (void) strcpy( path, key );
  1618.     (void) strcat( path, "\t" );
  1619. /*
  1620. ** "Binary search routines are never written right the first time around."
  1621. ** - Robert G. Sheldon.
  1622. */
  1623.     for( ;; ) {
  1624.         pos = middle = ( hi+lo+1 )/2;
  1625.         (void) fseek(file, pos, 0);    /* find midpoint */
  1626.         if(pos != 0)
  1627.             while(((c = getc(file)) != EOF) && (c != '\n'))
  1628.                 ;    /* go to beginning of next line */
  1629.         if(c == EOF) {
  1630.             return(EX_NOHOST);
  1631.         }
  1632.         for( flag = 0, s = path; flag == 0; s++ ) { /* match??? */
  1633.             if( *s == '\0' ) {
  1634.                 goto solved;
  1635.             }
  1636.             if((c = getc(file)) == EOF) {
  1637.                 return(EX_NOHOST);
  1638.             }
  1639.             flag = lower(c) - lower(*s);
  1640.         } 
  1641.         if(lo >= middle) {        /* failure? */
  1642.             return(EX_NOHOST);
  1643.         }
  1644.         if((c != EOF) && (flag < 0)) {    /* close window */
  1645.             lo = middle;
  1646.         } else {
  1647.             hi = middle - 1;
  1648.         }
  1649.     }
  1650. /* 
  1651. ** Now just copy the result.
  1652. */
  1653. solved:
  1654.     while(((c  = getc(file)) != EOF) && (c != '\t') && (c != '\n')) {
  1655.         *path++ = c;
  1656.     }
  1657.     *path = '\0';
  1658. /*
  1659. ** See if the next field on the line is numeric.
  1660. ** If so, use it as the cost for the route.
  1661. */
  1662.     if(c == '\t') {
  1663.         int tcost = -1;
  1664.         while(((c = getc(file)) != EOF) && isdigit(c)) {
  1665.             if(tcost < 0) tcost = 0;
  1666.             tcost *= 10;
  1667.             tcost += c - '0';
  1668.         }
  1669.         if(tcost >= 0) *cost = tcost;
  1670.     }
  1671.     return (EX_OK);
  1672. }
  1673. //E*O*F getpath.c//
  1674.  
  1675. echo x - headers.c
  1676. cat > "headers.c" << '//E*O*F headers.c//'
  1677. /*
  1678. **  message spooing, header and address parsing and completion
  1679. **  functions for smail/rmail
  1680. */
  1681.  
  1682. #ifndef lint
  1683. static char     *sccsid="@(#)headers.c    2.5 (smail) 9/15/87";
  1684. #endif
  1685.  
  1686. # include    <stdio.h>
  1687. # include    <sys/types.h>
  1688. # include    <time.h>
  1689. # include    <ctype.h>
  1690. # include    <pwd.h>
  1691. # include    "defs.h"
  1692.  
  1693. extern enum edebug debug;    /* how verbose we are         */ 
  1694. extern char hostname[];        /* */
  1695. extern char hostdomain[];    /* */
  1696. extern char *spoolfile;        /* file name of spooled message */
  1697. extern FILE *spoolfp;        /* file ptr  to spooled message */
  1698. extern int spoolmaster;        /* set if creator of spoolfile  */
  1699. extern time_t now;        /* time                */
  1700. extern char nows[], arpanows[];    /* time strings            */
  1701. extern struct tm *gmt, *loc;    /* time structs            */
  1702. extern char *from_addr;        /* replacement fromaddr with -F */
  1703.  
  1704. static char toline[SMLBUF];
  1705. static char fromline[SMLBUF];
  1706. static char dateline[SMLBUF];
  1707. static char midline[SMLBUF];
  1708. static char *ieof = "NOTNULL";
  1709.  
  1710. struct reqheaders {
  1711.     char *name;
  1712.     char *field;
  1713.     char have;
  1714. };
  1715.  
  1716. static struct reqheaders reqtab[] = {
  1717.     "Message-Id:"    ,    midline        ,    'N'    ,
  1718.     "Date:"        ,    dateline    ,    'N'    ,
  1719.     "From:"        ,    fromline    ,    'N'    ,
  1720.     "To:"        ,    toline        ,    'N'    ,
  1721.     NULL         ,    NULL        ,    'N'
  1722. };
  1723.  
  1724.  
  1725. /*
  1726. **
  1727. ** parse(): parse <address> into <domain, user, form>.
  1728. **
  1729. **     input        form
  1730. **    -----        ----
  1731. **    user        LOCAL
  1732. **    domain!user    DOMAIN
  1733. **    user@domain    DOMAIN
  1734. **    @domain,address    LOCAL    (just for sendmail)
  1735. **    host!address    UUCP
  1736. **
  1737. */
  1738.  
  1739. enum eform
  1740. parse(address, domain, user)
  1741. char *address;        /* input address     */
  1742. char *domain;        /* output domain     */
  1743. char *user;        /* output user         */
  1744. {
  1745.     int parts;
  1746.     char *partv[MAXPATH];                /* to crack address */
  1747.  
  1748. /*
  1749. **  If this is route address form @domain_a,@domain_b:user@domain_c, ...
  1750. */
  1751.     if(*address == '@')
  1752. #ifdef SENDMAIL
  1753. /*
  1754. **  hand it to sendmail
  1755. */
  1756.     {
  1757.         goto local;
  1758.     }
  1759. #else
  1760. /*
  1761. **  no sendmail, convert it into a bang path: domain_a!domain_b!domain_c!user
  1762. */
  1763.     {
  1764.         char buf[SMLBUF], *p;
  1765.         char t_dom[SMLBUF], t_user[SMLBUF];
  1766.  
  1767.         (void) strcpy(buf, address+1);        /* elide leading '@' */
  1768.  
  1769.         for(p=buf; *p != '\0' ; p++) {    /* search for ',' or ':' */
  1770.             if(*p == ':') {        /* reached end of route */
  1771.                 break;
  1772.             }
  1773.             if(*p == ',') {        /* elide ','s */
  1774.                 (void) strcpy(p, p+1);
  1775.             }
  1776.             if(*p == '@') {        /* convert '@' to '!' */
  1777.                 *p = '!';
  1778.             }
  1779.         }
  1780.  
  1781.         if(*p != ':') {    /* bad syntax - punt */
  1782.             goto local;
  1783.         }
  1784.         *p = '\0';
  1785.  
  1786.         if(parse(p+1, t_dom, t_user) != LOCAL) {
  1787.             (void) strcat(buf, "!");
  1788.             (void) strcat(buf, t_dom);
  1789.         }
  1790.         (void) strcat(buf, "!");
  1791.         (void) strcat(buf, t_user);
  1792.  
  1793.         /* munge the address (yuk)
  1794.         ** it's OK to copy into 'address', because the machinations
  1795.         ** above don't increase the string length of the address.
  1796.         */
  1797.  
  1798.         (void) strcpy(address, buf);
  1799.  
  1800.         /* re-parse the address */
  1801.         return(parse(address, domain, user));
  1802.     }
  1803. #endif
  1804. /*
  1805. **  Try splitting at @.  If it works, this is user@domain, form DOMAIN.
  1806. **  Prefer the righthand @ in a@b@c.
  1807. */
  1808.     if ((parts = ssplit(address, '@', partv)) >= 2) {
  1809.         (void) strcpy(domain, partv[parts-1]);
  1810.         (void) strncpy(user, partv[0], partv[parts-1]-partv[0]-1);
  1811.         user[partv[parts-1]-partv[0]-1] = '\0';
  1812.         return (DOMAIN);
  1813.     } 
  1814. /*
  1815. **  Try splitting at !. If it works, see if the piece before the ! has
  1816. **  a . in it (domain!user, form DOMAIN) or not (host!user, form UUCP).
  1817. */
  1818.     if (ssplit(address, '!', partv) > 1) {
  1819.         (void) strcpy(user, partv[1]);
  1820.         (void) strncpy(domain, partv[0], partv[1]-partv[0]-1);
  1821.         domain[partv[1]-partv[0]-1] = '\0';
  1822.  
  1823.         if((parts = ssplit(domain, '.', partv)) < 2) {
  1824.             return(UUCP);
  1825.         }
  1826.  
  1827.         if(partv[parts-1][0] == '\0') {
  1828.             partv[parts-1][-1] = '\0'; /* strip trailing . */
  1829.         }
  1830.         return (DOMAIN);
  1831.     }
  1832. /* 
  1833. **  Done trying.  This must be just a user name, form LOCAL.
  1834. */
  1835. local:
  1836.     (void) strcpy(user, address);
  1837.     (void) strcpy(domain, "");
  1838.     return(LOCAL);                /* user */
  1839. }
  1840.  
  1841. build(domain, user, form, result)
  1842. char *domain;
  1843. char *user;
  1844. enum eform form;
  1845. char *result;
  1846. {
  1847.     switch((int) form) {
  1848.     case LOCAL:
  1849.         (void) sprintf(result, "%s", user); 
  1850.         break;
  1851.     case UUCP:
  1852.         (void) sprintf(result, "%s!%s", domain, user);
  1853.         break;
  1854.     case DOMAIN:
  1855.         (void) sprintf(result, "%s@%s", user, domain);
  1856.         break;
  1857.     }
  1858. }
  1859.  
  1860. /*
  1861. **  ssplit(): split a line into array pointers.
  1862. **
  1863. **  Each pointer wordv[i] points to the first character after the i'th 
  1864. **  occurence of c in buf.  Note that each wordv[i] includes wordv[i+1].
  1865. **
  1866. */
  1867.  
  1868. ssplit(buf, c, ptr)
  1869. register char *buf;        /* line to split up         */
  1870. char c;                /* character to split on    */
  1871. char **ptr;            /* the resultant vector        */
  1872. {
  1873.         int count = 0;
  1874.         int wasword = 0;
  1875.  
  1876.         for(; *buf; buf++) {
  1877.         if (!wasword) {
  1878.             count++;
  1879.             *ptr++ = buf;
  1880.         }
  1881.         wasword = (c != *buf);
  1882.         }
  1883.     if (!wasword) {
  1884.         count++;
  1885.         *ptr++ = buf;
  1886.     }
  1887.         *ptr = NULL;
  1888.         return(count);
  1889. }
  1890.  
  1891. /*
  1892. ** Determine whether an address is a local address
  1893. */
  1894.  
  1895. islocal(addr, domain, user)
  1896. char *addr, *domain, *user;
  1897. {
  1898.         enum eform form, parse();
  1899.         extern char hostuucp[];
  1900.  
  1901.         /*
  1902.         ** parse the address
  1903.         */
  1904.  
  1905.         form = parse(addr, domain, user);
  1906.  
  1907.         if((form == LOCAL)            /* user */
  1908.         ||(strcmpic(domain, hostdomain) == 0)    /* user@hostdomain */
  1909.         ||(strcmpic(domain, hostname)   == 0)    /* user@hostname */
  1910. #ifdef DOMGATE
  1911.         ||(strcmpic(domain, &MYDOM[0]) == 0)    /* user@MYDOM w/ dot */
  1912.         ||(strcmpic(domain, &MYDOM[1]) == 0)    /* user@MYDOM no dot */
  1913. #endif
  1914.         ||(strcmpic(domain, hostuucp)   == 0)) {/* user@hostuucp */
  1915.             return(1);
  1916.         }
  1917.         return(0);
  1918. }
  1919.  
  1920. /*
  1921. ** spool - message spooling module
  1922. **
  1923. ** (1) get dates for headers, etc.
  1924. ** (2) if the message is on the standard input (no '-f')
  1925. **     (a) create a temp file for spooling the message.
  1926. **     (b) collapse the From_ headers into a path.
  1927. **     (c) if the mail originated locally, then
  1928. **         (i) establish default headers
  1929. **        (ii) scan the message headers for required header fields
  1930. **       (iii) add any required message headers that are absent
  1931. **     (d) copy rest of the message to the spool file
  1932. **     (e) close the spool file
  1933. ** (3) open the spool file for reading
  1934. */
  1935.  
  1936. void
  1937. spool(argc, argv)
  1938. int argc;
  1939. char **argv;
  1940. {
  1941.     static char *tmpf = "/tmp/rmXXXXXX";    /* temp file name */
  1942.     char *mktemp();
  1943.     char buf[SMLBUF];
  1944.     static char splbuf[SMLBUF];
  1945.     char from[SMLBUF], domain[SMLBUF], user[SMLBUF];
  1946.     void rline(), scanheaders(), compheaders();
  1947.  
  1948.     /*
  1949.     ** if the mail has already been spooled by
  1950.     ** a previous invocation of smail don't respool.
  1951.     ** check the file name to prevent things like
  1952.     ** rmail -f /etc/passwd badguy@dreadfuldomain
  1953.     */
  1954.  
  1955.     if((spoolfile != NULL)
  1956.     && (strncmp(spoolfile, tmpf, strlen(tmpf) - 6) != 0)) {
  1957.         error(EX_TEMPFAIL, "spool: bad file name '%s'\n", spoolfile);
  1958.     }
  1959.  
  1960.     /*
  1961.     ** set dates in local, arpa, and gmt forms
  1962.     */
  1963.     setdates();
  1964.  
  1965.     /*
  1966.     ** If necessary, copy stdin to a temp file.
  1967.     */
  1968.  
  1969.     if(spoolfile == NULL) {
  1970.         spoolfile = strcpy(splbuf, tmpf);
  1971.         (void) mktemp(spoolfile);
  1972.  
  1973.         if((spoolfp = fopen(spoolfile, "w")) == NULL) {
  1974.             error(EX_CANTCREAT, "can't create %s.\n", spoolfile);
  1975.         }
  1976.  
  1977.         spoolmaster = 1;
  1978.  
  1979.         /*
  1980.         ** rline reads the standard input,
  1981.         ** collapsing the From_ and >From_
  1982.         ** lines into a single uucp path.
  1983.         ** first non-from_ line is in buf[];
  1984.         */
  1985.  
  1986.         rline(from, buf);
  1987.  
  1988.         /*
  1989.         ** if the mail originated here, we parse the header
  1990.         ** and add any required headers that are missing.
  1991.         */
  1992.  
  1993.         if(islocal(from, domain, user) || (from_addr != NULL)) {
  1994.             /*
  1995.             ** initialize default headers
  1996.             */
  1997.             def_headers(argc, argv, from);
  1998.  
  1999.             /*
  2000.             ** buf has first, non-from_  line
  2001.             */
  2002.             scanheaders(buf);
  2003.             /*
  2004.             ** buf has first, non-header line,
  2005.             */
  2006.  
  2007.             compheaders();
  2008.  
  2009.             if(buf[0] != '\n') {
  2010.                 (void) fputs("\n", spoolfp);
  2011.             }
  2012.         }
  2013.  
  2014.         /*
  2015.         ** now, copy the rest of the letter into the spool file
  2016.         ** terminate on either EOF or '^.$'
  2017.         */
  2018.  
  2019.         while(ieof != NULL) {
  2020.             (void) fputs(buf, spoolfp);
  2021.             if((fgets(buf, SMLBUF, stdin) == NULL)
  2022.             || (buf[0] == '.' && buf[1] == '\n')) {
  2023.                 ieof = NULL;
  2024.             }
  2025.         }
  2026.  
  2027.         /*
  2028.         ** close the spool file, and the standard input.
  2029.         */
  2030.  
  2031.         (void) fclose(spoolfp);
  2032.         (void) fclose(stdin);    /* you don't see this too often! */
  2033.     }
  2034.  
  2035.     if((spoolfp = fopen(spoolfile, "r")) == NULL) {
  2036.         error(EX_TEMPFAIL, "can't open %s.\n", spoolfile);
  2037.     }
  2038. }
  2039.  
  2040. /*
  2041. **
  2042. **  rline(): collapse From_ and >From_ lines.
  2043. **
  2044. **  Same idea as the old rmail, but also turns user@domain to domain!user. 
  2045. **
  2046. */
  2047.  
  2048. void
  2049. rline(from, retbuf)
  2050. char *from;
  2051. char *retbuf;
  2052. {
  2053.     int parts;            /* for cracking From_ lines ... */
  2054.     char *partv[16];        /* ... apart using ssplit()     */
  2055.     char user[SMLBUF];        /* for rewriting user@host    */
  2056.     char domain[SMLBUF];        /* "   "         "              */
  2057.     char addr[SMLBUF];        /* "   "         "              */
  2058.     enum eform form, parse();    /* "   "         "              */
  2059.     extern build();            /* "   "         "              */
  2060.     char *c;
  2061.     int nhops, i;
  2062.     char buf[SMLBUF], tmp[SMLBUF], *hop[128], *e, *b;
  2063.     char *pwuid();
  2064.  
  2065.     if(spoolmaster == 0) return;
  2066.  
  2067.     buf[0] = from[0] = addr[0] = '\0';
  2068. /*
  2069. **  Read each line until we hit EOF or a line not beginning with "From "
  2070. **  or ">From " (called From_ lines), accumulating the new path in from
  2071. **  and stuffing the actual sending user (the user name on the last From_ 
  2072. **  line) in addr.
  2073. */
  2074.     for(;;) {
  2075.         (void) strcpy(retbuf, buf);
  2076.         if(ieof == NULL) {
  2077.             break;
  2078.         }
  2079.         if((fgets(buf, sizeof(buf), stdin) == NULL)
  2080.         || (buf[0] == '.' && buf[1] == '\n')) {
  2081.             ieof = NULL;
  2082.             break;
  2083.         }
  2084.         if (strncmp("From ", buf, 5) 
  2085.             && strncmp(">From ", buf, 6)) {
  2086.             break;
  2087.         }
  2088. /*
  2089. **  Crack the line apart using ssplit.
  2090. */
  2091.         if(c = index(buf, '\n')) {
  2092.             *c = '\0';
  2093.         }
  2094.         parts = ssplit(buf, ' ', partv);
  2095. /*
  2096. **  Tack host! onto the from argument if "remote from host" is present.
  2097. */
  2098.  
  2099.         if((parts > 3)
  2100.         && (strncmp("remote from ", partv[parts-3], 12) == 0)) {
  2101.             (void) strcat(from, partv[parts-1]);
  2102.             (void) strcat(from, "!");
  2103.         }
  2104. /*
  2105. **  Stuff user name into addr, overwriting the user name from previous 
  2106. **  From_ lines, since only the last one counts.  Then rewrite user@host 
  2107. **  into host!user, since @'s don't belong in the From_ argument.
  2108. */
  2109.         if(parts < 2) {
  2110.             break;
  2111.         } else {
  2112.             char *x = partv[1];
  2113.             char *q = index(x, ' ');
  2114.             if(q != NULL) {
  2115.                 *q = '\0';
  2116.             }
  2117.             (void) strcpy(addr, x);
  2118.         }
  2119.  
  2120.         (void) parse(addr, domain, user);
  2121.         if(*domain == '\0') {
  2122.             form = LOCAL;
  2123.         } else {
  2124.             form = UUCP;
  2125.         }
  2126.  
  2127.         build(domain, user, form, addr);
  2128.     }
  2129. /*
  2130. **  Now tack the user name onto the from argument.
  2131. */
  2132.     (void) strcat(from, addr);
  2133. /*
  2134. **  If we still have no from argument, we have junk headers, but we try
  2135. **  to get the user's name using /etc/passwd.
  2136. */
  2137.  
  2138.     if (from[0] == '\0') {
  2139.         char *login;
  2140.         if ((login = pwuid(getuid())) == NULL) {
  2141.             (void) strcpy(from, "nobody");    /* bad news */
  2142.         } else {
  2143.             (void) strcpy(from, login);
  2144.         }
  2145.     }
  2146.  
  2147.     /* split the from line on '!'s */
  2148.     nhops = ssplit(from, '!', hop);
  2149.  
  2150.     for(i = 0; i < (nhops - 1); i++) {
  2151.         b = hop[i];
  2152.         if(*b == '\0') {
  2153.             continue;
  2154.         }
  2155.         e = hop[i+1];
  2156.         e-- ;
  2157.         *e = '\0';    /* null terminate each path segment */
  2158.         e++;
  2159.  
  2160. #ifdef HIDDENHOSTS
  2161. /*
  2162. **  Strip hidden hosts:  anything.hostname.MYDOM -> hostname.MYDOM
  2163. */
  2164.         for(p = b;(p = index(p, '.')) != NULL; p++) {
  2165.             if(strcmpic(hostdomain, p+1) == 0) {
  2166.                 (void) strcpy(b, hostdomain);
  2167.                 break;
  2168.             }
  2169.         }
  2170. #endif
  2171.  
  2172. /*
  2173. **  Strip useless MYDOM: hostname.MYDOM -> hostname
  2174. */
  2175.         if(strcmpic(hop[i], hostdomain) == 0) {
  2176.             (void) strcpy(hop[i], hostname);
  2177.         }
  2178.     }
  2179.  
  2180. /*
  2181. **  Now strip out any redundant information in the From_ line
  2182. **  a!b!c!c!d    => a!b!c!d
  2183. */
  2184.  
  2185.     for(i = 0; i < (nhops - 2); i++) {
  2186.         b = hop[i];
  2187.         e = hop[i+1];
  2188.         if(strcmpic(b, e) == 0) {
  2189.             *b = '\0';
  2190.         }
  2191.     }
  2192. /*
  2193. **  Reconstruct the From_ line
  2194. */
  2195.     tmp[0] = '\0';            /* empty the tmp buffer */
  2196.  
  2197.     for(i = 0; i < (nhops - 1); i++) {
  2198.         if((hop[i][0] == '\0')    /* deleted this hop */
  2199.          ||((tmp[0] == '\0')    /* first hop == hostname */
  2200.           &&(strcmpic(hop[i], hostname) == 0))) {
  2201.             continue;
  2202.         }
  2203.         (void) strcat(tmp, hop[i]);
  2204.         (void) strcat(tmp, "!");
  2205.     }
  2206.     (void) strcat(tmp, hop[i]);
  2207.     (void) strcpy(from, tmp);
  2208.     (void) strcpy(retbuf, buf);
  2209.     (void) fprintf(spoolfp, "%s\n", from);
  2210. }
  2211.  
  2212. void
  2213. scanheaders(buf)
  2214. char *buf;
  2215. {
  2216.     int inheader = 0;
  2217.  
  2218.     while(ieof != NULL) {
  2219.         if(buf[0] == '\n') {
  2220.             break; /* end of headers */
  2221.         }
  2222.  
  2223.         /*
  2224.         ** header lines which begin with whitespace
  2225.         ** are continuation lines
  2226.         */
  2227.         if((inheader == 0)
  2228.         || ((buf[0] != ' ' && buf[0] != '\t'))) {
  2229.             /* not a continuation line
  2230.             ** check for header
  2231.             */
  2232.             if(isheader(buf) == 0) {
  2233.                 /*
  2234.                 ** not a header
  2235.                 */
  2236.                 break;
  2237.             }
  2238.             inheader = 1;
  2239.             haveheaders(buf);
  2240.         }
  2241.         (void) fputs(buf, spoolfp);
  2242.         if((fgets(buf, SMLBUF, stdin) == NULL)
  2243.         || (buf[0] == '.' && buf[1] == '\n')) {
  2244.             ieof = NULL;
  2245.         }
  2246.     }
  2247.  
  2248.     if(isheader(buf)) {
  2249.         buf[0] = '\0';
  2250.     }
  2251. }
  2252.  
  2253. /*
  2254. ** complete headers - add any required headers that are not in the message
  2255. */
  2256. void
  2257. compheaders()
  2258. {
  2259.     struct reqheaders *i;
  2260.  
  2261.     /*
  2262.     ** look at the table of required headers and
  2263.     ** add those that are missing to the spooled message.
  2264.     */
  2265.     for(i = reqtab; i->name != NULL; i++) {
  2266.         if(i->have != 'Y') {
  2267.             (void) fprintf(spoolfp, "%s\n", i->field);
  2268.         }
  2269.     }
  2270. }
  2271.  
  2272. /*
  2273. ** look at a string and determine
  2274. ** whether or not it is a valid header.
  2275. */
  2276. isheader(s)
  2277. char *s;
  2278. {
  2279.     char *p;
  2280.  
  2281.     /*
  2282.     ** header field names must terminate with a colon
  2283.     ** and may not be null.
  2284.     */
  2285.     if(((p = index(s, ':')) == NULL) || (s == p)) {
  2286.         return(0);
  2287.  
  2288.     }
  2289.     /*
  2290.     ** header field names must consist entirely of
  2291.     ** printable ascii characters.
  2292.     */
  2293.     while(s != p) {
  2294.         if((*s < '!') || (*s > '~')) {
  2295.             return(0);
  2296.         }
  2297.         s++;
  2298.     }
  2299.     /*
  2300.     ** we hit the ':', so the field may be a header
  2301.     */
  2302.     return(1);
  2303. }
  2304.  
  2305. /*
  2306. ** compare the header field to those in the required header table.
  2307. ** if it matches, then mark the required header as being present
  2308. ** in the message.
  2309. */
  2310. haveheaders(s)
  2311. char *s;
  2312. {
  2313.     struct reqheaders *i;
  2314.  
  2315.     for(i = reqtab; i->name != NULL; i++) {
  2316.         if(strncmpic(i->name, s, strlen(i->name)) == 0) {
  2317.             if((strncmpic("From:", s, 5) == 0)
  2318.             && (from_addr != NULL)) {
  2319.                 (void) sprintf(s, "From: %s\n", from_addr);
  2320.             }
  2321.             i->have = 'Y';
  2322.             break;
  2323.         }
  2324.     }
  2325. }
  2326.  
  2327. /*
  2328. ** create default headers for the message.
  2329. */
  2330. def_headers(argc, argv, from)
  2331. int argc;
  2332. char **argv;
  2333. char *from;
  2334. {
  2335.     def_to(argc, argv);    /* default To:        */
  2336.     def_date();        /* default Date:    */
  2337.     def_from(from);        /* default From:     */
  2338.     def_mid();        /* default Message-Id:    */
  2339. }
  2340.  
  2341. /*
  2342. ** default Date: in arpa format
  2343. */
  2344. def_date()
  2345. {
  2346.     (void) strcpy(dateline, "Date: ");
  2347.     (void) strcat(dateline, arpanows);
  2348. }
  2349.  
  2350. /*
  2351. ** default Message-Id
  2352. **  Message-Id: <yymmddhhmm.AAppppp@hostdomain>
  2353. **
  2354. **    yy     year
  2355. **    mm     month
  2356. **    dd     day
  2357. **    hh     hour
  2358. **    mm     minute
  2359. **    ppppp    process-id
  2360. **
  2361. ** date and time are set by GMT
  2362. */
  2363. def_mid()
  2364. {
  2365.     (void) sprintf(midline, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s>",
  2366.         gmt->tm_year,
  2367.         gmt->tm_mon+1,
  2368.         gmt->tm_mday,
  2369.         gmt->tm_hour,
  2370.         gmt->tm_min,
  2371.         getpid(),
  2372.         hostdomain);
  2373. }
  2374.  
  2375. /*
  2376. ** default From:
  2377. **  From: user@hostdomain (Full Name)
  2378. */
  2379. def_from(from)
  2380. char *from;
  2381. {
  2382.  
  2383.     char *nameptr;
  2384.     char name[SMLBUF];
  2385.     char *getenv(), *login;
  2386.     char *pwfnam(), *pwuid();
  2387.  
  2388.     if (from_addr != NULL) {
  2389.         (void) sprintf(fromline, "From: %s", from_addr);
  2390.         return;
  2391.     }
  2392.  
  2393.     name[0] = '\0';
  2394.     if((nameptr = getenv("NAME")) != NULL) {
  2395.         (void) strcpy(name, nameptr);
  2396.     } else if((login = pwuid(getuid())) != NULL) {
  2397.         if((nameptr = pwfnam(login)) != NULL) {
  2398.             (void) strcpy(name, nameptr);
  2399.         }
  2400.     }
  2401.     if(name[0] != '\0') {
  2402.         (void) sprintf(fromline,
  2403.             "From: %s@%s (%s)", from, hostdomain, name);
  2404.     } else {
  2405.         (void) sprintf(fromline,
  2406.             "From: %s@%s", from, hostdomain);
  2407.     }
  2408. }
  2409.  
  2410. /*
  2411. ** default To:
  2412. **  To: recip1, recip2, ...
  2413. **
  2414. ** lines longer than 50 chars are continued on another line.
  2415. */
  2416. def_to(argc, argv)
  2417. int argc;
  2418. char **argv;
  2419. {
  2420.     int i, n;
  2421.     char *bol;
  2422.  
  2423.     bol = toline;
  2424.     (void) strcpy(bol, "To: ");
  2425.     for(n = i = 0; i < argc; i++) {
  2426.         (void) strcat(bol, argv[i]);
  2427.  
  2428.         if((index(argv[i], '!') == NULL)
  2429.         && (index(argv[i], '@') == NULL)) {
  2430.             (void) strcat(bol, "@");
  2431.             (void) strcat(bol, hostdomain);
  2432.         }
  2433.         if(i+1 < argc) {
  2434.             n = strlen(bol);
  2435.             if(n > 50) {
  2436.                 (void) strcat(bol, ",\n\t");
  2437.                 bol = bol + strlen(bol);
  2438.                 *bol = '\0';
  2439.                 n = 8;
  2440.             } else {
  2441.                 (void) strcat(bol, ", ");
  2442.             }
  2443.         }
  2444.     }
  2445. }
  2446. //E*O*F headers.c//
  2447.  
  2448. exit 0
  2449.