11439Seric # include <errno.h> 23309Seric # include "sendmail.h" 31392Seric 4*4551Seric static char SccsId[] = "@(#)collect.c 3.24 10/19/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 /* 574322Seric ** Tell ARPANET to go ahead. 584322Seric */ 594322Seric 604322Seric if (ArpaMode == ARPA_MAIL) 614322Seric { 624322Seric extern char Arpa_Enter[]; 634322Seric 644322Seric message(Arpa_Enter, "Enter mail, end with \".\" on a line by itself"); 654322Seric } 664322Seric 674322Seric /* 684316Seric ** Try to read a UNIX-style From line 694316Seric */ 704316Seric 712900Seric if (fgets(buf, sizeof buf, stdin) == NULL) 724162Seric return; 734321Seric # ifndef NOTUNIX 744322Seric if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 752900Seric { 762900Seric eatfrom(buf); 774083Seric (void) fgets(buf, sizeof buf, stdin); 782900Seric } 794321Seric # endif NOTUNIX 802900Seric 811392Seric /* 821392Seric ** Copy stdin to temp file & do message editting. 831392Seric ** To keep certain mailers from getting confused, 841392Seric ** and to keep the output clean, lines that look 851392Seric ** like UNIX "From" lines are deleted in the header, 861392Seric ** and prepended with ">" in the body. 871392Seric */ 881392Seric 892900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin)) 901392Seric { 914316Seric register char c; 924316Seric extern bool isheader(); 934316Seric 942900Seric /* see if the header is over */ 952900Seric if (!isheader(buf)) 962900Seric break; 972900Seric 982900Seric /* get the rest of this field */ 992900Seric while ((c = getc(stdin)) == ' ' || c == '\t') 1001392Seric { 1012900Seric p = &buf[strlen(buf)]; 1022900Seric *p++ = c; 1032900Seric if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 1042900Seric break; 1051392Seric } 1064083Seric if (!feof(stdin)) 1074083Seric (void) ungetc(c, stdin); 1081392Seric 1092900Seric MsgSize += strlen(buf); 1101392Seric 1112900Seric /* 1122900Seric ** Snarf header away. 1132900Seric */ 1142900Seric 1153391Seric if (bitset(H_EOH, chompheader(buf, FALSE))) 1163058Seric break; 1172900Seric } 1181392Seric 1192900Seric # ifdef DEBUG 1202900Seric if (Debug) 1212900Seric printf("EOH\n"); 1222900Seric # endif DEBUG 1232900Seric 1242900Seric /* throw away a blank line */ 1252900Seric if (buf[0] == '\n') 1264083Seric (void) fgets(buf, sizeof buf, stdin); 1272900Seric 1282900Seric /* 1292900Seric ** Collect the body of the message. 1302900Seric */ 1312900Seric 1322900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 1332900Seric { 1344156Seric register int i; 135*4551Seric register char *bp = buf; 1364156Seric 1372900Seric /* check for end-of-message */ 1382900Seric if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 1392900Seric break; 1402900Seric 141*4551Seric /* check for transparent dot */ 142*4551Seric if (Smtp && *bp == '.') 143*4551Seric bp++; 144*4551Seric 1454321Seric # ifndef NOTUNIX 1462900Seric /* Hide UNIX-like From lines */ 147*4551Seric if (strncmp(bp, "From ", 5) == 0) 1481392Seric { 1492900Seric fputs(">", tf); 1502900Seric MsgSize++; 1511392Seric } 1524321Seric # endif NOTUNIX 1534156Seric 1544156Seric /* 1554156Seric ** Figure message length, output the line to the temp 1564156Seric ** file, and insert a newline if missing. 1574156Seric */ 1584156Seric 159*4551Seric i = strlen(bp); 1604156Seric MsgSize += i; 161*4551Seric fputs(bp, tf); 162*4551Seric if (bp[i - 1] != '\n') 1634156Seric fputs("\n", tf); 1641392Seric if (ferror(tf)) 1651392Seric { 1661439Seric if (errno == ENOSPC) 1671439Seric { 1684083Seric (void) freopen(InFileName, "w", tf); 1691439Seric fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 1704453Seric syserr("collect: Out of disk space for temp file"); 1711439Seric } 1721439Seric else 1734453Seric syserr("collect: Cannot write %s", InFileName); 1744083Seric (void) freopen("/dev/null", "w", tf); 1751392Seric } 1761392Seric } 1774083Seric (void) fclose(tf); 1782900Seric 1792900Seric /* 1802900Seric ** Find out some information from the headers. 1813386Seric ** Examples are who is the from person & the date. 1822900Seric */ 1832900Seric 1842900Seric /* from person */ 1852900Seric xfrom = hvalue("sender"); 1862900Seric if (xfrom == NULL) 1874371Seric xfrom = OrigFrom; 1884162Seric if (ArpaMode != ARPA_NONE) 1894316Seric setfrom(xfrom, (char *) NULL); 1902900Seric 1913390Seric /* full name of from person */ 1923390Seric p = hvalue("full-name"); 1933390Seric if (p != NULL) 1943390Seric define('x', p); 1954210Seric else 1964210Seric { 1974210Seric register char *q; 1983390Seric 1994210Seric /* 2004210Seric ** Try to extract the full name from a general From: 2014210Seric ** field. We take anything which is a comment as a 2024210Seric ** first choice. Failing in that, we see if there is 2034210Seric ** a "machine readable" name (in <angle brackets>); if 2044210Seric ** so we take anything preceeding that clause. 2054210Seric ** 2064210Seric ** If we blow it here it's not all that serious. 2074210Seric */ 2084210Seric 2094210Seric p = hvalue("original-from"); 2104371Seric if (p == NULL) 2114371Seric p = OrigFrom; 2124210Seric q = index(p, '('); 2134210Seric if (q != NULL) 2144210Seric { 2154210Seric int parenlev = 0; 2164210Seric 2174210Seric for (p = q; *p != '\0'; p++) 2184210Seric { 2194210Seric if (*p == '(') 2204210Seric parenlev++; 2214210Seric else if (*p == ')' && --parenlev <= 0) 2224210Seric break; 2234210Seric } 2244210Seric if (*p == ')') 2254210Seric { 2264210Seric *p = '\0'; 2274210Seric if (*++q != '\0') 2284210Seric define('x', newstr(q)); 2294210Seric *p = ')'; 2304210Seric } 2314210Seric } 2324210Seric else if ((q = index(p, '<')) != NULL) 2334210Seric { 2344210Seric char savec; 2354210Seric 2364210Seric while (*--q == ' ') 2374210Seric continue; 2384210Seric while (isspace(*p)) 2394210Seric p++; 2404210Seric savec = *++q; 2414210Seric *q = '\0'; 2424210Seric if (*p != '\0') 2434210Seric define('x', newstr(p)); 2444210Seric *q = savec; 2454210Seric } 2464210Seric } 2474210Seric 2482900Seric /* date message originated */ 2494149Seric p = hvalue("posted-date"); 2504149Seric if (p == NULL) 2514149Seric p = hvalue("date"); 2522900Seric if (p != NULL) 2532900Seric { 2543386Seric define('a', p); 2553386Seric /* we don't have a good way to do canonical conversion .... 2563386Seric define('d', newstr(arpatounix(p))); 2573386Seric .... so we will ignore the problem for the time being */ 2582900Seric } 2592900Seric 2604182Seric if ((TempFile = fopen(InFileName, "r")) == NULL) 2611392Seric syserr("Cannot reopen %s", InFileName); 2622900Seric 2632900Seric # ifdef DEBUG 2642900Seric if (Debug) 2652900Seric { 2664316Seric HDR *h; 2674316Seric extern char *capitalize(); 2684316Seric 2692900Seric printf("----- collected header -----\n"); 2702900Seric for (h = Header; h != NULL; h = h->h_link) 2712900Seric printf("%s: %s\n", capitalize(h->h_field), h->h_value); 2722900Seric printf("----------------------------\n"); 2732900Seric } 2742900Seric # endif DEBUG 2754162Seric return; 2761392Seric } 2771392Seric /* 2782900Seric ** EATFROM -- chew up a UNIX style from line and process 2792900Seric ** 2802900Seric ** This does indeed make some assumptions about the format 2812900Seric ** of UNIX messages. 2822900Seric ** 2832900Seric ** Parameters: 2842900Seric ** fm -- the from line. 2852900Seric ** 2862900Seric ** Returns: 2872900Seric ** none. 2882900Seric ** 2892900Seric ** Side Effects: 2902900Seric ** extracts what information it can from the header, 2913386Seric ** such as the date. 2922900Seric */ 2932900Seric 2944321Seric # ifndef NOTUNIX 2954321Seric 2964203Seric char *DowList[] = 2974203Seric { 2984203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 2994203Seric }; 3004203Seric 3012900Seric char *MonthList[] = 3022900Seric { 3032900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3042900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 3052900Seric NULL 3062900Seric }; 3072900Seric 3082900Seric eatfrom(fm) 3092900Seric char *fm; 3102900Seric { 3112900Seric register char *p; 3122900Seric register char **dt; 3132900Seric 3144203Seric # ifdef DEBUG 3154203Seric if (Debug > 1) 3164203Seric printf("eatfrom(%s)\n", fm); 3174203Seric # endif DEBUG 3184203Seric 3192900Seric /* find the date part */ 3202900Seric p = fm; 3212900Seric while (*p != '\0') 3222900Seric { 3232900Seric /* skip a word */ 3242900Seric while (*p != '\0' && *p != ' ') 3252900Seric *p++; 3262900Seric while (*p == ' ') 3272900Seric *p++; 3282900Seric if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 3292900Seric continue; 3302900Seric 3312900Seric /* we have a possible date */ 3324203Seric for (dt = DowList; *dt != NULL; dt++) 3332900Seric if (strncmp(*dt, p, 3) == 0) 3342900Seric break; 3354203Seric if (*dt == NULL) 3364203Seric continue; 3372900Seric 3384203Seric for (dt = MonthList; *dt != NULL; dt++) 3394203Seric if (strncmp(*dt, &p[4], 3) == 0) 3404203Seric break; 3412900Seric if (*dt != NULL) 3422900Seric break; 3432900Seric } 3442900Seric 3452900Seric if (*p != NULL) 3462900Seric { 3473386Seric char *q; 3483386Seric 3492900Seric /* we have found a date */ 3503386Seric q = xalloc(25); 3513386Seric strncpy(q, p, 25); 3523386Seric q[24] = '\0'; 3533386Seric define('d', q); 3542900Seric } 3552900Seric } 3564321Seric 3574321Seric # endif NOTUNIX 358