1 /* 2 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14 #ifndef lint 15 static char id[] = "@(#)$Id: collect.c,v 8.136.4.6 2000/09/21 21:52:16 ca Exp $"; 16 #endif /* ! lint */ 17 18 #include <sendmail.h> 19 20 21 static void collecttimeout __P((time_t)); 22 static void dferror __P((FILE *volatile, char *, ENVELOPE *)); 23 static void eatfrom __P((char *volatile, ENVELOPE *)); 24 25 /* 26 ** COLLECT -- read & parse message header & make temp file. 27 ** 28 ** Creates a temporary file name and copies the standard 29 ** input to that file. Leading UNIX-style "From" lines are 30 ** stripped off (after important information is extracted). 31 ** 32 ** Parameters: 33 ** fp -- file to read. 34 ** smtpmode -- if set, we are running SMTP: give an RFC821 35 ** style message to say we are ready to collect 36 ** input, and never ignore a single dot to mean 37 ** end of message. 38 ** hdrp -- the location to stash the header. 39 ** e -- the current envelope. 40 ** 41 ** Returns: 42 ** none. 43 ** 44 ** Side Effects: 45 ** Temp file is created and filled. 46 ** The from person may be set. 47 */ 48 49 static jmp_buf CtxCollectTimeout; 50 static bool CollectProgress; 51 static EVENT *CollectTimeout; 52 53 /* values for input state machine */ 54 #define IS_NORM 0 /* middle of line */ 55 #define IS_BOL 1 /* beginning of line */ 56 #define IS_DOT 2 /* read a dot at beginning of line */ 57 #define IS_DOTCR 3 /* read ".\r" at beginning of line */ 58 #define IS_CR 4 /* read a carriage return */ 59 60 /* values for message state machine */ 61 #define MS_UFROM 0 /* reading Unix from line */ 62 #define MS_HEADER 1 /* reading message header */ 63 #define MS_BODY 2 /* reading message body */ 64 #define MS_DISCARD 3 /* discarding rest of message */ 65 66 void 67 collect(fp, smtpmode, hdrp, e) 68 FILE *fp; 69 bool smtpmode; 70 HDR **hdrp; 71 register ENVELOPE *e; 72 { 73 register FILE *volatile df; 74 volatile bool ignrdot = smtpmode ? FALSE : IgnrDot; 75 volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0; 76 register char *volatile bp; 77 volatile int c = EOF; 78 volatile bool inputerr = FALSE; 79 bool headeronly; 80 char *volatile buf; 81 volatile int buflen; 82 volatile int istate; 83 volatile int mstate; 84 volatile int hdrslen = 0; 85 volatile int numhdrs = 0; 86 volatile int dfd; 87 volatile int afd; 88 volatile int rstat = EX_OK; 89 u_char *volatile pbp; 90 u_char peekbuf[8]; 91 char hsize[16]; 92 char hnum[16]; 93 char dfname[MAXPATHLEN]; 94 char bufbuf[MAXLINE]; 95 96 headeronly = hdrp != NULL; 97 98 /* 99 ** Create the temp file name and create the file. 100 */ 101 102 if (!headeronly) 103 { 104 struct stat stbuf; 105 106 (void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname); 107 #if _FFR_QUEUE_FILE_MODE 108 { 109 MODE_T oldumask; 110 111 if (bitset(S_IWGRP, QueueFileMode)) 112 oldumask = umask(002); 113 df = bfopen(dfname, QueueFileMode, DataFileBufferSize, 114 SFF_OPENASROOT); 115 if (bitset(S_IWGRP, QueueFileMode)) 116 (void) umask(oldumask); 117 } 118 #else /* _FFR_QUEUE_FILE_MODE */ 119 df = bfopen(dfname, FileMode, DataFileBufferSize, 120 SFF_OPENASROOT); 121 #endif /* _FFR_QUEUE_FILE_MODE */ 122 if (df == NULL) 123 { 124 syserr("Cannot create %s", dfname); 125 e->e_flags |= EF_NO_BODY_RETN; 126 finis(TRUE, ExitStat); 127 /* NOTREACHED */ 128 } 129 dfd = fileno(df); 130 if (dfd < 0 || fstat(dfd, &stbuf) < 0) 131 e->e_dfino = -1; 132 else 133 { 134 e->e_dfdev = stbuf.st_dev; 135 e->e_dfino = stbuf.st_ino; 136 } 137 HasEightBits = FALSE; 138 e->e_msgsize = 0; 139 e->e_flags |= EF_HAS_DF; 140 } 141 142 /* 143 ** Tell ARPANET to go ahead. 144 */ 145 146 if (smtpmode) 147 message("354 Enter mail, end with \".\" on a line by itself"); 148 149 if (tTd(30, 2)) 150 dprintf("collect\n"); 151 152 /* 153 ** Read the message. 154 ** 155 ** This is done using two interleaved state machines. 156 ** The input state machine is looking for things like 157 ** hidden dots; the message state machine is handling 158 ** the larger picture (e.g., header versus body). 159 */ 160 161 buf = bp = bufbuf; 162 buflen = sizeof bufbuf; 163 pbp = peekbuf; 164 istate = IS_BOL; 165 mstate = SaveFrom ? MS_HEADER : MS_UFROM; 166 CollectProgress = FALSE; 167 168 if (dbto != 0) 169 { 170 /* handle possible input timeout */ 171 if (setjmp(CtxCollectTimeout) != 0) 172 { 173 if (LogLevel > 2) 174 sm_syslog(LOG_NOTICE, e->e_id, 175 "timeout waiting for input from %s during message collect", 176 CurHostName ? CurHostName : "<local machine>"); 177 errno = 0; 178 usrerr("451 4.4.1 timeout waiting for input during message collect"); 179 goto readerr; 180 } 181 CollectTimeout = setevent(dbto, collecttimeout, dbto); 182 } 183 184 for (;;) 185 { 186 if (tTd(30, 35)) 187 dprintf("top, istate=%d, mstate=%d\n", istate, mstate); 188 for (;;) 189 { 190 if (pbp > peekbuf) 191 c = *--pbp; 192 else 193 { 194 while (!feof(fp) && !ferror(fp)) 195 { 196 errno = 0; 197 c = getc(fp); 198 199 if (c == EOF && errno == EINTR) 200 { 201 /* Interrupted, retry */ 202 clearerr(fp); 203 continue; 204 } 205 break; 206 } 207 CollectProgress = TRUE; 208 if (TrafficLogFile != NULL && !headeronly) 209 { 210 if (istate == IS_BOL) 211 (void) fprintf(TrafficLogFile, "%05d <<< ", 212 (int) getpid()); 213 if (c == EOF) 214 (void) fprintf(TrafficLogFile, "[EOF]\n"); 215 else 216 (void) putc(c, TrafficLogFile); 217 } 218 if (c == EOF) 219 goto readerr; 220 if (SevenBitInput) 221 c &= 0x7f; 222 else 223 HasEightBits |= bitset(0x80, c); 224 } 225 if (tTd(30, 94)) 226 dprintf("istate=%d, c=%c (0x%x)\n", 227 istate, (char) c, c); 228 switch (istate) 229 { 230 case IS_BOL: 231 if (c == '.') 232 { 233 istate = IS_DOT; 234 continue; 235 } 236 break; 237 238 case IS_DOT: 239 if (c == '\n' && !ignrdot && 240 !bitset(EF_NL_NOT_EOL, e->e_flags)) 241 goto readerr; 242 else if (c == '\r' && 243 !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 244 { 245 istate = IS_DOTCR; 246 continue; 247 } 248 else if (c != '.' || 249 (OpMode != MD_SMTP && 250 OpMode != MD_DAEMON && 251 OpMode != MD_ARPAFTP)) 252 { 253 *pbp++ = c; 254 c = '.'; 255 } 256 break; 257 258 case IS_DOTCR: 259 if (c == '\n' && !ignrdot) 260 goto readerr; 261 else 262 { 263 /* push back the ".\rx" */ 264 *pbp++ = c; 265 *pbp++ = '\r'; 266 c = '.'; 267 } 268 break; 269 270 case IS_CR: 271 if (c == '\n') 272 istate = IS_BOL; 273 else 274 { 275 (void) ungetc(c, fp); 276 c = '\r'; 277 istate = IS_NORM; 278 } 279 goto bufferchar; 280 } 281 282 if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags)) 283 { 284 istate = IS_CR; 285 continue; 286 } 287 else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags)) 288 istate = IS_BOL; 289 else 290 istate = IS_NORM; 291 292 bufferchar: 293 if (!headeronly) 294 { 295 /* no overflow? */ 296 if (e->e_msgsize >= 0) 297 { 298 e->e_msgsize++; 299 if (MaxMessageSize > 0 && 300 !bitset(EF_TOOBIG, e->e_flags) && 301 e->e_msgsize > MaxMessageSize) 302 e->e_flags |= EF_TOOBIG; 303 } 304 } 305 switch (mstate) 306 { 307 case MS_BODY: 308 /* just put the character out */ 309 if (!bitset(EF_TOOBIG, e->e_flags)) 310 (void) putc(c, df); 311 312 /* FALLTHROUGH */ 313 314 case MS_DISCARD: 315 continue; 316 } 317 318 /* header -- buffer up */ 319 if (bp >= &buf[buflen - 2]) 320 { 321 char *obuf; 322 323 if (mstate != MS_HEADER) 324 break; 325 326 /* out of space for header */ 327 obuf = buf; 328 if (buflen < MEMCHUNKSIZE) 329 buflen *= 2; 330 else 331 buflen += MEMCHUNKSIZE; 332 buf = xalloc(buflen); 333 memmove(buf, obuf, bp - obuf); 334 bp = &buf[bp - obuf]; 335 if (obuf != bufbuf) 336 free(obuf); 337 } 338 if (c >= 0200 && c <= 0237) 339 { 340 #if 0 /* causes complaints -- figure out something for 8.11 */ 341 usrerr("Illegal character 0x%x in header", c); 342 #else /* 0 */ 343 /* EMPTY */ 344 #endif /* 0 */ 345 } 346 else if (c != '\0') 347 { 348 *bp++ = c; 349 if (MaxHeadersLength > 0 && 350 ++hdrslen > MaxHeadersLength) 351 { 352 sm_syslog(LOG_NOTICE, e->e_id, 353 "headers too large (%d max) from %s during message collect", 354 MaxHeadersLength, 355 CurHostName != NULL ? CurHostName : "localhost"); 356 errno = 0; 357 e->e_flags |= EF_CLRQUEUE; 358 e->e_status = "5.6.0"; 359 usrerrenh(e->e_status, 360 "552 Headers too large (%d max)", 361 MaxHeadersLength); 362 mstate = MS_DISCARD; 363 } 364 } 365 if (istate == IS_BOL) 366 break; 367 } 368 *bp = '\0'; 369 370 nextstate: 371 if (tTd(30, 35)) 372 dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 373 istate, mstate, buf); 374 switch (mstate) 375 { 376 case MS_UFROM: 377 mstate = MS_HEADER; 378 #ifndef NOTUNIX 379 if (strncmp(buf, "From ", 5) == 0) 380 { 381 bp = buf; 382 eatfrom(buf, e); 383 continue; 384 } 385 #endif /* ! NOTUNIX */ 386 /* FALLTHROUGH */ 387 388 case MS_HEADER: 389 if (!isheader(buf)) 390 { 391 mstate = MS_BODY; 392 goto nextstate; 393 } 394 395 /* check for possible continuation line */ 396 do 397 { 398 clearerr(fp); 399 errno = 0; 400 c = getc(fp); 401 } while (c == EOF && errno == EINTR); 402 if (c != EOF) 403 (void) ungetc(c, fp); 404 if (c == ' ' || c == '\t') 405 { 406 /* yep -- defer this */ 407 continue; 408 } 409 410 /* trim off trailing CRLF or NL */ 411 if (*--bp != '\n' || *--bp != '\r') 412 bp++; 413 *bp = '\0'; 414 415 if (bitset(H_EOH, chompheader(buf, 416 CHHDR_CHECK | CHHDR_USER, 417 hdrp, e))) 418 { 419 mstate = MS_BODY; 420 goto nextstate; 421 } 422 numhdrs++; 423 break; 424 425 case MS_BODY: 426 if (tTd(30, 1)) 427 dprintf("EOH\n"); 428 429 if (headeronly) 430 goto readerr; 431 432 /* call the end-of-header check ruleset */ 433 snprintf(hnum, sizeof hnum, "%d", numhdrs); 434 snprintf(hsize, sizeof hsize, "%d", hdrslen); 435 if (tTd(30, 10)) 436 dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 437 hnum, hsize); 438 rstat = rscheck("check_eoh", hnum, hsize, e, FALSE, 439 TRUE, 4); 440 441 bp = buf; 442 443 /* toss blank line */ 444 if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 445 bp[0] == '\r' && bp[1] == '\n') || 446 (!bitset(EF_NL_NOT_EOL, e->e_flags) && 447 bp[0] == '\n')) 448 { 449 break; 450 } 451 452 /* if not a blank separator, write it out */ 453 if (!bitset(EF_TOOBIG, e->e_flags)) 454 { 455 while (*bp != '\0') 456 (void) putc(*bp++, df); 457 } 458 break; 459 } 460 bp = buf; 461 } 462 463 readerr: 464 if ((feof(fp) && smtpmode) || ferror(fp)) 465 { 466 const char *errmsg = errstring(errno); 467 468 if (tTd(30, 1)) 469 dprintf("collect: premature EOM: %s\n", errmsg); 470 if (LogLevel >= 2) 471 sm_syslog(LOG_WARNING, e->e_id, 472 "collect: premature EOM: %s", errmsg); 473 inputerr = TRUE; 474 } 475 476 /* reset global timer */ 477 clrevent(CollectTimeout); 478 479 if (headeronly) 480 return; 481 482 if (df == NULL) 483 { 484 /* skip next few clauses */ 485 /* EMPTY */ 486 } 487 else if (fflush(df) != 0 || ferror(df)) 488 { 489 dferror(df, "fflush||ferror", e); 490 flush_errors(TRUE); 491 finis(TRUE, ExitStat); 492 /* NOTREACHED */ 493 } 494 else if (!SuperSafe) 495 { 496 /* skip next few clauses */ 497 /* EMPTY */ 498 } 499 else if ((afd = fileno(df)) >= 0 && fsync(afd) < 0) 500 { 501 dferror(df, "fsync", e); 502 flush_errors(TRUE); 503 finis(TRUE, ExitStat); 504 /* NOTREACHED */ 505 } 506 else if (bfcommit(df) < 0) 507 { 508 int save_errno = errno; 509 510 if (save_errno == EEXIST) 511 { 512 char *dfile; 513 struct stat st; 514 515 dfile = queuename(e, 'd'); 516 if (stat(dfile, &st) < 0) 517 st.st_size = -1; 518 errno = EEXIST; 519 syserr("collect: bfcommit(%s): already on disk, size = %ld", 520 dfile, (long) st.st_size); 521 dfd = fileno(df); 522 if (dfd >= 0) 523 dumpfd(dfd, TRUE, TRUE); 524 } 525 errno = save_errno; 526 dferror(df, "bfcommit", e); 527 flush_errors(TRUE); 528 finis(save_errno != EEXIST, ExitStat); 529 } 530 else if (bfclose(df) < 0) 531 { 532 dferror(df, "bfclose", e); 533 flush_errors(TRUE); 534 finis(TRUE, ExitStat); 535 /* NOTREACHED */ 536 } 537 else 538 { 539 /* everything is happily flushed to disk */ 540 df = NULL; 541 } 542 543 /* An EOF when running SMTP is an error */ 544 if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 545 { 546 char *host; 547 char *problem; 548 549 host = RealHostName; 550 if (host == NULL) 551 host = "localhost"; 552 553 if (feof(fp)) 554 problem = "unexpected close"; 555 else if (ferror(fp)) 556 problem = "I/O error"; 557 else 558 problem = "read timeout"; 559 if (LogLevel > 0 && feof(fp)) 560 sm_syslog(LOG_NOTICE, e->e_id, 561 "collect: %s on connection from %.100s, sender=%s: %s", 562 problem, host, 563 shortenstring(e->e_from.q_paddr, MAXSHORTSTR), 564 errstring(errno)); 565 if (feof(fp)) 566 usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 567 problem, host, 568 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 569 else 570 syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 571 problem, host, 572 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 573 574 /* don't return an error indication */ 575 e->e_to = NULL; 576 e->e_flags &= ~EF_FATALERRS; 577 e->e_flags |= EF_CLRQUEUE; 578 579 /* and don't try to deliver the partial message either */ 580 if (InChild) 581 ExitStat = EX_QUIT; 582 finis(TRUE, ExitStat); 583 /* NOTREACHED */ 584 } 585 586 /* 587 ** Find out some information from the headers. 588 ** Examples are who is the from person & the date. 589 */ 590 591 eatheader(e, TRUE); 592 593 if (GrabTo && e->e_sendqueue == NULL) 594 usrerr("No recipient addresses found in header"); 595 596 /* collect statistics */ 597 if (OpMode != MD_VERIFY) 598 markstats(e, (ADDRESS *) NULL, FALSE); 599 600 /* 601 ** If we have a Return-Receipt-To:, turn it into a DSN. 602 */ 603 604 if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 605 { 606 ADDRESS *q; 607 608 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 609 if (!bitset(QHASNOTIFY, q->q_flags)) 610 q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 611 } 612 613 /* 614 ** Add an Apparently-To: line if we have no recipient lines. 615 */ 616 617 if (hvalue("to", e->e_header) != NULL || 618 hvalue("cc", e->e_header) != NULL || 619 hvalue("apparently-to", e->e_header) != NULL) 620 { 621 /* have a valid recipient header -- delete Bcc: headers */ 622 e->e_flags |= EF_DELETE_BCC; 623 } 624 else if (hvalue("bcc", e->e_header) == NULL) 625 { 626 /* no valid recipient headers */ 627 register ADDRESS *q; 628 char *hdr = NULL; 629 630 /* create an Apparently-To: field */ 631 /* that or reject the message.... */ 632 switch (NoRecipientAction) 633 { 634 case NRA_ADD_APPARENTLY_TO: 635 hdr = "Apparently-To"; 636 break; 637 638 case NRA_ADD_TO: 639 hdr = "To"; 640 break; 641 642 case NRA_ADD_BCC: 643 addheader("Bcc", " ", 0, &e->e_header); 644 break; 645 646 case NRA_ADD_TO_UNDISCLOSED: 647 addheader("To", "undisclosed-recipients:;", 0, &e->e_header); 648 break; 649 } 650 651 if (hdr != NULL) 652 { 653 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 654 { 655 if (q->q_alias != NULL) 656 continue; 657 if (tTd(30, 3)) 658 dprintf("Adding %s: %s\n", 659 hdr, q->q_paddr); 660 addheader(hdr, q->q_paddr, 0, &e->e_header); 661 } 662 } 663 } 664 665 /* check for message too large */ 666 if (bitset(EF_TOOBIG, e->e_flags)) 667 { 668 e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 669 e->e_status = "5.2.3"; 670 usrerrenh(e->e_status, 671 "552 Message exceeds maximum fixed size (%ld)", 672 MaxMessageSize); 673 if (LogLevel > 6) 674 sm_syslog(LOG_NOTICE, e->e_id, 675 "message size (%ld) exceeds maximum (%ld)", 676 e->e_msgsize, MaxMessageSize); 677 } 678 679 /* check for illegal 8-bit data */ 680 if (HasEightBits) 681 { 682 e->e_flags |= EF_HAS8BIT; 683 if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 684 !bitset(EF_IS_MIME, e->e_flags)) 685 { 686 e->e_status = "5.6.1"; 687 usrerrenh(e->e_status, "554 Eight bit data not allowed"); 688 } 689 } 690 else 691 { 692 /* if it claimed to be 8 bits, well, it lied.... */ 693 if (e->e_bodytype != NULL && 694 strcasecmp(e->e_bodytype, "8BITMIME") == 0) 695 e->e_bodytype = "7BIT"; 696 } 697 698 if (SuperSafe) 699 { 700 if ((e->e_dfp = fopen(dfname, "r")) == NULL) 701 { 702 /* we haven't acked receipt yet, so just chuck this */ 703 syserr("Cannot reopen %s", dfname); 704 finis(TRUE, ExitStat); 705 /* NOTREACHED */ 706 } 707 } 708 else 709 e->e_dfp = df; 710 if (e->e_dfp == NULL) 711 syserr("!collect: no e_dfp"); 712 } 713 714 715 static void 716 collecttimeout(timeout) 717 time_t timeout; 718 { 719 /* if no progress was made, die now */ 720 if (!CollectProgress) 721 longjmp(CtxCollectTimeout, 1); 722 723 /* otherwise reset the timeout */ 724 CollectTimeout = setevent(timeout, collecttimeout, timeout); 725 CollectProgress = FALSE; 726 } 727 /* 728 ** DFERROR -- signal error on writing the data file. 729 ** 730 ** Parameters: 731 ** df -- the file pointer for the data file. 732 ** msg -- detailed message. 733 ** e -- the current envelope. 734 ** 735 ** Returns: 736 ** none. 737 ** 738 ** Side Effects: 739 ** Gives an error message. 740 ** Arranges for following output to go elsewhere. 741 */ 742 743 static void 744 dferror(df, msg, e) 745 FILE *volatile df; 746 char *msg; 747 register ENVELOPE *e; 748 { 749 char *dfname; 750 751 dfname = queuename(e, 'd'); 752 setstat(EX_IOERR); 753 if (errno == ENOSPC) 754 { 755 #if STAT64 > 0 756 struct stat64 st; 757 #else /* STAT64 > 0 */ 758 struct stat st; 759 #endif /* STAT64 > 0 */ 760 long avail; 761 long bsize; 762 763 e->e_flags |= EF_NO_BODY_RETN; 764 765 if ( 766 #if STAT64 > 0 767 fstat64(fileno(df), &st) 768 #else /* STAT64 > 0 */ 769 fstat(fileno(df), &st) 770 #endif /* STAT64 > 0 */ 771 < 0) 772 st.st_size = 0; 773 (void) freopen(dfname, "w", df); 774 if (st.st_size <= 0) 775 fprintf(df, "\n*** Mail could not be accepted"); 776 /*CONSTCOND*/ 777 else if (sizeof st.st_size > sizeof (long)) 778 fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n", 779 quad_to_string(st.st_size)); 780 else 781 fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n", 782 (unsigned long) st.st_size); 783 fprintf(df, "*** at %s due to lack of disk space for temp file.\n", 784 MyHostName); 785 avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize); 786 if (avail > 0) 787 { 788 if (bsize > 1024) 789 avail *= bsize / 1024; 790 else if (bsize < 1024) 791 avail /= 1024 / bsize; 792 fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n", 793 avail); 794 } 795 e->e_status = "4.3.1"; 796 usrerrenh(e->e_status, "452 Out of disk space for temp file"); 797 } 798 else 799 syserr("collect: Cannot write %s (%s, uid=%d)", 800 dfname, msg, geteuid()); 801 if (freopen("/dev/null", "w", df) == NULL) 802 sm_syslog(LOG_ERR, e->e_id, 803 "dferror: freopen(\"/dev/null\") failed: %s", 804 errstring(errno)); 805 } 806 /* 807 ** EATFROM -- chew up a UNIX style from line and process 808 ** 809 ** This does indeed make some assumptions about the format 810 ** of UNIX messages. 811 ** 812 ** Parameters: 813 ** fm -- the from line. 814 ** 815 ** Returns: 816 ** none. 817 ** 818 ** Side Effects: 819 ** extracts what information it can from the header, 820 ** such as the date. 821 */ 822 823 #ifndef NOTUNIX 824 825 static char *DowList[] = 826 { 827 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 828 }; 829 830 static char *MonthList[] = 831 { 832 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 833 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 834 NULL 835 }; 836 837 static void 838 eatfrom(fm, e) 839 char *volatile fm; 840 register ENVELOPE *e; 841 { 842 register char *p; 843 register char **dt; 844 845 if (tTd(30, 2)) 846 dprintf("eatfrom(%s)\n", fm); 847 848 /* find the date part */ 849 p = fm; 850 while (*p != '\0') 851 { 852 /* skip a word */ 853 while (*p != '\0' && *p != ' ') 854 p++; 855 while (*p == ' ') 856 p++; 857 if (!(isascii(*p) && isupper(*p)) || 858 p[3] != ' ' || p[13] != ':' || p[16] != ':') 859 continue; 860 861 /* we have a possible date */ 862 for (dt = DowList; *dt != NULL; dt++) 863 if (strncmp(*dt, p, 3) == 0) 864 break; 865 if (*dt == NULL) 866 continue; 867 868 for (dt = MonthList; *dt != NULL; dt++) 869 if (strncmp(*dt, &p[4], 3) == 0) 870 break; 871 if (*dt != NULL) 872 break; 873 } 874 875 if (*p != '\0') 876 { 877 char *q; 878 879 /* we have found a date */ 880 q = xalloc(25); 881 (void) strlcpy(q, p, 25); 882 q = arpadate(q); 883 define('a', newstr(q), e); 884 } 885 } 886 #endif /* ! NOTUNIX */ 887