11439Seric # include <errno.h> 23309Seric # include "sendmail.h" 31392Seric 4*4321Seric static char SccsId[] = "@(#)collect.c 3.20 09/07/81"; 51392Seric 61392Seric /* 72969Seric ** COLLECT -- read & parse message header & make temp file. 81392Seric ** 91392Seric ** Creates a temporary file name and copies the standard 101392Seric ** input to that file. While it is doing it, it looks for 111392Seric ** "From:" and "Sender:" fields to use as the from-person 121392Seric ** (but only if the -a flag is specified). It prefers to 131392Seric ** to use the "Sender:" field. 141392Seric ** 151392Seric ** MIT seems to like to produce "Sent-By:" fields instead 161392Seric ** of "Sender:" fields. We used to catch this, but it turns 171392Seric ** out that the "Sent-By:" field doesn't always correspond 181392Seric ** to someone real ("___057", for instance), as required by 191392Seric ** the protocol. So we limp by..... 201392Seric ** 211392Seric ** Parameters: 221875Seric ** none 231392Seric ** 241392Seric ** Returns: 254162Seric ** none. 261392Seric ** 271392Seric ** Side Effects: 281392Seric ** Temp file is created and filled. 294162Seric ** The from person may be set. 301392Seric */ 311392Seric 321624Seric long MsgSize; /* size of message in bytes */ 334182Seric FILE *TempFile; /* the tempfile (after creation) */ 341397Seric 352969Seric collect() 361392Seric { 371392Seric register FILE *tf; 381392Seric char buf[MAXFIELD+1]; 391392Seric register char *p; 402900Seric char *xfrom; 412900Seric extern char *hvalue(); 424083Seric extern char *mktemp(); 431392Seric 441392Seric /* 451392Seric ** Create the temp file name and create the file. 461392Seric */ 471392Seric 484083Seric (void) mktemp(InFileName); 494083Seric (void) close(creat(InFileName, 0600)); 501392Seric if ((tf = fopen(InFileName, "w")) == NULL) 511392Seric { 521392Seric syserr("Cannot create %s", InFileName); 534162Seric return; 541392Seric } 551392Seric 564316Seric /* 574316Seric ** Try to read a UNIX-style From line 584316Seric */ 594316Seric 602900Seric if (fgets(buf, sizeof buf, stdin) == NULL) 614162Seric return; 62*4321Seric # ifndef NOTUNIX 632900Seric if (strncmp(buf, "From ", 5) == 0) 642900Seric { 652900Seric eatfrom(buf); 664083Seric (void) fgets(buf, sizeof buf, stdin); 672900Seric } 68*4321Seric # endif NOTUNIX 692900Seric 701392Seric /* 711392Seric ** Copy stdin to temp file & do message editting. 721392Seric ** To keep certain mailers from getting confused, 731392Seric ** and to keep the output clean, lines that look 741392Seric ** like UNIX "From" lines are deleted in the header, 751392Seric ** and prepended with ">" in the body. 761392Seric */ 771392Seric 782900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin)) 791392Seric { 804316Seric register char c; 814316Seric extern bool isheader(); 824316Seric 832900Seric /* see if the header is over */ 842900Seric if (!isheader(buf)) 852900Seric break; 862900Seric 872900Seric /* get the rest of this field */ 882900Seric while ((c = getc(stdin)) == ' ' || c == '\t') 891392Seric { 902900Seric p = &buf[strlen(buf)]; 912900Seric *p++ = c; 922900Seric if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 932900Seric break; 941392Seric } 954083Seric if (!feof(stdin)) 964083Seric (void) ungetc(c, stdin); 971392Seric 982900Seric MsgSize += strlen(buf); 991392Seric 1002900Seric /* 1012900Seric ** Snarf header away. 1022900Seric */ 1032900Seric 1043391Seric if (bitset(H_EOH, chompheader(buf, FALSE))) 1053058Seric break; 1062900Seric } 1071392Seric 1082900Seric # ifdef DEBUG 1092900Seric if (Debug) 1102900Seric printf("EOH\n"); 1112900Seric # endif DEBUG 1122900Seric 1132900Seric /* throw away a blank line */ 1142900Seric if (buf[0] == '\n') 1154083Seric (void) fgets(buf, sizeof buf, stdin); 1162900Seric 1172900Seric /* 1182900Seric ** Collect the body of the message. 1192900Seric */ 1202900Seric 1212900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 1222900Seric { 1234156Seric register int i; 1244156Seric 1252900Seric /* check for end-of-message */ 1262900Seric if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 1272900Seric break; 1282900Seric 129*4321Seric # ifndef NOTUNIX 1302900Seric /* Hide UNIX-like From lines */ 1312900Seric if (strncmp(buf, "From ", 5) == 0) 1321392Seric { 1332900Seric fputs(">", tf); 1342900Seric MsgSize++; 1351392Seric } 136*4321Seric # endif NOTUNIX 1374156Seric 1384156Seric /* 1394156Seric ** Figure message length, output the line to the temp 1404156Seric ** file, and insert a newline if missing. 1414156Seric */ 1424156Seric 1434156Seric i = strlen(buf); 1444156Seric MsgSize += i; 1451392Seric fputs(buf, tf); 1464156Seric if (buf[i - 1] != '\n') 1474156Seric fputs("\n", tf); 1481392Seric if (ferror(tf)) 1491392Seric { 1501439Seric if (errno == ENOSPC) 1511439Seric { 1524083Seric (void) freopen(InFileName, "w", tf); 1531439Seric fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 1541439Seric syserr("Out of disk space for temp file"); 1551439Seric } 1561439Seric else 1571439Seric syserr("Cannot write %s", InFileName); 1584083Seric (void) freopen("/dev/null", "w", tf); 1591392Seric } 1601392Seric } 1614083Seric (void) fclose(tf); 1622900Seric 1632900Seric /* 1642900Seric ** Find out some information from the headers. 1653386Seric ** Examples are who is the from person & the date. 1662900Seric */ 1672900Seric 1682900Seric /* from person */ 1692900Seric xfrom = hvalue("sender"); 1702900Seric if (xfrom == NULL) 1714210Seric xfrom = hvalue("original-from"); 1724162Seric if (ArpaMode != ARPA_NONE) 1734316Seric setfrom(xfrom, (char *) NULL); 1742900Seric 1753390Seric /* full name of from person */ 1763390Seric p = hvalue("full-name"); 1773390Seric if (p != NULL) 1783390Seric define('x', p); 1794210Seric else 1804210Seric { 1814210Seric register char *q; 1823390Seric 1834210Seric /* 1844210Seric ** Try to extract the full name from a general From: 1854210Seric ** field. We take anything which is a comment as a 1864210Seric ** first choice. Failing in that, we see if there is 1874210Seric ** a "machine readable" name (in <angle brackets>); if 1884210Seric ** so we take anything preceeding that clause. 1894210Seric ** 1904210Seric ** If we blow it here it's not all that serious. 1914210Seric */ 1924210Seric 1934210Seric p = hvalue("original-from"); 1944210Seric q = index(p, '('); 1954210Seric if (q != NULL) 1964210Seric { 1974210Seric int parenlev = 0; 1984210Seric 1994210Seric for (p = q; *p != '\0'; p++) 2004210Seric { 2014210Seric if (*p == '(') 2024210Seric parenlev++; 2034210Seric else if (*p == ')' && --parenlev <= 0) 2044210Seric break; 2054210Seric } 2064210Seric if (*p == ')') 2074210Seric { 2084210Seric *p = '\0'; 2094210Seric if (*++q != '\0') 2104210Seric define('x', newstr(q)); 2114210Seric *p = ')'; 2124210Seric } 2134210Seric } 2144210Seric else if ((q = index(p, '<')) != NULL) 2154210Seric { 2164210Seric char savec; 2174210Seric 2184210Seric while (*--q == ' ') 2194210Seric continue; 2204210Seric while (isspace(*p)) 2214210Seric p++; 2224210Seric savec = *++q; 2234210Seric *q = '\0'; 2244210Seric if (*p != '\0') 2254210Seric define('x', newstr(p)); 2264210Seric *q = savec; 2274210Seric } 2284210Seric } 2294210Seric 2302900Seric /* date message originated */ 2314149Seric p = hvalue("posted-date"); 2324149Seric if (p == NULL) 2334149Seric p = hvalue("date"); 2342900Seric if (p != NULL) 2352900Seric { 2363386Seric define('a', p); 2373386Seric /* we don't have a good way to do canonical conversion .... 2383386Seric define('d', newstr(arpatounix(p))); 2393386Seric .... so we will ignore the problem for the time being */ 2402900Seric } 2412900Seric 2424182Seric if ((TempFile = fopen(InFileName, "r")) == NULL) 2431392Seric syserr("Cannot reopen %s", InFileName); 2442900Seric 2452900Seric # ifdef DEBUG 2462900Seric if (Debug) 2472900Seric { 2484316Seric HDR *h; 2494316Seric extern char *capitalize(); 2504316Seric 2512900Seric printf("----- collected header -----\n"); 2522900Seric for (h = Header; h != NULL; h = h->h_link) 2532900Seric printf("%s: %s\n", capitalize(h->h_field), h->h_value); 2542900Seric printf("----------------------------\n"); 2552900Seric } 2562900Seric # endif DEBUG 2574162Seric return; 2581392Seric } 2591392Seric /* 2602900Seric ** EATFROM -- chew up a UNIX style from line and process 2612900Seric ** 2622900Seric ** This does indeed make some assumptions about the format 2632900Seric ** of UNIX messages. 2642900Seric ** 2652900Seric ** Parameters: 2662900Seric ** fm -- the from line. 2672900Seric ** 2682900Seric ** Returns: 2692900Seric ** none. 2702900Seric ** 2712900Seric ** Side Effects: 2722900Seric ** extracts what information it can from the header, 2733386Seric ** such as the date. 2742900Seric */ 2752900Seric 276*4321Seric # ifndef NOTUNIX 277*4321Seric 2784203Seric char *DowList[] = 2794203Seric { 2804203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 2814203Seric }; 2824203Seric 2832900Seric char *MonthList[] = 2842900Seric { 2852900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 2862900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 2872900Seric NULL 2882900Seric }; 2892900Seric 2902900Seric eatfrom(fm) 2912900Seric char *fm; 2922900Seric { 2932900Seric register char *p; 2942900Seric register char **dt; 2952900Seric 2964203Seric # ifdef DEBUG 2974203Seric if (Debug > 1) 2984203Seric printf("eatfrom(%s)\n", fm); 2994203Seric # endif DEBUG 3004203Seric 3012900Seric /* find the date part */ 3022900Seric p = fm; 3032900Seric while (*p != '\0') 3042900Seric { 3052900Seric /* skip a word */ 3062900Seric while (*p != '\0' && *p != ' ') 3072900Seric *p++; 3082900Seric while (*p == ' ') 3092900Seric *p++; 3102900Seric if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 3112900Seric continue; 3122900Seric 3132900Seric /* we have a possible date */ 3144203Seric for (dt = DowList; *dt != NULL; dt++) 3152900Seric if (strncmp(*dt, p, 3) == 0) 3162900Seric break; 3174203Seric if (*dt == NULL) 3184203Seric continue; 3192900Seric 3204203Seric for (dt = MonthList; *dt != NULL; dt++) 3214203Seric if (strncmp(*dt, &p[4], 3) == 0) 3224203Seric break; 3232900Seric if (*dt != NULL) 3242900Seric break; 3252900Seric } 3262900Seric 3272900Seric if (*p != NULL) 3282900Seric { 3293386Seric char *q; 3303386Seric 3312900Seric /* we have found a date */ 3323386Seric q = xalloc(25); 3333386Seric strncpy(q, p, 25); 3343386Seric q[24] = '\0'; 3353386Seric define('d', q); 3362900Seric } 3372900Seric } 338*4321Seric 339*4321Seric # endif NOTUNIX 340