11439Seric # include <errno.h> 23309Seric # include "sendmail.h" 31392Seric 4*4633Seric static char SccsId[] = "@(#)collect.c 3.27 10/27/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 */ 331397Seric 342969Seric collect() 351392Seric { 361392Seric register FILE *tf; 371392Seric char buf[MAXFIELD+1]; 381392Seric register char *p; 392900Seric char *xfrom; 402900Seric extern char *hvalue(); 414083Seric extern char *mktemp(); 424622Seric static char tempfname[40]; 434622Seric extern char *QueueDir; 441392Seric 451392Seric /* 461392Seric ** Create the temp file name and create the file. 471392Seric */ 481392Seric 494622Seric strcpy(tempfname, QueueDir); 504622Seric strcat(tempfname, "/dfaXXXXXX"); 514622Seric (void) mktemp(tempfname); 524622Seric (void) close(creat(tempfname, 0600)); 534622Seric if ((tf = fopen(tempfname, "w")) == NULL) 541392Seric { 554622Seric syserr("Cannot create %s", tempfname); 564162Seric return; 571392Seric } 584622Seric InFileName = tempfname; 591392Seric 604316Seric /* 614322Seric ** Tell ARPANET to go ahead. 624322Seric */ 634322Seric 644322Seric if (ArpaMode == ARPA_MAIL) 654322Seric { 664322Seric extern char Arpa_Enter[]; 674322Seric 684322Seric message(Arpa_Enter, "Enter mail, end with \".\" on a line by itself"); 694322Seric } 704322Seric 714322Seric /* 724316Seric ** Try to read a UNIX-style From line 734316Seric */ 744316Seric 752900Seric if (fgets(buf, sizeof buf, stdin) == NULL) 764162Seric return; 774557Seric fixcrlf(buf, FALSE); 784321Seric # ifndef NOTUNIX 794322Seric if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 802900Seric { 812900Seric eatfrom(buf); 824083Seric (void) fgets(buf, sizeof buf, stdin); 834557Seric fixcrlf(buf, FALSE); 842900Seric } 854321Seric # endif NOTUNIX 862900Seric 871392Seric /* 881392Seric ** Copy stdin to temp file & do message editting. 891392Seric ** To keep certain mailers from getting confused, 901392Seric ** and to keep the output clean, lines that look 911392Seric ** like UNIX "From" lines are deleted in the header, 921392Seric ** and prepended with ">" in the body. 931392Seric */ 941392Seric 954622Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 961392Seric { 974316Seric register char c; 984316Seric extern bool isheader(); 994316Seric 1004557Seric fixcrlf(buf, FALSE); 1014557Seric 1022900Seric /* see if the header is over */ 1032900Seric if (!isheader(buf)) 1042900Seric break; 1052900Seric 1062900Seric /* get the rest of this field */ 1072900Seric while ((c = getc(stdin)) == ' ' || c == '\t') 1081392Seric { 1092900Seric p = &buf[strlen(buf)]; 1102900Seric *p++ = c; 1112900Seric if (fgets(p, sizeof buf - (p - buf), stdin) == NULL) 1122900Seric break; 1134557Seric fixcrlf(p, FALSE); 1141392Seric } 1154083Seric if (!feof(stdin)) 1164083Seric (void) ungetc(c, stdin); 1171392Seric 1182900Seric MsgSize += strlen(buf); 1191392Seric 1202900Seric /* 1212900Seric ** Snarf header away. 1222900Seric */ 1232900Seric 1243391Seric if (bitset(H_EOH, chompheader(buf, FALSE))) 1253058Seric break; 1262900Seric } 1271392Seric 1282900Seric # ifdef DEBUG 1292900Seric if (Debug) 1302900Seric printf("EOH\n"); 1312900Seric # endif DEBUG 1322900Seric 1332900Seric /* throw away a blank line */ 1342900Seric if (buf[0] == '\n') 1354557Seric { 1364083Seric (void) fgets(buf, sizeof buf, stdin); 1374557Seric fixcrlf(buf, FALSE); 1384557Seric } 1392900Seric 1402900Seric /* 1412900Seric ** Collect the body of the message. 1422900Seric */ 1432900Seric 1442900Seric for (; !feof(stdin); !feof(stdin) && fgets(buf, sizeof buf, stdin) != NULL) 1452900Seric { 1464156Seric register int i; 1474551Seric register char *bp = buf; 1484156Seric 1494557Seric fixcrlf(buf, FALSE); 1504557Seric 1512900Seric /* check for end-of-message */ 1522900Seric if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 1532900Seric break; 1542900Seric 1554551Seric /* check for transparent dot */ 1564551Seric if (Smtp && *bp == '.') 1574551Seric bp++; 1584551Seric 1594321Seric # ifndef NOTUNIX 1602900Seric /* Hide UNIX-like From lines */ 1614551Seric if (strncmp(bp, "From ", 5) == 0) 1621392Seric { 1632900Seric fputs(">", tf); 1642900Seric MsgSize++; 1651392Seric } 1664321Seric # endif NOTUNIX 1674156Seric 1684156Seric /* 1694156Seric ** Figure message length, output the line to the temp 1704156Seric ** file, and insert a newline if missing. 1714156Seric */ 1724156Seric 1734551Seric i = strlen(bp); 1744156Seric MsgSize += i; 1754551Seric fputs(bp, tf); 1764551Seric if (bp[i - 1] != '\n') 1774156Seric fputs("\n", tf); 1781392Seric if (ferror(tf)) 1791392Seric { 1801439Seric if (errno == ENOSPC) 1811439Seric { 1824083Seric (void) freopen(InFileName, "w", tf); 1831439Seric fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 1844557Seric usrerr("452 Out of disk space for temp file"); 1851439Seric } 1861439Seric else 1874453Seric syserr("collect: Cannot write %s", InFileName); 1884083Seric (void) freopen("/dev/null", "w", tf); 1891392Seric } 1901392Seric } 1914083Seric (void) fclose(tf); 1922900Seric 1932900Seric /* 1942900Seric ** Find out some information from the headers. 1953386Seric ** Examples are who is the from person & the date. 1962900Seric */ 1972900Seric 1984622Seric /* message priority */ 1994622Seric p = hvalue("priority"); 2004622Seric if (p != NULL) 2014622Seric MsgPriority = priencode(p); 2024622Seric 2032900Seric /* from person */ 2042900Seric xfrom = hvalue("sender"); 2052900Seric if (xfrom == NULL) 2064371Seric xfrom = OrigFrom; 2074162Seric if (ArpaMode != ARPA_NONE) 2084316Seric setfrom(xfrom, (char *) NULL); 2092900Seric 2103390Seric /* full name of from person */ 2113390Seric p = hvalue("full-name"); 2123390Seric if (p != NULL) 2133390Seric define('x', p); 2144210Seric else 2154210Seric { 2164210Seric register char *q; 2173390Seric 2184210Seric /* 2194210Seric ** Try to extract the full name from a general From: 2204210Seric ** field. We take anything which is a comment as a 2214210Seric ** first choice. Failing in that, we see if there is 2224210Seric ** a "machine readable" name (in <angle brackets>); if 2234210Seric ** so we take anything preceeding that clause. 2244210Seric ** 2254210Seric ** If we blow it here it's not all that serious. 2264210Seric */ 2274210Seric 2284210Seric p = hvalue("original-from"); 2294371Seric if (p == NULL) 2304371Seric p = OrigFrom; 2314210Seric q = index(p, '('); 2324210Seric if (q != NULL) 2334210Seric { 2344210Seric int parenlev = 0; 2354210Seric 2364210Seric for (p = q; *p != '\0'; p++) 2374210Seric { 2384210Seric if (*p == '(') 2394210Seric parenlev++; 2404210Seric else if (*p == ')' && --parenlev <= 0) 2414210Seric break; 2424210Seric } 2434210Seric if (*p == ')') 2444210Seric { 2454210Seric *p = '\0'; 2464210Seric if (*++q != '\0') 2474210Seric define('x', newstr(q)); 2484210Seric *p = ')'; 2494210Seric } 2504210Seric } 2514210Seric else if ((q = index(p, '<')) != NULL) 2524210Seric { 2534210Seric char savec; 2544210Seric 2554210Seric while (*--q == ' ') 2564210Seric continue; 2574210Seric while (isspace(*p)) 2584210Seric p++; 2594210Seric savec = *++q; 2604210Seric *q = '\0'; 2614210Seric if (*p != '\0') 2624210Seric define('x', newstr(p)); 2634210Seric *q = savec; 2644210Seric } 2654210Seric } 2664210Seric 2672900Seric /* date message originated */ 2684149Seric p = hvalue("posted-date"); 2694149Seric if (p == NULL) 2704149Seric p = hvalue("date"); 2712900Seric if (p != NULL) 2722900Seric { 2733386Seric define('a', p); 2743386Seric /* we don't have a good way to do canonical conversion .... 2753386Seric define('d', newstr(arpatounix(p))); 2763386Seric .... so we will ignore the problem for the time being */ 2772900Seric } 2782900Seric 2794182Seric if ((TempFile = fopen(InFileName, "r")) == NULL) 2801392Seric syserr("Cannot reopen %s", InFileName); 2812900Seric 2822900Seric # ifdef DEBUG 2832900Seric if (Debug) 2842900Seric { 2854316Seric HDR *h; 2864316Seric extern char *capitalize(); 2874316Seric 2882900Seric printf("----- collected header -----\n"); 2892900Seric for (h = Header; h != NULL; h = h->h_link) 2902900Seric printf("%s: %s\n", capitalize(h->h_field), h->h_value); 2912900Seric printf("----------------------------\n"); 2922900Seric } 2932900Seric # endif DEBUG 2944162Seric return; 2951392Seric } 2961392Seric /* 2972900Seric ** EATFROM -- chew up a UNIX style from line and process 2982900Seric ** 2992900Seric ** This does indeed make some assumptions about the format 3002900Seric ** of UNIX messages. 3012900Seric ** 3022900Seric ** Parameters: 3032900Seric ** fm -- the from line. 3042900Seric ** 3052900Seric ** Returns: 3062900Seric ** none. 3072900Seric ** 3082900Seric ** Side Effects: 3092900Seric ** extracts what information it can from the header, 3103386Seric ** such as the date. 3112900Seric */ 3122900Seric 3134321Seric # ifndef NOTUNIX 3144321Seric 3154203Seric char *DowList[] = 3164203Seric { 3174203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 3184203Seric }; 3194203Seric 3202900Seric char *MonthList[] = 3212900Seric { 3222900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 3232900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 3242900Seric NULL 3252900Seric }; 3262900Seric 3272900Seric eatfrom(fm) 3282900Seric char *fm; 3292900Seric { 3302900Seric register char *p; 3312900Seric register char **dt; 3322900Seric 3334203Seric # ifdef DEBUG 3344203Seric if (Debug > 1) 3354203Seric printf("eatfrom(%s)\n", fm); 3364203Seric # endif DEBUG 3374203Seric 3382900Seric /* find the date part */ 3392900Seric p = fm; 3402900Seric while (*p != '\0') 3412900Seric { 3422900Seric /* skip a word */ 3432900Seric while (*p != '\0' && *p != ' ') 3442900Seric *p++; 3452900Seric while (*p == ' ') 3462900Seric *p++; 3472900Seric if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 3482900Seric continue; 3492900Seric 3502900Seric /* we have a possible date */ 3514203Seric for (dt = DowList; *dt != NULL; dt++) 3522900Seric if (strncmp(*dt, p, 3) == 0) 3532900Seric break; 3544203Seric if (*dt == NULL) 3554203Seric continue; 3562900Seric 3574203Seric for (dt = MonthList; *dt != NULL; dt++) 3584203Seric if (strncmp(*dt, &p[4], 3) == 0) 3594203Seric break; 3602900Seric if (*dt != NULL) 3612900Seric break; 3622900Seric } 3632900Seric 3642900Seric if (*p != NULL) 3652900Seric { 3663386Seric char *q; 3673386Seric 3682900Seric /* we have found a date */ 3693386Seric q = xalloc(25); 3703386Seric strncpy(q, p, 25); 3713386Seric q[24] = '\0'; 3723386Seric define('d', q); 3732900Seric } 3742900Seric } 3754321Seric 3764321Seric # endif NOTUNIX 3774622Seric /* 3784622Seric ** PRIENCODE -- encode external priority names into internal values. 3794622Seric ** 3804622Seric ** Parameters: 3814622Seric ** p -- priority in ascii. 3824622Seric ** 3834622Seric ** Returns: 3844622Seric ** priority as a numeric level. 3854622Seric ** 3864622Seric ** Side Effects: 3874622Seric ** none. 3884622Seric */ 3894622Seric 3904622Seric struct prio 3914622Seric { 3924622Seric char *pri_name; /* external name of priority */ 3934622Seric int pri_val; /* internal value for same */ 3944622Seric }; 3954622Seric 3964622Seric static struct prio Prio[] = 3974622Seric { 398*4633Seric "alert", PRI_ALERT, 399*4633Seric "quick", PRI_QUICK, 400*4633Seric "first-class", PRI_FIRSTCL, 4014622Seric "normal", PRI_NORMAL, 4024622Seric "second-class", PRI_SECONDCL, 4034622Seric "third-class", PRI_THIRDCL, 4044622Seric NULL, PRI_NORMAL, 4054622Seric }; 4064622Seric 4074622Seric priencode(p) 4084622Seric char *p; 4094622Seric { 4104622Seric register struct prio *pl; 411*4633Seric extern bool sameword(); 4124622Seric 4134622Seric for (pl = Prio; pl->pri_name != NULL; pl++) 4144622Seric { 415*4633Seric if (sameword(p, pl->pri_name)) 4164622Seric break; 4174622Seric } 4184622Seric return (pl->pri_val); 4194622Seric } 420