11392Seric # include <stdio.h> 21392Seric # include <ctype.h> 31439Seric # include <errno.h> 43309Seric # include "sendmail.h" 51392Seric 6*3386Seric static char SccsId[] = "@(#)collect.c 3.8 03/28/81"; 71392Seric 81392Seric /* 92969Seric ** COLLECT -- read & parse message header & make temp file. 101392Seric ** 111392Seric ** Creates a temporary file name and copies the standard 121392Seric ** input to that file. While it is doing it, it looks for 131392Seric ** "From:" and "Sender:" fields to use as the from-person 141392Seric ** (but only if the -a flag is specified). It prefers to 151392Seric ** to use the "Sender:" field. 161392Seric ** 171392Seric ** MIT seems to like to produce "Sent-By:" fields instead 181392Seric ** of "Sender:" fields. We used to catch this, but it turns 191392Seric ** out that the "Sent-By:" field doesn't always correspond 201392Seric ** to someone real ("___057", for instance), as required by 211392Seric ** the protocol. So we limp by..... 221392Seric ** 231392Seric ** Parameters: 241875Seric ** none 251392Seric ** 261392Seric ** Returns: 271875Seric ** Name of temp file. 281392Seric ** 291392Seric ** Side Effects: 301392Seric ** Temp file is created and filled. 311392Seric ** 321392Seric ** Called By: 331392Seric ** main 341392Seric ** 351392Seric ** Notes: 361392Seric ** This is broken off from main largely so that the 371392Seric ** temp buffer can be deallocated. 381392Seric */ 391392Seric 401624Seric long MsgSize; /* size of message in bytes */ 411397Seric 421392Seric char * 432969Seric collect() 441392Seric { 451392Seric register FILE *tf; 461392Seric char buf[MAXFIELD+1]; 471392Seric register char *p; 481392Seric char c; 491439Seric extern int errno; 502900Seric extern bool isheader(); 512900Seric extern char *newstr(); 522900Seric extern char *xalloc(); 532900Seric extern char *index(), *rindex(); 542900Seric char *xfrom; 552900Seric extern char *hvalue(); 562988Seric extern char *strcpy(), *strcat(), *mktemp(); 57*3386Seric HDR *h; 581392Seric 591392Seric /* 601392Seric ** Create the temp file name and create the file. 611392Seric */ 621392Seric 631392Seric mktemp(InFileName); 641392Seric close(creat(InFileName, 0600)); 651392Seric if ((tf = fopen(InFileName, "w")) == NULL) 661392Seric { 671392Seric syserr("Cannot create %s", InFileName); 681392Seric return (NULL); 691392Seric } 701392Seric 712900Seric /* try to read a UNIX-style From line */ 722900Seric if (fgets(buf, sizeof buf, stdin) == NULL) 732900Seric return (NULL); 742900Seric if (strncmp(buf, "From ", 5) == 0) 752900Seric { 762900Seric eatfrom(buf); 772900Seric fgets(buf, sizeof buf, stdin); 782900Seric } 792900Seric 801392Seric /* 811392Seric ** Copy stdin to temp file & do message editting. 821392Seric ** To keep certain mailers from getting confused, 831392Seric ** and to keep the output clean, lines that look 841392Seric ** like UNIX "From" lines are deleted in the header, 851392Seric ** and prepended with ">" in the body. 861392Seric */ 871392Seric 882900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin)) 891392Seric { 902900Seric /* see if the header is over */ 912900Seric if (!isheader(buf)) 922900Seric break; 932900Seric 942900Seric /* get the rest of this field */ 952900Seric while ((c = getc(stdin)) == ' ' || c == '\t') 961392Seric { 972900Seric p = &buf[strlen(buf)]; 982900Seric *p++ = c; 992900Seric if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 1002900Seric break; 1011392Seric } 1022900Seric if (c != EOF) 1032900Seric ungetc(c, stdin); 1041392Seric 1052900Seric MsgSize += strlen(buf); 1061392Seric 1072900Seric /* 1082900Seric ** Snarf header away. 1092900Seric */ 1102900Seric 111*3386Seric if (bitset(H_EOH, chompheader(buf, 0))) 1123058Seric break; 1132900Seric } 1141392Seric 1152900Seric # ifdef DEBUG 1162900Seric if (Debug) 1172900Seric printf("EOH\n"); 1182900Seric # endif DEBUG 1192900Seric 1202900Seric /* throw away a blank line */ 1212900Seric if (buf[0] == '\n') 1222900Seric fgets(buf, sizeof buf, stdin); 1232900Seric 1242900Seric /* 1252900Seric ** Collect the body of the message. 1262900Seric */ 1272900Seric 1282900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 1292900Seric { 1302900Seric /* check for end-of-message */ 1312900Seric if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 1322900Seric break; 1332900Seric 1342900Seric /* Hide UNIX-like From lines */ 1352900Seric if (strncmp(buf, "From ", 5) == 0) 1361392Seric { 1372900Seric fputs(">", tf); 1382900Seric MsgSize++; 1391392Seric } 1401624Seric MsgSize += strlen(buf); 1411392Seric fputs(buf, tf); 1421392Seric if (ferror(tf)) 1431392Seric { 1441439Seric if (errno == ENOSPC) 1451439Seric { 1461439Seric freopen(InFileName, "w", tf); 1471439Seric fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 1481439Seric syserr("Out of disk space for temp file"); 1491439Seric } 1501439Seric else 1511439Seric syserr("Cannot write %s", InFileName); 1521439Seric freopen("/dev/null", "w", tf); 1531392Seric } 1541392Seric } 1551392Seric fclose(tf); 1562900Seric 1572900Seric /* 1582900Seric ** Find out some information from the headers. 159*3386Seric ** Examples are who is the from person & the date. 1602900Seric */ 1612900Seric 1622900Seric /* from person */ 1632900Seric xfrom = hvalue("sender"); 1642900Seric if (xfrom == NULL) 1652900Seric xfrom = hvalue("from"); 1662900Seric 1672900Seric /* date message originated */ 1682900Seric p = hvalue("date"); 1692900Seric if (p != NULL) 1702900Seric { 171*3386Seric define('a', p); 172*3386Seric /* we don't have a good way to do canonical conversion .... 173*3386Seric define('d', newstr(arpatounix(p))); 174*3386Seric .... so we will ignore the problem for the time being */ 1752900Seric } 1762900Seric 1771392Seric if (freopen(InFileName, "r", stdin) == NULL) 1781392Seric syserr("Cannot reopen %s", InFileName); 1792900Seric 1802900Seric # ifdef DEBUG 1812900Seric if (Debug) 1822900Seric { 1832900Seric printf("----- collected header -----\n"); 1842900Seric for (h = Header; h != NULL; h = h->h_link) 1852900Seric printf("%s: %s\n", capitalize(h->h_field), h->h_value); 1862900Seric printf("----------------------------\n"); 1872900Seric } 1882900Seric # endif DEBUG 1892900Seric return (ArpaFmt ? xfrom : NULL); 1901392Seric } 1911392Seric /* 1922900Seric ** EATFROM -- chew up a UNIX style from line and process 1932900Seric ** 1942900Seric ** This does indeed make some assumptions about the format 1952900Seric ** of UNIX messages. 1962900Seric ** 1972900Seric ** Parameters: 1982900Seric ** fm -- the from line. 1992900Seric ** 2002900Seric ** Returns: 2012900Seric ** none. 2022900Seric ** 2032900Seric ** Side Effects: 2042900Seric ** extracts what information it can from the header, 205*3386Seric ** such as the date. 2062900Seric */ 2072900Seric 2082900Seric char *MonthList[] = 2092900Seric { 2102900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 2112900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 2122900Seric NULL 2132900Seric }; 2142900Seric 2152900Seric eatfrom(fm) 2162900Seric char *fm; 2172900Seric { 2182900Seric register char *p; 2192900Seric register char **dt; 2202900Seric 2212900Seric /* find the date part */ 2222900Seric p = fm; 2232900Seric while (*p != '\0') 2242900Seric { 2252900Seric /* skip a word */ 2262900Seric while (*p != '\0' && *p != ' ') 2272900Seric *p++; 2282900Seric while (*p == ' ') 2292900Seric *p++; 2302900Seric if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 2312900Seric continue; 2322900Seric 2332900Seric /* we have a possible date */ 2342900Seric for (dt = MonthList; *dt != NULL; dt++) 2352900Seric if (strncmp(*dt, p, 3) == 0) 2362900Seric break; 2372900Seric 2382900Seric if (*dt != NULL) 2392900Seric break; 2402900Seric } 2412900Seric 2422900Seric if (*p != NULL) 2432900Seric { 244*3386Seric char *q; 245*3386Seric 2462900Seric /* we have found a date */ 247*3386Seric q = xalloc(25); 248*3386Seric strncpy(q, p, 25); 249*3386Seric q[24] = '\0'; 250*3386Seric define('d', q); 2512900Seric } 2522900Seric } 2532900Seric /* 2542900Seric ** HVALUE -- return value of a header. 2552900Seric ** 256*3386Seric ** Only "real" fields (i.e., ones that have not been supplied 257*3386Seric ** as a default) are used. 258*3386Seric ** 2592900Seric ** Parameters: 2602900Seric ** field -- the field name. 2612900Seric ** 2622900Seric ** Returns: 2632900Seric ** pointer to the value part. 2642900Seric ** NULL if not found. 2652900Seric ** 2662900Seric ** Side Effects: 2672900Seric ** sets the H_USED bit in the header if found. 2682900Seric */ 2692900Seric 2702900Seric char * 2712900Seric hvalue(field) 2722900Seric char *field; 2732900Seric { 2742900Seric register HDR *h; 2752900Seric 2762900Seric for (h = Header; h != NULL; h = h->h_link) 2772900Seric { 278*3386Seric if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 2792900Seric { 2802900Seric h->h_flags |= H_USED; 2812900Seric return (h->h_value); 2822900Seric } 2832900Seric } 2842900Seric return (NULL); 2852900Seric } 2862900Seric /* 2872900Seric ** ISHEADER -- predicate telling if argument is a header. 2882900Seric ** 2892900Seric ** Parameters: 2902900Seric ** s -- string to check for possible headerness. 2912900Seric ** 2922900Seric ** Returns: 2932900Seric ** TRUE if s is a header. 2942900Seric ** FALSE otherwise. 2952900Seric ** 2962900Seric ** Side Effects: 2972900Seric ** none. 2982900Seric */ 2992900Seric 3002900Seric bool 3012900Seric isheader(s) 3022900Seric register char *s; 3032900Seric { 3042900Seric if (!isalnum(*s)) 3052900Seric return (FALSE); 3062900Seric while (!isspace(*s) && *s != ':') 3072900Seric s++; 3082900Seric while (isspace(*s)) 3092900Seric s++; 3102900Seric return (*s == ':'); 3112900Seric } 312*3386Seric /* 313*3386Seric ** CHOMPHEADER -- process and save a header line. 314*3386Seric ** 315*3386Seric ** Called by collect and by readcf to deal with header lines. 316*3386Seric ** 317*3386Seric ** Parameters: 318*3386Seric ** line -- header as a text line. 319*3386Seric ** stat -- bits to set in the h_flags field. 320*3386Seric ** 321*3386Seric ** Returns: 322*3386Seric ** flags for this header. 323*3386Seric ** 324*3386Seric ** Side Effects: 325*3386Seric ** The header is saved on the header list. 326*3386Seric */ 327*3386Seric 328*3386Seric chompheader(line, stat) 329*3386Seric char *line; 330*3386Seric int stat; 331*3386Seric { 332*3386Seric register char *p; 333*3386Seric extern int errno; 334*3386Seric register HDR *h; 335*3386Seric HDR **hp; 336*3386Seric extern bool isheader(); 337*3386Seric extern char *newstr(); 338*3386Seric extern char *xalloc(); 339*3386Seric char *fname; 340*3386Seric char *fvalue; 341*3386Seric extern char *index(), *rindex(); 342*3386Seric struct hdrinfo *hi; 343*3386Seric extern char *strcpy(), *strcat(), *mktemp(); 344*3386Seric 345*3386Seric /* strip off trailing newline */ 346*3386Seric p = rindex(line, '\n'); 347*3386Seric if (p != NULL) 348*3386Seric *p = '\0'; 349*3386Seric 350*3386Seric /* find canonical name */ 351*3386Seric fname = line; 352*3386Seric p = index(line, ':'); 353*3386Seric fvalue = &p[1]; 354*3386Seric while (isspace(*--p)) 355*3386Seric continue; 356*3386Seric *++p = '\0'; 357*3386Seric makelower(fname); 358*3386Seric 359*3386Seric /* strip field value on front */ 360*3386Seric if (*fvalue == ' ') 361*3386Seric fvalue++; 362*3386Seric 363*3386Seric /* search header list for this header */ 364*3386Seric for (hp = &Header, h = Header; h != NULL; hp = &h->h_link, h = h->h_link) 365*3386Seric { 366*3386Seric if (strcmp(fname, h->h_field) == 0 && bitset(H_DEFAULT, h->h_flags)) 367*3386Seric break; 368*3386Seric } 369*3386Seric 370*3386Seric /* see if it is a known type */ 371*3386Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 372*3386Seric { 373*3386Seric if (strcmp(hi->hi_field, fname) == 0) 374*3386Seric break; 375*3386Seric } 376*3386Seric 377*3386Seric /* if this means "end of header" quit now */ 378*3386Seric if (bitset(H_EOH, hi->hi_flags)) 379*3386Seric return (hi->hi_flags); 380*3386Seric 381*3386Seric /* create/fill in a new node */ 382*3386Seric if (h == NULL) 383*3386Seric { 384*3386Seric /* create a new node */ 385*3386Seric *hp = h = (HDR *) xalloc(sizeof *h); 386*3386Seric h->h_field = newstr(fname); 387*3386Seric h->h_value = NULL; 388*3386Seric h->h_link = NULL; 389*3386Seric h->h_flags = hi->hi_flags | stat; 390*3386Seric h->h_mflags = hi->hi_mflags; 391*3386Seric } 392*3386Seric else 393*3386Seric h->h_flags &= ~H_DEFAULT; 394*3386Seric if (h->h_value != NULL) 395*3386Seric free(h->h_value); 396*3386Seric h->h_value = newstr(fvalue); 397*3386Seric 398*3386Seric return (h->h_flags); 399*3386Seric } 400