11439Seric # include <errno.h> 23309Seric # include "sendmail.h" 31392Seric 4*4557Seric static char SccsId[] = "@(#)collect.c 3.25 10/20/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; 73*4557Seric fixcrlf(buf, FALSE); 744321Seric # ifndef NOTUNIX 754322Seric if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 762900Seric { 772900Seric eatfrom(buf); 784083Seric (void) fgets(buf, sizeof buf, stdin); 79*4557Seric fixcrlf(buf, FALSE); 802900Seric } 814321Seric # endif NOTUNIX 822900Seric 831392Seric /* 841392Seric ** Copy stdin to temp file & do message editting. 851392Seric ** To keep certain mailers from getting confused, 861392Seric ** and to keep the output clean, lines that look 871392Seric ** like UNIX "From" lines are deleted in the header, 881392Seric ** and prepended with ">" in the body. 891392Seric */ 901392Seric 912900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin)) 921392Seric { 934316Seric register char c; 944316Seric extern bool isheader(); 954316Seric 96*4557Seric fixcrlf(buf, FALSE); 97*4557Seric 982900Seric /* see if the header is over */ 992900Seric if (!isheader(buf)) 1002900Seric break; 1012900Seric 1022900Seric /* get the rest of this field */ 1032900Seric while ((c = getc(stdin)) == ' ' || c == '\t') 1041392Seric { 1052900Seric p = &buf[strlen(buf)]; 1062900Seric *p++ = c; 1072900Seric if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 1082900Seric break; 109*4557Seric fixcrlf(p, FALSE); 1101392Seric } 1114083Seric if (!feof(stdin)) 1124083Seric (void) ungetc(c, stdin); 1131392Seric 1142900Seric MsgSize += strlen(buf); 1151392Seric 1162900Seric /* 1172900Seric ** Snarf header away. 1182900Seric */ 1192900Seric 1203391Seric if (bitset(H_EOH, chompheader(buf, FALSE))) 1213058Seric break; 1222900Seric } 1231392Seric 1242900Seric # ifdef DEBUG 1252900Seric if (Debug) 1262900Seric printf("EOH\n"); 1272900Seric # endif DEBUG 1282900Seric 1292900Seric /* throw away a blank line */ 1302900Seric if (buf[0] == '\n') 131*4557Seric { 1324083Seric (void) fgets(buf, sizeof buf, stdin); 133*4557Seric fixcrlf(buf, FALSE); 134*4557Seric } 1352900Seric 1362900Seric /* 1372900Seric ** Collect the body of the message. 1382900Seric */ 1392900Seric 1402900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 1412900Seric { 1424156Seric register int i; 1434551Seric register char *bp = buf; 1444156Seric 145*4557Seric fixcrlf(buf, FALSE); 146*4557Seric 1472900Seric /* check for end-of-message */ 1482900Seric if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 1492900Seric break; 1502900Seric 1514551Seric /* check for transparent dot */ 1524551Seric if (Smtp && *bp == '.') 1534551Seric bp++; 1544551Seric 1554321Seric # ifndef NOTUNIX 1562900Seric /* Hide UNIX-like From lines */ 1574551Seric if (strncmp(bp, "From ", 5) == 0) 1581392Seric { 1592900Seric fputs(">", tf); 1602900Seric MsgSize++; 1611392Seric } 1624321Seric # endif NOTUNIX 1634156Seric 1644156Seric /* 1654156Seric ** Figure message length, output the line to the temp 1664156Seric ** file, and insert a newline if missing. 1674156Seric */ 1684156Seric 1694551Seric i = strlen(bp); 1704156Seric MsgSize += i; 1714551Seric fputs(bp, tf); 1724551Seric if (bp[i - 1] != '\n') 1734156Seric fputs("\n", tf); 1741392Seric if (ferror(tf)) 1751392Seric { 1761439Seric if (errno == ENOSPC) 1771439Seric { 1784083Seric (void) freopen(InFileName, "w", tf); 1791439Seric fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 180*4557Seric usrerr("452 Out of disk space for temp file"); 1811439Seric } 1821439Seric else 1834453Seric syserr("collect: Cannot write %s", InFileName); 1844083Seric (void) freopen("/dev/null", "w", tf); 1851392Seric } 1861392Seric } 1874083Seric (void) fclose(tf); 1882900Seric 1892900Seric /* 1902900Seric ** Find out some information from the headers. 1913386Seric ** Examples are who is the from person & the date. 1922900Seric */ 1932900Seric 1942900Seric /* from person */ 1952900Seric xfrom = hvalue("sender"); 1962900Seric if (xfrom == NULL) 1974371Seric xfrom = OrigFrom; 1984162Seric if (ArpaMode != ARPA_NONE) 1994316Seric setfrom(xfrom, (char *) NULL); 2002900Seric 2013390Seric /* full name of from person */ 2023390Seric p = hvalue("full-name"); 2033390Seric if (p != NULL) 2043390Seric define('x', p); 2054210Seric else 2064210Seric { 2074210Seric register char *q; 2083390Seric 2094210Seric /* 2104210Seric ** Try to extract the full name from a general From: 2114210Seric ** field. We take anything which is a comment as a 2124210Seric ** first choice. Failing in that, we see if there is 2134210Seric ** a "machine readable" name (in <angle brackets>); if 2144210Seric ** so we take anything preceeding that clause. 2154210Seric ** 2164210Seric ** If we blow it here it's not all that serious. 2174210Seric */ 2184210Seric 2194210Seric p = hvalue("original-from"); 2204371Seric if (p == NULL) 2214371Seric p = OrigFrom; 2224210Seric q = index(p, '('); 2234210Seric if (q != NULL) 2244210Seric { 2254210Seric int parenlev = 0; 2264210Seric 2274210Seric for (p = q; *p != '\0'; p++) 2284210Seric { 2294210Seric if (*p == '(') 2304210Seric parenlev++; 2314210Seric else if (*p == ')' && --parenlev <= 0) 2324210Seric break; 2334210Seric } 2344210Seric if (*p == ')') 2354210Seric { 2364210Seric *p = '\0'; 2374210Seric if (*++q != '\0') 2384210Seric define('x', newstr(q)); 2394210Seric *p = ')'; 2404210Seric } 2414210Seric } 2424210Seric else if ((q = index(p, '<')) != NULL) 2434210Seric { 2444210Seric char savec; 2454210Seric 2464210Seric while (*--q == ' ') 2474210Seric continue; 2484210Seric while (isspace(*p)) 2494210Seric p++; 2504210Seric savec = *++q; 2514210Seric *q = '\0'; 2524210Seric if (*p != '\0') 2534210Seric define('x', newstr(p)); 2544210Seric *q = savec; 2554210Seric } 2564210Seric } 2574210Seric 2582900Seric /* date message originated */ 2594149Seric p = hvalue("posted-date"); 2604149Seric if (p == NULL) 2614149Seric p = hvalue("date"); 2622900Seric if (p != NULL) 2632900Seric { 2643386Seric define('a', p); 2653386Seric /* we don't have a good way to do canonical conversion .... 2663386Seric define('d', newstr(arpatounix(p))); 2673386Seric .... so we will ignore the problem for the time being */ 2682900Seric } 2692900Seric 2704182Seric if ((TempFile = fopen(InFileName, "r")) == NULL) 2711392Seric syserr("Cannot reopen %s", InFileName); 2722900Seric 2732900Seric # ifdef DEBUG 2742900Seric if (Debug) 2752900Seric { 2764316Seric HDR *h; 2774316Seric extern char *capitalize(); 2784316Seric 2792900Seric printf("----- collected header -----\n"); 2802900Seric for (h = Header; h != NULL; h = h->h_link) 2812900Seric printf("%s: %s\n", capitalize(h->h_field), h->h_value); 2822900Seric printf("----------------------------\n"); 2832900Seric } 2842900Seric # endif DEBUG 2854162Seric return; 2861392Seric } 2871392Seric /* 2882900Seric ** EATFROM -- chew up a UNIX style from line and process 2892900Seric ** 2902900Seric ** This does indeed make some assumptions about the format 2912900Seric ** of UNIX messages. 2922900Seric ** 2932900Seric ** Parameters: 2942900Seric ** fm -- the from line. 2952900Seric ** 2962900Seric ** Returns: 2972900Seric ** none. 2982900Seric ** 2992900Seric ** Side Effects: 3002900Seric ** extracts what information it can from the header, 3013386Seric ** such as the date. 3022900Seric */ 3032900Seric 3044321Seric # ifndef NOTUNIX 3054321Seric 3064203Seric char *DowList[] = 3074203Seric { 3084203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 3094203Seric }; 3104203Seric 3112900Seric char *MonthList[] = 3122900Seric { 3132900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3142900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 3152900Seric NULL 3162900Seric }; 3172900Seric 3182900Seric eatfrom(fm) 3192900Seric char *fm; 3202900Seric { 3212900Seric register char *p; 3222900Seric register char **dt; 3232900Seric 3244203Seric # ifdef DEBUG 3254203Seric if (Debug > 1) 3264203Seric printf("eatfrom(%s)\n", fm); 3274203Seric # endif DEBUG 3284203Seric 3292900Seric /* find the date part */ 3302900Seric p = fm; 3312900Seric while (*p != '\0') 3322900Seric { 3332900Seric /* skip a word */ 3342900Seric while (*p != '\0' && *p != ' ') 3352900Seric *p++; 3362900Seric while (*p == ' ') 3372900Seric *p++; 3382900Seric if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 3392900Seric continue; 3402900Seric 3412900Seric /* we have a possible date */ 3424203Seric for (dt = DowList; *dt != NULL; dt++) 3432900Seric if (strncmp(*dt, p, 3) == 0) 3442900Seric break; 3454203Seric if (*dt == NULL) 3464203Seric continue; 3472900Seric 3484203Seric for (dt = MonthList; *dt != NULL; dt++) 3494203Seric if (strncmp(*dt, &p[4], 3) == 0) 3504203Seric break; 3512900Seric if (*dt != NULL) 3522900Seric break; 3532900Seric } 3542900Seric 3552900Seric if (*p != NULL) 3562900Seric { 3573386Seric char *q; 3583386Seric 3592900Seric /* we have found a date */ 3603386Seric q = xalloc(25); 3613386Seric strncpy(q, p, 25); 3623386Seric q[24] = '\0'; 3633386Seric define('d', q); 3642900Seric } 3652900Seric } 3664321Seric 3674321Seric # endif NOTUNIX 368