home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / SMAILSRC.ZIP / SMAIL.ZIP / HEADERS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-05  |  17.9 KB  |  820 lines

  1. /*
  2. **  message spooing, header and address parsing and completion
  3. **  functions for smail/rmail
  4. */
  5.  
  6. /*
  7. **    Modified by Chip Salzenberg (chip@ateng.UUCP), originally for SCO XENIX.
  8. **    Released to Usenet on 01 Dec 1987.
  9. **    Further modified 23 Dec 1987.
  10. **    Modifications added to MS-DOS version by Stephen Trier, 3/27/90
  11. **
  12. **    Additions:
  13. **
  14. **            Understand "a%b" to mean "a@b".  (This is a judgement call.
  15. **            I prefer to accept any mail that I can understand, not just
  16. **            that which is "correct.")
  17. */
  18.  
  19. /*
  20. **    Patched for MS-DOS compatibility by Stephen Trier March, April and
  21. **    May, 1990.  This file is in the public domain.
  22. **
  23. **    I added the a%b patch by Chip Salzenburg not knowing that one of my
  24. **    test feeds was going to start giving me mail in that misformed notation.
  25. **    This is the only one of Chip's patches that I used.
  26. */
  27.  
  28. #ifndef lint
  29. static char     *sccsid="@(#)headers.c    2.5 (smail) 9/15/87";
  30. #endif
  31.  
  32. # include    <stdio.h>
  33. # include    <sys/types.h>
  34. # include    <time.h>
  35. # include    <ctype.h>
  36. # include    <pwd.h>
  37. # include       "defs.h"
  38. #ifdef MSDOS
  39. # include       <process.h>
  40. #endif
  41.  
  42. extern enum edebug debug;    /* how verbose we are         */ 
  43. extern char hostname[];        /* */
  44. extern char hostdomain[];    /* */
  45. extern char *spoolfile;        /* file name of spooled message */
  46. extern FILE *spoolfp;        /* file ptr  to spooled message */
  47. extern int spoolmaster;        /* set if creator of spoolfile  */
  48. extern time_t now;        /* time                */
  49. extern char nows[], arpanows[];    /* time strings            */
  50. extern struct tm *gmt, *loc;    /* time structs            */
  51. extern char *from_addr;        /* replacement fromaddr with -F */
  52.  
  53. static char toline[SMLBUF];
  54. static char fromline[SMLBUF];
  55. static char dateline[SMLBUF];
  56. static char midline[SMLBUF];
  57. static char *ieof = "NOTNULL";
  58.  
  59. struct reqheaders {
  60.     char *name;
  61.     char *field;
  62.     char have;
  63. };
  64.  
  65. static struct reqheaders reqtab[] = {
  66.     "Message-Id:"    ,    midline        ,    'N'    ,
  67.     "Date:"        ,    dateline    ,    'N'    ,
  68.     "From:"        ,    fromline    ,    'N'    ,
  69.     "To:"        ,    toline        ,    'N'    ,
  70.     NULL         ,    NULL        ,    'N'
  71. };
  72.  
  73.  
  74. /*
  75. **
  76. ** parse(): parse <address> into <domain, user, form>.
  77. **
  78. **     input        form
  79. **    -----        ----
  80. **    user        LOCAL
  81. **    domain!user    DOMAIN
  82. **    user@domain    DOMAIN
  83. **    @domain,address    LOCAL    (just for sendmail)
  84. **    host!address    UUCP
  85. **
  86. */
  87.  
  88. enum eform
  89. parse(address, domain, user)
  90. char *address;        /* input address     */
  91. char *domain;        /* output domain     */
  92. char *user;        /* output user         */
  93. {
  94.     int parts;
  95.     char *partv[MAXPATH];                /* to crack address */
  96.  
  97. /*
  98. **  If this is route address form @domain_a,@domain_b:user@domain_c, ...
  99. */
  100.     if(*address == '@')
  101. #ifdef SENDMAIL
  102. /*
  103. **  hand it to sendmail
  104. */
  105.     {
  106.         goto local;
  107.     }
  108. #else
  109. /*
  110. **  no sendmail, convert it into a bang path: domain_a!domain_b!domain_c!user
  111. */
  112.     {
  113.         char buf[SMLBUF], *p;
  114.         char t_dom[SMLBUF], t_user[SMLBUF];
  115.  
  116.         (void) strcpy(buf, address+1);        /* elide leading '@' */
  117.  
  118.         for(p=buf; *p != '\0' ; p++) {    /* search for ',' or ':' */
  119.             if(*p == ':') {        /* reached end of route */
  120.                 break;
  121.             }
  122.             if(*p == ',') {        /* elide ','s */
  123.                 (void) strcpy(p, p+1);
  124.             }
  125.             if(*p == '@') {        /* convert '@' to '!' */
  126.                 *p = '!';
  127.             }
  128.         }
  129.  
  130.         if(*p != ':') {    /* bad syntax - punt */
  131.             goto local;
  132.         }
  133.         *p = '\0';
  134.  
  135.         if(parse(p+1, t_dom, t_user) != LOCAL) {
  136.             (void) strcat(buf, "!");
  137.             (void) strcat(buf, t_dom);
  138.         }
  139.         (void) strcat(buf, "!");
  140.         (void) strcat(buf, t_user);
  141.  
  142.         /* munge the address (yuk)
  143.         ** it's OK to copy into 'address', because the machinations
  144.         ** above don't increase the string length of the address.
  145.         */
  146.  
  147.         (void) strcpy(address, buf);
  148.  
  149.         /* re-parse the address */
  150.         return(parse(address, domain, user));
  151.     }
  152. #endif
  153. /*
  154. **  Try splitting at @.  If it works, this is user@domain, form DOMAIN.
  155. **  Prefer the righthand @ in a@b@c.
  156. */
  157.     if ((parts = ssplit(address, '@', partv)) >= 2) {
  158.         (void) strcpy(domain, partv[parts-1]);
  159.         (void) strncpy(user, partv[0], partv[parts-1]-partv[0]-1);
  160.         user[partv[parts-1]-partv[0]-1] = '\0';
  161.         return (DOMAIN);
  162.     } 
  163. /*
  164. **  Try splitting at !. If it works, see if the piece before the ! has
  165. **  a . in it (domain!user, form DOMAIN) or not (host!user, form UUCP).
  166. */
  167.     if (ssplit(address, '!', partv) > 1) {
  168.         (void) strcpy(user, partv[1]);
  169.         (void) strncpy(domain, partv[0], partv[1]-partv[0]-1);
  170.         domain[partv[1]-partv[0]-1] = '\0';
  171.  
  172.         if((parts = ssplit(domain, '.', partv)) < 2) {
  173.             return(UUCP);
  174.         }
  175.  
  176.         if(partv[parts-1][0] == '\0') {
  177.             partv[parts-1][-1] = '\0'; /* strip trailing . */
  178.         }
  179.         return (DOMAIN);
  180.     }
  181. /*
  182. **  Try splitting at %.  If it works, this is user%domain, which we choose
  183. **  to understand as user@domain.  Prefer the righthand % in a%b%c.
  184. **  (This code allows 'user%foo@mydom' to mean '@mydom,user@foo'.)
  185. **     [Chip Salzenburg]
  186. */
  187.        if ((parts = ssplit(address, '%', partv)) >= 2) {
  188.            (void) strcpy(domain, partv[parts-1]);
  189.            (void) strncpy(user, partv[0], partv[parts-1]-partv[0]-1);
  190.            user[partv[parts-1]-partv[0]-1] = '\0';
  191.            return (DOMAIN);
  192.        }
  193. /*
  194. **  Done trying.  This must be just a user name, form LOCAL.
  195. */
  196. local:
  197.     (void) strcpy(user, address);
  198.     (void) strcpy(domain, "");
  199.     return(LOCAL);                /* user */
  200. }
  201.  
  202. build(domain, user, form, result)
  203. char *domain;
  204. char *user;
  205. enum eform form;
  206. char *result;
  207. {
  208.     switch((int) form) {
  209.     case LOCAL:
  210.         (void) sprintf(result, "%s", user); 
  211.         break;
  212.     case UUCP:
  213.         (void) sprintf(result, "%s!%s", domain, user);
  214.         break;
  215.     case DOMAIN:
  216.         (void) sprintf(result, "%s@%s", user, domain);
  217.         break;
  218.     }
  219. }
  220.  
  221. /*
  222. **  ssplit(): split a line into array pointers.
  223. **
  224. **  Each pointer wordv[i] points to the first character after the i'th 
  225. **  occurence of c in buf.  Note that each wordv[i] includes wordv[i+1].
  226. **
  227. */
  228.  
  229. ssplit(buf, c, ptr)
  230. register char *buf;        /* line to split up         */
  231. char c;                /* character to split on    */
  232. char **ptr;            /* the resultant vector        */
  233. {
  234.         int count = 0;
  235.         int wasword = 0;
  236.  
  237.         for(; *buf; buf++) {
  238.         if (!wasword) {
  239.             count++;
  240.             *ptr++ = buf;
  241.         }
  242.         wasword = (c != *buf);
  243.         }
  244.     if (!wasword) {
  245.         count++;
  246.         *ptr++ = buf;
  247.     }
  248.         *ptr = NULL;
  249.         return(count);
  250. }
  251.  
  252. /*
  253. ** Determine whether an address is a local address
  254. */
  255.  
  256. islocal(addr, domain, user)
  257. char *addr, *domain, *user;
  258. {
  259.         enum eform form, parse();
  260.         extern char hostuucp[];
  261.  
  262.         /*
  263.         ** parse the address
  264.         */
  265.  
  266.         form = parse(addr, domain, user);
  267.  
  268.         if((form == LOCAL)            /* user */
  269.         ||(strcmpic(domain, hostdomain) == 0)    /* user@hostdomain */
  270.         ||(strcmpic(domain, hostname)   == 0)    /* user@hostname */
  271. #ifdef DOMGATE
  272.         ||(strcmpic(domain, &MYDOM[0]) == 0)    /* user@MYDOM w/ dot */
  273.         ||(strcmpic(domain, &MYDOM[1]) == 0)    /* user@MYDOM no dot */
  274. #endif
  275.         ||(strcmpic(domain, hostuucp)   == 0)) {/* user@hostuucp */
  276.             return(1);
  277.         }
  278.         return(0);
  279. }
  280.  
  281. /*
  282. ** spool - message spooling module
  283. **
  284. ** (1) get dates for headers, etc.
  285. ** (2) if the message is on the standard input (no '-f')
  286. **     (a) create a temp file for spooling the message.
  287. **     (b) collapse the From_ headers into a path.
  288. **     (c) if the mail originated locally, then
  289. **         (i) establish default headers
  290. **        (ii) scan the message headers for required header fields
  291. **       (iii) add any required message headers that are absent
  292. **     (d) copy rest of the message to the spool file
  293. **     (e) close the spool file
  294. ** (3) open the spool file for reading
  295. */
  296.  
  297. void
  298. spool(argc, argv)
  299. int argc;
  300. char **argv;
  301. {
  302. #ifndef MSDOS
  303.     static char *tmpf = "/tmp/rmXXXXXX";    /* temp file name */
  304. #else /* MSDOS */
  305.     static char tmpf[80] = "";
  306. #endif /* !MSDOS */
  307.     char *mktemp();
  308.     char buf[SMLBUF];
  309.     static char splbuf[SMLBUF];
  310.     char from[SMLBUF], domain[SMLBUF], user[SMLBUF];
  311.     void rline(), scanheaders(), compheaders();
  312.  
  313. #ifdef MSDOS
  314.     /*
  315.      *  If we haven't figured out a name for the
  316.      *  temporary file yet, do so now.
  317.      */
  318.     if (*tmpf == '\0')
  319.         sprintf(tmpf, "%s/rmXXXXXX", ms_tmpdir);
  320. #endif /* MSDOS */
  321.  
  322.     /*
  323.     ** if the mail has already been spooled by
  324.     ** a previous invocation of smail don't respool.
  325.     ** check the file name to prevent things like
  326.     ** rmail -f /etc/passwd badguy@dreadfuldomain
  327.     */
  328.  
  329.     if((spoolfile != NULL)
  330.     && (strncmp(spoolfile, tmpf, strlen(tmpf) - 6) != 0)) {
  331.         error(EX_TEMPFAIL, "spool: bad file name '%s'\n", spoolfile);
  332.     }
  333.  
  334.     /*
  335.     ** set dates in local, arpa, and gmt forms
  336.     */
  337.     setdates();
  338.  
  339.     /*
  340.     ** If necessary, copy stdin to a temp file.
  341.     */
  342.  
  343.     if(spoolfile == NULL) {
  344.         spoolfile = strcpy(splbuf, tmpf);
  345.         (void) mktemp(spoolfile);
  346.  
  347.         if((spoolfp = fopen(spoolfile, "w")) == NULL) {
  348.             error(EX_CANTCREAT, "can't create %s.\n", spoolfile);
  349.         }
  350.  
  351.         spoolmaster = 1;
  352.  
  353.         /*
  354.         ** rline reads the standard input,
  355.         ** collapsing the From_ and >From_
  356.         ** lines into a single uucp path.
  357.         ** first non-from_ line is in buf[];
  358.         */
  359.  
  360.         rline(from, buf);
  361.  
  362.         /*
  363.         ** if the mail originated here, we parse the header
  364.         ** and add any required headers that are missing.
  365.         */
  366.  
  367.         if(islocal(from, domain, user) || (from_addr != NULL)) {
  368.             /*
  369.             ** initialize default headers
  370.             */
  371.             def_headers(argc, argv, from);
  372.  
  373.             /*
  374.             ** buf has first, non-from_  line
  375.             */
  376.             scanheaders(buf);
  377.             /*
  378.             ** buf has first, non-header line,
  379.             */
  380.  
  381.             compheaders();
  382.  
  383.             if(buf[0] != '\n') {
  384.                 (void) fputs("\n", spoolfp);
  385.             }
  386.         }
  387.  
  388.         /*
  389.         ** now, copy the rest of the letter into the spool file
  390.         ** terminate on either EOF or '^.$'
  391.         */
  392.  
  393.         while(ieof != NULL) {
  394.             (void) fputs(buf, spoolfp);
  395.             if((fgets(buf, SMLBUF, stdin) == NULL)
  396.             || (buf[0] == '.' && buf[1] == '\n')) {
  397.                 ieof = NULL;
  398.             }
  399.         }
  400.  
  401.         /*
  402.         ** close the spool file, and the standard input.
  403.         */
  404.  
  405.         (void) fclose(spoolfp);
  406.         (void) fclose(stdin);    /* you don't see this too often! */
  407.     }
  408.  
  409.     if((spoolfp = fopen(spoolfile, "r")) == NULL) {
  410.         error(EX_TEMPFAIL, "can't open %s.\n", spoolfile);
  411.     }
  412. }
  413.  
  414. /*
  415. **
  416. **  rline(): collapse From_ and >From_ lines.
  417. **
  418. **  Same idea as the old rmail, but also turns user@domain to domain!user. 
  419. **
  420. */
  421.  
  422. void
  423. rline(from, retbuf)
  424. char *from;
  425. char *retbuf;
  426. {
  427.     int parts;            /* for cracking From_ lines ... */
  428.     char *partv[16];        /* ... apart using ssplit()     */
  429.     char user[SMLBUF];        /* for rewriting user@host    */
  430.     char domain[SMLBUF];        /* "   "         "              */
  431.     char addr[SMLBUF];        /* "   "         "              */
  432.     enum eform form, parse();    /* "   "         "              */
  433.     extern build();            /* "   "         "              */
  434.     char *c;
  435.     int nhops, i;
  436.     char buf[SMLBUF], tmp[SMLBUF], *hop[128], *e, *b;
  437.     char *pwuid();
  438.  
  439.     if(spoolmaster == 0) return;
  440.  
  441.     buf[0] = from[0] = addr[0] = '\0';
  442. /*
  443. **  Read each line until we hit EOF or a line not beginning with "From "
  444. **  or ">From " (called From_ lines), accumulating the new path in from
  445. **  and stuffing the actual sending user (the user name on the last From_ 
  446. **  line) in addr.
  447. */
  448.     for(;;) {
  449.         (void) strcpy(retbuf, buf);
  450.         if(ieof == NULL) {
  451.             break;
  452.         }
  453.         if((fgets(buf, sizeof(buf), stdin) == NULL)
  454.         || (buf[0] == '.' && buf[1] == '\n')) {
  455.             ieof = NULL;
  456.             break;
  457.         }
  458.         if (strncmp("From ", buf, 5) 
  459.             && strncmp(">From ", buf, 6)) {
  460.             break;
  461.         }
  462. /*
  463. **  Crack the line apart using ssplit.
  464. */
  465.         if(c = index(buf, '\n')) {
  466.             *c = '\0';
  467.         }
  468.         parts = ssplit(buf, ' ', partv);
  469. /*
  470. **  Tack host! onto the from argument if "remote from host" is present.
  471. */
  472.  
  473.         if((parts > 3)
  474.         && (strncmp("remote from ", partv[parts-3], 12) == 0)) {
  475.             (void) strcat(from, partv[parts-1]);
  476.             (void) strcat(from, "!");
  477.         }
  478. /*
  479. **  Stuff user name into addr, overwriting the user name from previous 
  480. **  From_ lines, since only the last one counts.  Then rewrite user@host 
  481. **  into host!user, since @'s don't belong in the From_ argument.
  482. */
  483.         if(parts < 2) {
  484.             break;
  485.         } else {
  486.             char *x = partv[1];
  487.             char *q = index(x, ' ');
  488.             if(q != NULL) {
  489.                 *q = '\0';
  490.             }
  491.             (void) strcpy(addr, x);
  492.         }
  493.  
  494.         (void) parse(addr, domain, user);
  495.         if(*domain == '\0') {
  496.             form = LOCAL;
  497.         } else {
  498.             form = UUCP;
  499.         }
  500.  
  501.         build(domain, user, form, addr);
  502.     }
  503. /*
  504. **  Now tack the user name onto the from argument.
  505. */
  506.     (void) strcat(from, addr);
  507. /*
  508. **  If we still have no from argument, we have junk headers, but we try
  509. **  to get the user's name using /etc/passwd.
  510. */
  511.  
  512.     if (from[0] == '\0') {
  513.         char *login;
  514.         if ((login = pwuid(getuid())) == NULL) {
  515.             (void) strcpy(from, "nobody");    /* bad news */
  516.         } else {
  517.             (void) strcpy(from, login);
  518.         }
  519.     }
  520.  
  521.     /* split the from line on '!'s */
  522.     nhops = ssplit(from, '!', hop);
  523.  
  524.     for(i = 0; i < (nhops - 1); i++) {
  525.         b = hop[i];
  526.         if(*b == '\0') {
  527.             continue;
  528.         }
  529.         e = hop[i+1];
  530.         e-- ;
  531.         *e = '\0';    /* null terminate each path segment */
  532.         e++;
  533.  
  534. #ifdef HIDDENHOSTS
  535. /*
  536. **  Strip hidden hosts:  anything.hostname.MYDOM -> hostname.MYDOM
  537. */
  538.         for(p = b;(p = index(p, '.')) != NULL; p++) {
  539.             if(strcmpic(hostdomain, p+1) == 0) {
  540.                 (void) strcpy(b, hostdomain);
  541.                 break;
  542.             }
  543.         }
  544. #endif
  545.  
  546. /*
  547. **  Strip useless MYDOM: hostname.MYDOM -> hostname
  548. */
  549.         if(strcmpic(hop[i], hostdomain) == 0) {
  550.             (void) strcpy(hop[i], hostname);
  551.         }
  552.     }
  553.  
  554. /*
  555. **  Now strip out any redundant information in the From_ line
  556. **  a!b!c!c!d    => a!b!c!d
  557. */
  558.  
  559.     for(i = 0; i < (nhops - 2); i++) {
  560.         b = hop[i];
  561.         e = hop[i+1];
  562.         if(strcmpic(b, e) == 0) {
  563.             *b = '\0';
  564.         }
  565.     }
  566. /*
  567. **  Reconstruct the From_ line
  568. */
  569.     tmp[0] = '\0';            /* empty the tmp buffer */
  570.  
  571.     for(i = 0; i < (nhops - 1); i++) {
  572.         if((hop[i][0] == '\0')    /* deleted this hop */
  573.          ||((tmp[0] == '\0')    /* first hop == hostname */
  574.           &&(strcmpic(hop[i], hostname) == 0))) {
  575.             continue;
  576.         }
  577.         (void) strcat(tmp, hop[i]);
  578.         (void) strcat(tmp, "!");
  579.     }
  580.     (void) strcat(tmp, hop[i]);
  581.     (void) strcpy(from, tmp);
  582.     (void) strcpy(retbuf, buf);
  583.     (void) fprintf(spoolfp, "%s\n", from);
  584. }
  585.  
  586. void
  587. scanheaders(buf)
  588. char *buf;
  589. {
  590.     int inheader = 0;
  591.  
  592.     while(ieof != NULL) {
  593.         if(buf[0] == '\n') {
  594.             break; /* end of headers */
  595.         }
  596.  
  597.         /*
  598.         ** header lines which begin with whitespace
  599.         ** are continuation lines
  600.         */
  601.         if((inheader == 0)
  602.         || ((buf[0] != ' ' && buf[0] != '\t'))) {
  603.             /* not a continuation line
  604.             ** check for header
  605.             */
  606.             if(isheader(buf) == 0) {
  607.                 /*
  608.                 ** not a header
  609.                 */
  610.                 break;
  611.             }
  612.             inheader = 1;
  613.             haveheaders(buf);
  614.         }
  615.         (void) fputs(buf, spoolfp);
  616.         if((fgets(buf, SMLBUF, stdin) == NULL)
  617.         || (buf[0] == '.' && buf[1] == '\n')) {
  618.             ieof = NULL;
  619.         }
  620.     }
  621.  
  622.     if(isheader(buf)) {
  623.         buf[0] = '\0';
  624.     }
  625. }
  626.  
  627. /*
  628. ** complete headers - add any required headers that are not in the message
  629. */
  630. void
  631. compheaders()
  632. {
  633.     struct reqheaders *i;
  634.  
  635.     /*
  636.     ** look at the table of required headers and
  637.     ** add those that are missing to the spooled message.
  638.     */
  639.     for(i = reqtab; i->name != NULL; i++) {
  640.         if(i->have != 'Y') {
  641.             (void) fprintf(spoolfp, "%s\n", i->field);
  642.         }
  643.     }
  644. }
  645.  
  646. /*
  647. ** look at a string and determine
  648. ** whether or not it is a valid header.
  649. */
  650. isheader(s)
  651. char *s;
  652. {
  653.     char *p;
  654.  
  655.     /*
  656.     ** header field names must terminate with a colon
  657.     ** and may not be null.
  658.     */
  659.     if(((p = index(s, ':')) == NULL) || (s == p)) {
  660.         return(0);
  661.  
  662.     }
  663.     /*
  664.     ** header field names must consist entirely of
  665.     ** printable ascii characters.
  666.     */
  667.     while(s != p) {
  668.         if((*s < '!') || (*s > '~')) {
  669.             return(0);
  670.         }
  671.         s++;
  672.     }
  673.     /*
  674.     ** we hit the ':', so the field may be a header
  675.     */
  676.     return(1);
  677. }
  678.  
  679. /*
  680. ** compare the header field to those in the required header table.
  681. ** if it matches, then mark the required header as being present
  682. ** in the message.
  683. */
  684. haveheaders(s)
  685. char *s;
  686. {
  687.     struct reqheaders *i;
  688.  
  689.     for(i = reqtab; i->name != NULL; i++) {
  690.         if(strncmpic(i->name, s, strlen(i->name)) == 0) {
  691.             if((strncmpic("From:", s, 5) == 0)
  692.             && (from_addr != NULL)) {
  693.                 (void) sprintf(s, "From: %s\n", from_addr);
  694.             }
  695.             i->have = 'Y';
  696.             break;
  697.         }
  698.     }
  699. }
  700.  
  701. /*
  702. ** create default headers for the message.
  703. */
  704. def_headers(argc, argv, from)
  705. int argc;
  706. char **argv;
  707. char *from;
  708. {
  709.     def_to(argc, argv);    /* default To:        */
  710.     def_date();        /* default Date:    */
  711.     def_from(from);        /* default From:     */
  712.     def_mid();        /* default Message-Id:    */
  713. }
  714.  
  715. /*
  716. ** default Date: in arpa format
  717. */
  718. def_date()
  719. {
  720.     (void) strcpy(dateline, "Date: ");
  721.     (void) strcat(dateline, arpanows);
  722. }
  723.  
  724. /*
  725. ** default Message-Id
  726. **  Message-Id: <yymmddhhmm.AAppppp@hostdomain>
  727. **
  728. **    yy     year
  729. **    mm     month
  730. **    dd     day
  731. **    hh     hour
  732. **    mm     minute
  733. **    ppppp    process-id
  734. **
  735. ** date and time are set by GMT
  736. */
  737. def_mid()
  738. {
  739.     (void) sprintf(midline, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s>",
  740.         gmt->tm_year,
  741.         gmt->tm_mon+1,
  742.         gmt->tm_mday,
  743.         gmt->tm_hour,
  744.         gmt->tm_min,
  745.         getpid(),
  746.         hostdomain);
  747. }
  748.  
  749. /*
  750. ** default From:
  751. **  From: user@hostdomain (Full Name)
  752. */
  753. def_from(from)
  754. char *from;
  755. {
  756.  
  757.     char *nameptr;
  758.     char name[SMLBUF];
  759.     char *getenv(), *login;
  760.     char *pwfnam(), *pwuid();
  761.  
  762.     if (from_addr != NULL) {
  763.         (void) sprintf(fromline, "From: %s", from_addr);
  764.         return;
  765.     }
  766.  
  767.     name[0] = '\0';
  768.     if((nameptr = getenv("NAME")) != NULL) {
  769.         (void) strcpy(name, nameptr);
  770.     } else if((login = pwuid(getuid())) != NULL) {
  771.         if((nameptr = pwfnam(login)) != NULL) {
  772.             (void) strcpy(name, nameptr);
  773.         }
  774.     }
  775.     if(name[0] != '\0') {
  776.         (void) sprintf(fromline,
  777.             "From: %s@%s (%s)", from, hostdomain, name);
  778.     } else {
  779.         (void) sprintf(fromline,
  780.             "From: %s@%s", from, hostdomain);
  781.     }
  782. }
  783.  
  784. /*
  785. ** default To:
  786. **  To: recip1, recip2, ...
  787. **
  788. ** lines longer than 50 chars are continued on another line.
  789. */
  790. def_to(argc, argv)
  791. int argc;
  792. char **argv;
  793. {
  794.     int i, n;
  795.     char *bol;
  796.  
  797.     bol = toline;
  798.     (void) strcpy(bol, "To: ");
  799.     for(n = i = 0; i < argc; i++) {
  800.         (void) strcat(bol, argv[i]);
  801.  
  802.         if((index(argv[i], '!') == NULL)
  803.         && (index(argv[i], '@') == NULL)) {
  804.             (void) strcat(bol, "@");
  805.             (void) strcat(bol, hostdomain);
  806.         }
  807.         if(i+1 < argc) {
  808.             n = strlen(bol);
  809.             if(n > 50) {
  810.                 (void) strcat(bol, ",\n\t");
  811.                 bol = bol + strlen(bol);
  812.                 *bol = '\0';
  813.                 n = 8;
  814.             } else {
  815.                 (void) strcat(bol, ", ");
  816.             }
  817.         }
  818.     }
  819. }
  820.