122697Sdist /* 222697Sdist ** Sendmail 322697Sdist ** Copyright (c) 1983 Eric P. Allman 422697Sdist ** Berkeley, California 522697Sdist ** 622697Sdist ** Copyright (c) 1983 Regents of the University of California. 722697Sdist ** All rights reserved. The Berkeley software License Agreement 822697Sdist ** specifies the terms and conditions for redistribution. 922697Sdist */ 1022697Sdist 1122697Sdist #ifndef lint 12*23103Seric static char SccsId[] = "@(#)collect.c 5.2 (Berkeley) 06/08/85"; 1322697Sdist #endif not lint 1422697Sdist 151439Seric # include <errno.h> 163309Seric # include "sendmail.h" 171392Seric 181392Seric /* 192969Seric ** COLLECT -- read & parse message header & make temp file. 201392Seric ** 211392Seric ** Creates a temporary file name and copies the standard 229371Seric ** input to that file. Leading UNIX-style "From" lines are 239371Seric ** stripped off (after important information is extracted). 241392Seric ** 251392Seric ** Parameters: 264710Seric ** sayok -- if set, give an ARPANET style message 274710Seric ** to say we are ready to collect input. 281392Seric ** 291392Seric ** Returns: 304162Seric ** none. 311392Seric ** 321392Seric ** Side Effects: 331392Seric ** Temp file is created and filled. 344162Seric ** The from person may be set. 351392Seric */ 361392Seric 374710Seric collect(sayok) 384710Seric bool sayok; 391392Seric { 401392Seric register FILE *tf; 417852Seric char buf[MAXFIELD+2]; 421392Seric register char *p; 432900Seric extern char *hvalue(); 441392Seric 451392Seric /* 461392Seric ** Create the temp file name and create the file. 471392Seric */ 481392Seric 497809Seric CurEnv->e_df = newstr(queuename(CurEnv, 'd')); 507809Seric if ((tf = dfopen(CurEnv->e_df, "w")) == NULL) 511392Seric { 527809Seric syserr("Cannot create %s", CurEnv->e_df); 535366Seric NoReturn = TRUE; 545366Seric finis(); 551392Seric } 569047Seric (void) chmod(CurEnv->e_df, FileMode); 571392Seric 584316Seric /* 594322Seric ** Tell ARPANET to go ahead. 604322Seric */ 614322Seric 624710Seric if (sayok) 634710Seric message("354", "Enter mail, end with \".\" on a line by itself"); 644322Seric 654322Seric /* 664316Seric ** Try to read a UNIX-style From line 674316Seric */ 684316Seric 6915532Seric (void) sfgets(buf, sizeof buf, InChannel); 704557Seric fixcrlf(buf, FALSE); 714321Seric # ifndef NOTUNIX 724322Seric if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 732900Seric { 742900Seric eatfrom(buf); 7513932Seric (void) sfgets(buf, sizeof buf, InChannel); 764557Seric fixcrlf(buf, FALSE); 772900Seric } 784321Seric # endif NOTUNIX 792900Seric 801392Seric /* 815975Seric ** Copy InChannel to temp file & do message editing. 821392Seric ** To keep certain mailers from getting confused, 831392Seric ** and to keep the output clean, lines that look 8413932Seric ** like UNIX "From" lines are deleted in the header. 851392Seric */ 861392Seric 8715532Seric do 881392Seric { 8915532Seric int c; 904316Seric extern bool isheader(); 914316Seric 9219036Seric /* drop out on error */ 9319036Seric if (ferror(InChannel)) 9419036Seric break; 9519036Seric 967681Seric /* if the line is too long, throw the rest away */ 977681Seric if (index(buf, '\n') == NULL) 987681Seric { 9915532Seric while ((c = getc(InChannel)) != '\n' && c != EOF) 1007681Seric continue; 1017681Seric /* give an error? */ 1027681Seric } 1037681Seric 1047852Seric fixcrlf(buf, TRUE); 1054557Seric 1062900Seric /* see if the header is over */ 1072900Seric if (!isheader(buf)) 1082900Seric break; 1092900Seric 1102900Seric /* get the rest of this field */ 1115975Seric while ((c = getc(InChannel)) == ' ' || c == '\t') 1121392Seric { 1132900Seric p = &buf[strlen(buf)]; 1147852Seric *p++ = '\n'; 1152900Seric *p++ = c; 11613932Seric if (sfgets(p, MAXFIELD - (p - buf), InChannel) == NULL) 1172900Seric break; 1187852Seric fixcrlf(p, TRUE); 1191392Seric } 12019036Seric if (!feof(InChannel) && !ferror(InChannel)) 1215975Seric (void) ungetc(c, InChannel); 1221392Seric 1236901Seric CurEnv->e_msgsize += strlen(buf); 1241392Seric 1252900Seric /* 1262900Seric ** Snarf header away. 1272900Seric */ 1282900Seric 1293391Seric if (bitset(H_EOH, chompheader(buf, FALSE))) 1303058Seric break; 13115532Seric } while (sfgets(buf, MAXFIELD, InChannel) != NULL); 1321392Seric 1332900Seric # ifdef DEBUG 1347673Seric if (tTd(30, 1)) 1352900Seric printf("EOH\n"); 1362900Seric # endif DEBUG 1372900Seric 1382900Seric /* throw away a blank line */ 1397852Seric if (buf[0] == '\0') 14013932Seric (void) sfgets(buf, MAXFIELD, InChannel); 1412900Seric 1422900Seric /* 1432900Seric ** Collect the body of the message. 1442900Seric */ 1452900Seric 14615532Seric do 1472900Seric { 1484551Seric register char *bp = buf; 1494156Seric 1507852Seric fixcrlf(buf, TRUE); 1514557Seric 1522900Seric /* check for end-of-message */ 1532900Seric if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 1542900Seric break; 1552900Seric 1564551Seric /* check for transparent dot */ 1579371Seric if (OpMode == MD_SMTP && !IgnrDot && bp[0] == '.' && bp[1] == '.') 1584551Seric bp++; 1594551Seric 1604156Seric /* 1614156Seric ** Figure message length, output the line to the temp 1624156Seric ** file, and insert a newline if missing. 1634156Seric */ 1644156Seric 1659371Seric CurEnv->e_msgsize += strlen(bp) + 1; 1664551Seric fputs(bp, tf); 1677852Seric fputs("\n", tf); 1681392Seric if (ferror(tf)) 16911544Seric tferror(tf); 17015532Seric } while (sfgets(buf, MAXFIELD, InChannel) != NULL); 17111544Seric if (fflush(tf) != 0) 17211544Seric tferror(tf); 1734083Seric (void) fclose(tf); 1742900Seric 17511145Seric /* An EOF when running SMTP is an error */ 17619036Seric if ((feof(InChannel) || ferror(InChannel)) && OpMode == MD_SMTP) 17716136Seric { 17816136Seric syserr("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr); 17911145Seric 18016136Seric /* don't return an error indication */ 18116136Seric CurEnv->e_to = NULL; 18216136Seric CurEnv->e_flags &= ~EF_FATALERRS; 18316136Seric 18416136Seric /* and don't try to deliver the partial message either */ 18516136Seric finis(); 18616136Seric } 18716136Seric 1882900Seric /* 1892900Seric ** Find out some information from the headers. 1903386Seric ** Examples are who is the from person & the date. 1912900Seric */ 1922900Seric 1939371Seric eatheader(CurEnv); 1947673Seric 1957782Seric /* 1967782Seric ** Add an Apparently-To: line if we have no recipient lines. 1977782Seric */ 1984622Seric 1997367Seric if (hvalue("to") == NULL && hvalue("cc") == NULL && 2007367Seric hvalue("bcc") == NULL && hvalue("apparently-to") == NULL) 2017367Seric { 2027367Seric register ADDRESS *q; 2037367Seric 2047367Seric /* create an Apparently-To: field */ 2057367Seric /* that or reject the message.... */ 2067367Seric for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 2077367Seric { 2087389Seric if (q->q_alias != NULL) 2097389Seric continue; 2107367Seric # ifdef DEBUG 2117673Seric if (tTd(30, 3)) 2127367Seric printf("Adding Apparently-To: %s\n", q->q_paddr); 2137367Seric # endif DEBUG 2147367Seric addheader("apparently-to", q->q_paddr, CurEnv); 2157367Seric } 2167367Seric } 2177367Seric 2189539Seric if ((CurEnv->e_dfp = fopen(CurEnv->e_df, "r")) == NULL) 2196986Seric syserr("Cannot reopen %s", CurEnv->e_df); 2201392Seric } 2211392Seric /* 22211544Seric ** TFERROR -- signal error on writing the temporary file. 22311544Seric ** 22411544Seric ** Parameters: 22511544Seric ** tf -- the file pointer for the temporary file. 22611544Seric ** 22711544Seric ** Returns: 22811544Seric ** none. 22911544Seric ** 23011544Seric ** Side Effects: 23111544Seric ** Gives an error message. 23211544Seric ** Arranges for following output to go elsewhere. 23311544Seric */ 23411544Seric 23511544Seric tferror(tf) 23611544Seric FILE *tf; 23711544Seric { 23811544Seric if (errno == ENOSPC) 23911544Seric { 24011544Seric (void) freopen(CurEnv->e_df, "w", tf); 24111544Seric fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 24211544Seric usrerr("452 Out of disk space for temp file"); 24311544Seric } 24411544Seric else 24511544Seric syserr("collect: Cannot write %s", CurEnv->e_df); 24611544Seric (void) freopen("/dev/null", "w", tf); 24711544Seric } 24811544Seric /* 2492900Seric ** EATFROM -- chew up a UNIX style from line and process 2502900Seric ** 2512900Seric ** This does indeed make some assumptions about the format 2522900Seric ** of UNIX messages. 2532900Seric ** 2542900Seric ** Parameters: 2552900Seric ** fm -- the from line. 2562900Seric ** 2572900Seric ** Returns: 2582900Seric ** none. 2592900Seric ** 2602900Seric ** Side Effects: 2612900Seric ** extracts what information it can from the header, 2623386Seric ** such as the date. 2632900Seric */ 2642900Seric 2654321Seric # ifndef NOTUNIX 2664321Seric 2674203Seric char *DowList[] = 2684203Seric { 2694203Seric "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 2704203Seric }; 2714203Seric 2722900Seric char *MonthList[] = 2732900Seric { 2742900Seric "Jan", "Feb", "Mar", "Apr", "May", "Jun", 2752900Seric "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 2762900Seric NULL 2772900Seric }; 2782900Seric 2792900Seric eatfrom(fm) 2802900Seric char *fm; 2812900Seric { 2822900Seric register char *p; 2832900Seric register char **dt; 2842900Seric 2854203Seric # ifdef DEBUG 2867673Seric if (tTd(30, 2)) 2874203Seric printf("eatfrom(%s)\n", fm); 2884203Seric # endif DEBUG 2894203Seric 2902900Seric /* find the date part */ 2912900Seric p = fm; 2922900Seric while (*p != '\0') 2932900Seric { 2942900Seric /* skip a word */ 2952900Seric while (*p != '\0' && *p != ' ') 29616896Seric p++; 2972900Seric while (*p == ' ') 29816896Seric p++; 2992900Seric if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 3002900Seric continue; 3012900Seric 3022900Seric /* we have a possible date */ 3034203Seric for (dt = DowList; *dt != NULL; dt++) 3042900Seric if (strncmp(*dt, p, 3) == 0) 3052900Seric break; 3064203Seric if (*dt == NULL) 3074203Seric continue; 3082900Seric 3094203Seric for (dt = MonthList; *dt != NULL; dt++) 3104203Seric if (strncmp(*dt, &p[4], 3) == 0) 3114203Seric break; 3122900Seric if (*dt != NULL) 3132900Seric break; 3142900Seric } 3152900Seric 3162900Seric if (*p != NULL) 3172900Seric { 3183386Seric char *q; 3195366Seric extern char *arpadate(); 3203386Seric 3212900Seric /* we have found a date */ 3223386Seric q = xalloc(25); 323*23103Seric (void) strncpy(q, p, 25); 3243386Seric q[24] = '\0'; 3259371Seric define('d', q, CurEnv); 3265366Seric q = arpadate(q); 3279371Seric define('a', newstr(q), CurEnv); 3282900Seric } 3292900Seric } 3304321Seric 3314321Seric # endif NOTUNIX 332