1: /* 2: * Copyright (c) 1988 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: * 12: * Sendmail 13: * Copyright (c) 1983 Eric P. Allman 14: * Berkeley, California 15: */ 16: 17: #if !defined(lint) && !defined(NOSCCS) 18: static char sccsid[] = "@(#)collect.c 5.3 (Berkeley) 3/13/88"; 19: #endif /* not lint */ 20: 21: # include <errno.h> 22: # include "sendmail.h" 23: 24: /* 25: ** COLLECT -- read & parse message header & make temp file. 26: ** 27: ** Creates a temporary file name and copies the standard 28: ** input to that file. Leading UNIX-style "From" lines are 29: ** stripped off (after important information is extracted). 30: ** 31: ** Parameters: 32: ** sayok -- if set, give an ARPANET style message 33: ** to say we are ready to collect input. 34: ** 35: ** Returns: 36: ** none. 37: ** 38: ** Side Effects: 39: ** Temp file is created and filled. 40: ** The from person may be set. 41: */ 42: 43: collect(sayok) 44: bool sayok; 45: { 46: register FILE *tf; 47: char buf[MAXFIELD+2]; 48: register char *p; 49: extern char *hvalue(); 50: 51: /* 52: ** Create the temp file name and create the file. 53: */ 54: 55: CurEnv->e_df = newstr(queuename(CurEnv, 'd')); 56: if ((tf = dfopen(CurEnv->e_df, "w")) == NULL) 57: { 58: syserr("Cannot create %s", CurEnv->e_df); 59: NoReturn = TRUE; 60: finis(); 61: } 62: (void) chmod(CurEnv->e_df, FileMode); 63: 64: /* 65: ** Tell ARPANET to go ahead. 66: */ 67: 68: if (sayok) 69: message("354", "Enter mail, end with \".\" on a line by itself"); 70: 71: /* 72: ** Try to read a UNIX-style From line 73: */ 74: 75: (void) sfgets(buf, sizeof buf, InChannel); 76: fixcrlf(buf, FALSE); 77: # ifndef NOTUNIX 78: if (!SaveFrom && strncmp(buf, "From ", 5) == 0) 79: { 80: eatfrom(buf); 81: (void) sfgets(buf, sizeof buf, InChannel); 82: fixcrlf(buf, FALSE); 83: } 84: # endif NOTUNIX 85: 86: /* 87: ** Copy InChannel to temp file & do message editing. 88: ** To keep certain mailers from getting confused, 89: ** and to keep the output clean, lines that look 90: ** like UNIX "From" lines are deleted in the header. 91: */ 92: 93: do 94: { 95: int c; 96: extern bool isheader(); 97: 98: /* drop out on error */ 99: if (ferror(InChannel)) 100: break; 101: 102: /* if the line is too long, throw the rest away */ 103: if (index(buf, '\n') == NULL) 104: { 105: while ((c = getc(InChannel)) != '\n' && c != EOF) 106: continue; 107: /* give an error? */ 108: } 109: 110: fixcrlf(buf, TRUE); 111: 112: /* see if the header is over */ 113: if (!isheader(buf)) 114: break; 115: 116: /* get the rest of this field */ 117: while ((c = getc(InChannel)) == ' ' || c == '\t') 118: { 119: p = &buf[strlen(buf)]; 120: *p++ = '\n'; 121: *p++ = c; 122: if (sfgets(p, MAXFIELD - (p - buf), InChannel) == NULL) 123: break; 124: fixcrlf(p, TRUE); 125: } 126: if (!feof(InChannel) && !ferror(InChannel)) 127: (void) ungetc(c, InChannel); 128: 129: CurEnv->e_msgsize += strlen(buf); 130: 131: /* 132: ** Snarf header away. 133: */ 134: 135: if (bitset(H_EOH, chompheader(buf, FALSE))) 136: break; 137: } while (sfgets(buf, MAXFIELD, InChannel) != NULL); 138: 139: # ifdef DEBUG 140: if (tTd(30, 1)) 141: printf("EOH\n"); 142: # endif DEBUG 143: 144: /* throw away a blank line */ 145: if (buf[0] == '\0') 146: (void) sfgets(buf, MAXFIELD, InChannel); 147: 148: /* 149: ** Collect the body of the message. 150: */ 151: 152: do 153: { 154: register char *bp = buf; 155: 156: fixcrlf(buf, TRUE); 157: 158: /* check for end-of-message */ 159: if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) 160: break; 161: 162: /* check for transparent dot */ 163: if (OpMode == MD_SMTP && !IgnrDot && bp[0] == '.' && bp[1] == '.') 164: bp++; 165: 166: /* 167: ** Figure message length, output the line to the temp 168: ** file, and insert a newline if missing. 169: */ 170: 171: CurEnv->e_msgsize += strlen(bp) + 1; 172: fputs(bp, tf); 173: fputs("\n", tf); 174: if (ferror(tf)) 175: tferror(tf); 176: } while (sfgets(buf, MAXFIELD, InChannel) != NULL); 177: if (fflush(tf) != 0) 178: tferror(tf); 179: (void) fclose(tf); 180: 181: /* An EOF when running SMTP is an error */ 182: if ((feof(InChannel) || ferror(InChannel)) && OpMode == MD_SMTP) 183: { 184: syserr("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr); 185: 186: /* don't return an error indication */ 187: CurEnv->e_to = NULL; 188: CurEnv->e_flags &= ~EF_FATALERRS; 189: 190: /* and don't try to deliver the partial message either */ 191: finis(); 192: } 193: 194: /* 195: ** Find out some information from the headers. 196: ** Examples are who is the from person & the date. 197: */ 198: 199: eatheader(CurEnv); 200: 201: /* 202: ** Add an Apparently-To: line if we have no recipient lines. 203: */ 204: 205: if (hvalue("to") == NULL && hvalue("cc") == NULL && 206: hvalue("bcc") == NULL && hvalue("apparently-to") == NULL) 207: { 208: register ADDRESS *q; 209: 210: /* create an Apparently-To: field */ 211: /* that or reject the message.... */ 212: for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) 213: { 214: if (q->q_alias != NULL) 215: continue; 216: # ifdef DEBUG 217: if (tTd(30, 3)) 218: printf("Adding Apparently-To: %s\n", q->q_paddr); 219: # endif DEBUG 220: addheader("apparently-to", q->q_paddr, CurEnv); 221: } 222: } 223: 224: if ((CurEnv->e_dfp = fopen(CurEnv->e_df, "r")) == NULL) 225: syserr("Cannot reopen %s", CurEnv->e_df); 226: } 227: /* 228: ** TFERROR -- signal error on writing the temporary file. 229: ** 230: ** Parameters: 231: ** tf -- the file pointer for the temporary file. 232: ** 233: ** Returns: 234: ** none. 235: ** 236: ** Side Effects: 237: ** Gives an error message. 238: ** Arranges for following output to go elsewhere. 239: */ 240: 241: tferror(tf) 242: FILE *tf; 243: { 244: if (errno == ENOSPC) 245: { 246: (void) freopen(CurEnv->e_df, "w", tf); 247: fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); 248: usrerr("452 Out of disk space for temp file"); 249: } 250: else 251: syserr("collect: Cannot write %s", CurEnv->e_df); 252: (void) freopen("/dev/null", "w", tf); 253: } 254: /* 255: ** EATFROM -- chew up a UNIX style from line and process 256: ** 257: ** This does indeed make some assumptions about the format 258: ** of UNIX messages. 259: ** 260: ** Parameters: 261: ** fm -- the from line. 262: ** 263: ** Returns: 264: ** none. 265: ** 266: ** Side Effects: 267: ** extracts what information it can from the header, 268: ** such as the date. 269: */ 270: 271: # ifndef NOTUNIX 272: 273: char *DowList[] = 274: { 275: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 276: }; 277: 278: char *MonthList[] = 279: { 280: "Jan", "Feb", "Mar", "Apr", "May", "Jun", 281: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 282: NULL 283: }; 284: 285: eatfrom(fm) 286: char *fm; 287: { 288: register char *p; 289: register char **dt; 290: 291: # ifdef DEBUG 292: if (tTd(30, 2)) 293: printf("eatfrom(%s)\n", fm); 294: # endif DEBUG 295: 296: /* find the date part */ 297: p = fm; 298: while (*p != '\0') 299: { 300: /* skip a word */ 301: while (*p != '\0' && *p != ' ') 302: p++; 303: while (*p == ' ') 304: p++; 305: if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') 306: continue; 307: 308: /* we have a possible date */ 309: for (dt = DowList; *dt != NULL; dt++) 310: if (strncmp(*dt, p, 3) == 0) 311: break; 312: if (*dt == NULL) 313: continue; 314: 315: for (dt = MonthList; *dt != NULL; dt++) 316: if (strncmp(*dt, &p[4], 3) == 0) 317: break; 318: if (*dt != NULL) 319: break; 320: } 321: 322: if (*p != NULL) 323: { 324: char *q; 325: extern char *arpadate(); 326: 327: /* we have found a date */ 328: q = xalloc(25); 329: (void) strncpy(q, p, 25); 330: q[24] = '\0'; 331: define('d', q, CurEnv); 332: q = arpadate(q); 333: define('a', newstr(q), CurEnv); 334: } 335: } 336: 337: # endif NOTUNIX