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