|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Eric P. Allman ! 3: * Copyright (c) 1988 Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms are permitted provided ! 7: * that: (1) source distributions retain this entire copyright notice and ! 8: * comment, and (2) distributions including binaries display the following ! 9: * acknowledgement: ``This product includes software developed by the ! 10: * University of California, Berkeley and its contributors'' in the ! 11: * documentation or other materials provided with the distribution and in ! 12: * all advertising materials mentioning features or use of this software. ! 13: * Neither the name of the University nor the names of its contributors may ! 14: * be used to endorse or promote products derived from this software without ! 15: * specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: */ ! 20: ! 21: #ifndef lint ! 22: static char sccsid[] = "@(#)collect.c 5.9 (Berkeley) 6/1/90"; ! 23: #endif /* not lint */ ! 24: ! 25: # include <errno.h> ! 26: # include "sendmail.h" ! 27: ! 28: /* ! 29: ** COLLECT -- read & parse message header & make temp file. ! 30: ** ! 31: ** Creates a temporary file name and copies the standard ! 32: ** input to that file. Leading UNIX-style "From" lines are ! 33: ** stripped off (after important information is extracted). ! 34: ** ! 35: ** Parameters: ! 36: ** sayok -- if set, give an ARPANET style message ! 37: ** to say we are ready to collect input. ! 38: ** ! 39: ** Returns: ! 40: ** none. ! 41: ** ! 42: ** Side Effects: ! 43: ** Temp file is created and filled. ! 44: ** The from person may be set. ! 45: */ ! 46: ! 47: collect(sayok) ! 48: bool sayok; ! 49: { ! 50: register FILE *tf; ! 51: char buf[MAXFIELD], buf2[MAXFIELD]; ! 52: register char *workbuf, *freebuf; ! 53: register int workbuflen; ! 54: extern char *hvalue(); ! 55: extern bool isheader(), flusheol(); ! 56: ! 57: /* ! 58: ** Create the temp file name and create the file. ! 59: */ ! 60: ! 61: CurEnv->e_df = newstr(queuename(CurEnv, 'd')); ! 62: if ((tf = dfopen(CurEnv->e_df, "w")) == NULL) ! 63: { ! 64: syserr("Cannot create %s", CurEnv->e_df); ! 65: NoReturn = TRUE; ! 66: finis(); ! 67: } ! 68: (void) chmod(CurEnv->e_df, FileMode); ! 69: ! 70: /* ! 71: ** Tell ARPANET to go ahead. ! 72: */ ! 73: ! 74: if (sayok) ! 75: message("354", "Enter mail, end with \".\" on a line by itself"); ! 76: ! 77: /* ! 78: ** Try to read a UNIX-style From line ! 79: */ ! 80: ! 81: if (sfgets(buf, MAXFIELD, InChannel) == NULL) ! 82: goto readerr; ! 83: fixcrlf(buf, FALSE); ! 84: # ifndef NOTUNIX ! 85: if (!SaveFrom && strncmp(buf, "From ", 5) == 0) ! 86: { ! 87: if (!flusheol(buf, InChannel)) ! 88: goto readerr; ! 89: eatfrom(buf); ! 90: if (sfgets(buf, MAXFIELD, InChannel) == NULL) ! 91: goto readerr; ! 92: fixcrlf(buf, FALSE); ! 93: } ! 94: # endif NOTUNIX ! 95: ! 96: /* ! 97: ** Copy InChannel to temp file & do message editing. ! 98: ** To keep certain mailers from getting confused, ! 99: ** and to keep the output clean, lines that look ! 100: ** like UNIX "From" lines are deleted in the header. ! 101: */ ! 102: ! 103: workbuf = buf; /* `workbuf' contains a header field */ ! 104: freebuf = buf2; /* `freebuf' can be used for read-ahead */ ! 105: for (;;) ! 106: { ! 107: /* first, see if the header is over */ ! 108: if (!isheader(workbuf)) ! 109: { ! 110: fixcrlf(workbuf, TRUE); ! 111: break; ! 112: } ! 113: ! 114: /* if the line is too long, throw the rest away */ ! 115: if (!flusheol(workbuf, InChannel)) ! 116: goto readerr; ! 117: ! 118: /* it's okay to toss '\n' now (flusheol() needed it) */ ! 119: fixcrlf(workbuf, TRUE); ! 120: ! 121: workbuflen = strlen(workbuf); ! 122: ! 123: /* get the rest of this field */ ! 124: for (;;) ! 125: { ! 126: if (sfgets(freebuf, MAXFIELD, InChannel) == NULL) ! 127: goto readerr; ! 128: ! 129: /* is this a continuation line? */ ! 130: if (*freebuf != ' ' && *freebuf != '\t') ! 131: break; ! 132: ! 133: if (!flusheol(freebuf, InChannel)) ! 134: goto readerr; ! 135: ! 136: /* yes; append line to `workbuf' if there's room */ ! 137: if (workbuflen < MAXFIELD-3) ! 138: { ! 139: register char *p = workbuf + workbuflen; ! 140: register char *q = freebuf; ! 141: ! 142: /* we have room for more of this field */ ! 143: fixcrlf(freebuf, TRUE); ! 144: *p++ = '\n'; workbuflen++; ! 145: while(*q != '\0' && workbuflen < MAXFIELD-1) ! 146: { ! 147: *p++ = *q++; ! 148: workbuflen++; ! 149: } ! 150: *p = '\0'; ! 151: } ! 152: } ! 153: ! 154: CurEnv->e_msgsize += workbuflen; ! 155: ! 156: /* ! 157: ** The working buffer now becomes the free buffer, since ! 158: ** the free buffer contains a new header field. ! 159: ** ! 160: ** This is premature, since we still havent called ! 161: ** chompheader() to process the field we just created ! 162: ** (so the call to chompheader() will use `freebuf'). ! 163: ** This convolution is necessary so that if we break out ! 164: ** of the loop due to H_EOH, `workbuf' will always be ! 165: ** the next unprocessed buffer. ! 166: */ ! 167: ! 168: { ! 169: register char *tmp = workbuf; ! 170: workbuf = freebuf; ! 171: freebuf = tmp; ! 172: } ! 173: ! 174: /* ! 175: ** Snarf header away. ! 176: */ ! 177: ! 178: if (bitset(H_EOH, chompheader(freebuf, FALSE))) ! 179: break; ! 180: } ! 181: ! 182: if (tTd(30, 1)) ! 183: printf("EOH\n"); ! 184: ! 185: if (*workbuf == '\0') ! 186: { ! 187: /* throw away a blank line */ ! 188: if (sfgets(buf, MAXFIELD, InChannel) == NULL) ! 189: goto readerr; ! 190: } ! 191: else if (workbuf == buf2) /* guarantee `buf' contains data */ ! 192: (void) strcpy(buf, buf2); ! 193: ! 194: /* ! 195: ** Collect the body of the message. ! 196: */ ! 197: ! 198: do ! 199: { ! 200: register char *bp = buf; ! 201: ! 202: fixcrlf(buf, TRUE); ! 203: ! 204: /* check for end-of-message */ ! 205: if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0')) ! 206: break; ! 207: ! 208: /* check for transparent dot */ ! 209: if (OpMode == MD_SMTP && !IgnrDot && bp[0] == '.' && bp[1] == '.') ! 210: bp++; ! 211: ! 212: /* ! 213: ** Figure message length, output the line to the temp ! 214: ** file, and insert a newline if missing. ! 215: */ ! 216: ! 217: CurEnv->e_msgsize += strlen(bp) + 1; ! 218: fputs(bp, tf); ! 219: fputs("\n", tf); ! 220: if (ferror(tf)) ! 221: tferror(tf); ! 222: } while (sfgets(buf, MAXFIELD, InChannel) != NULL); ! 223: ! 224: readerr: ! 225: if (fflush(tf) != 0) ! 226: tferror(tf); ! 227: (void) fclose(tf); ! 228: ! 229: /* An EOF when running SMTP is an error */ ! 230: if ((feof(InChannel) || ferror(InChannel)) && OpMode == MD_SMTP) ! 231: { ! 232: int usrerr(), syserr(); ! 233: # ifdef LOG ! 234: if (RealHostName != NULL && LogLevel > 0) ! 235: syslog(LOG_NOTICE, ! 236: "collect: unexpected close on connection from %s: %m\n", ! 237: CurEnv->e_from.q_paddr, RealHostName); ! 238: # endif ! 239: (feof(InChannel) ? usrerr: syserr) ! 240: ("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr); ! 241: ! 242: /* don't return an error indication */ ! 243: CurEnv->e_to = NULL; ! 244: CurEnv->e_flags &= ~EF_FATALERRS; ! 245: ! 246: /* and don't try to deliver the partial message either */ ! 247: finis(); ! 248: } ! 249: ! 250: /* ! 251: ** Find out some information from the headers. ! 252: ** Examples are who is the from person & the date. ! 253: */ ! 254: ! 255: eatheader(CurEnv); ! 256: ! 257: /* ! 258: ** Add an Apparently-To: line if we have no recipient lines. ! 259: */ ! 260: ! 261: if (hvalue("to") == NULL && hvalue("cc") == NULL && ! 262: hvalue("bcc") == NULL && hvalue("apparently-to") == NULL) ! 263: { ! 264: register ADDRESS *q; ! 265: ! 266: /* create an Apparently-To: field */ ! 267: /* that or reject the message.... */ ! 268: for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next) ! 269: { ! 270: if (q->q_alias != NULL) ! 271: continue; ! 272: if (tTd(30, 3)) ! 273: printf("Adding Apparently-To: %s\n", q->q_paddr); ! 274: addheader("apparently-to", q->q_paddr, CurEnv); ! 275: } ! 276: } ! 277: ! 278: if ((CurEnv->e_dfp = fopen(CurEnv->e_df, "r")) == NULL) ! 279: syserr("Cannot reopen %s", CurEnv->e_df); ! 280: } ! 281: /* ! 282: ** FLUSHEOL -- if not at EOL, throw away rest of input line. ! 283: ** ! 284: ** Parameters: ! 285: ** buf -- last line read in (checked for '\n'), ! 286: ** fp -- file to be read from. ! 287: ** ! 288: ** Returns: ! 289: ** FALSE on error from sfgets(), TRUE otherwise. ! 290: ** ! 291: ** Side Effects: ! 292: ** none. ! 293: */ ! 294: ! 295: bool ! 296: flusheol(buf, fp) ! 297: char *buf; ! 298: FILE *fp; ! 299: { ! 300: char junkbuf[MAXLINE], *sfgets(); ! 301: register char *p = buf; ! 302: ! 303: while (index(p, '\n') == NULL) { ! 304: if (sfgets(junkbuf,MAXLINE,fp) == NULL) ! 305: return(FALSE); ! 306: p = junkbuf; ! 307: } ! 308: ! 309: return(TRUE); ! 310: } ! 311: /* ! 312: ** TFERROR -- signal error on writing the temporary file. ! 313: ** ! 314: ** Parameters: ! 315: ** tf -- the file pointer for the temporary file. ! 316: ** ! 317: ** Returns: ! 318: ** none. ! 319: ** ! 320: ** Side Effects: ! 321: ** Gives an error message. ! 322: ** Arranges for following output to go elsewhere. ! 323: */ ! 324: ! 325: tferror(tf) ! 326: FILE *tf; ! 327: { ! 328: if (errno == ENOSPC) ! 329: { ! 330: (void) freopen(CurEnv->e_df, "w", tf); ! 331: fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf); ! 332: usrerr("452 Out of disk space for temp file"); ! 333: } ! 334: else ! 335: syserr("collect: Cannot write %s", CurEnv->e_df); ! 336: (void) freopen("/dev/null", "w", tf); ! 337: } ! 338: /* ! 339: ** EATFROM -- chew up a UNIX style from line and process ! 340: ** ! 341: ** This does indeed make some assumptions about the format ! 342: ** of UNIX messages. ! 343: ** ! 344: ** Parameters: ! 345: ** fm -- the from line. ! 346: ** ! 347: ** Returns: ! 348: ** none. ! 349: ** ! 350: ** Side Effects: ! 351: ** extracts what information it can from the header, ! 352: ** such as the date. ! 353: */ ! 354: ! 355: # ifndef NOTUNIX ! 356: ! 357: char *DowList[] = ! 358: { ! 359: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL ! 360: }; ! 361: ! 362: char *MonthList[] = ! 363: { ! 364: "Jan", "Feb", "Mar", "Apr", "May", "Jun", ! 365: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ! 366: NULL ! 367: }; ! 368: ! 369: eatfrom(fm) ! 370: char *fm; ! 371: { ! 372: register char *p; ! 373: register char **dt; ! 374: ! 375: if (tTd(30, 2)) ! 376: printf("eatfrom(%s)\n", fm); ! 377: ! 378: /* find the date part */ ! 379: p = fm; ! 380: while (*p != '\0') ! 381: { ! 382: /* skip a word */ ! 383: while (*p != '\0' && *p != ' ') ! 384: p++; ! 385: while (*p == ' ') ! 386: p++; ! 387: if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':') ! 388: continue; ! 389: ! 390: /* we have a possible date */ ! 391: for (dt = DowList; *dt != NULL; dt++) ! 392: if (strncmp(*dt, p, 3) == 0) ! 393: break; ! 394: if (*dt == NULL) ! 395: continue; ! 396: ! 397: for (dt = MonthList; *dt != NULL; dt++) ! 398: if (strncmp(*dt, &p[4], 3) == 0) ! 399: break; ! 400: if (*dt != NULL) ! 401: break; ! 402: } ! 403: ! 404: if (*p != NULL) ! 405: { ! 406: char *q; ! 407: extern char *arpadate(); ! 408: ! 409: /* we have found a date */ ! 410: q = xalloc(25); ! 411: (void) strncpy(q, p, 25); ! 412: q[24] = '\0'; ! 413: define('d', q, CurEnv); ! 414: q = arpadate(q); ! 415: define('a', newstr(q), CurEnv); ! 416: } ! 417: } ! 418: ! 419: # endif NOTUNIX
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.