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.22 2001/06/07 21:01:02 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 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 (!headeronly && 356 MaxHeadersLength > 0 && 357 hdrslen > MaxHeadersLength) 358 { 359 sm_syslog(LOG_NOTICE, e->e_id, 360 "headers too large (%d max) from %s during message collect", 361 MaxHeadersLength, 362 CurHostName != NULL ? CurHostName : "localhost"); 363 errno = 0; 364 e->e_flags |= EF_CLRQUEUE; 365 e->e_status = "5.6.0"; 366 usrerrenh(e->e_status, 367 "552 Headers too large (%d max)", 368 MaxHeadersLength); 369 mstate = MS_DISCARD; 370 } 371 } 372 if (istate == IS_BOL) 373 break; 374 } 375 *bp = '\0'; 376 377 nextstate: 378 if (tTd(30, 35)) 379 dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n", 380 istate, mstate, buf); 381 switch (mstate) 382 { 383 case MS_UFROM: 384 mstate = MS_HEADER; 385 #ifndef NOTUNIX 386 if (strncmp(buf, "From ", 5) == 0) 387 { 388 bp = buf; 389 eatfrom(buf, e); 390 continue; 391 } 392 #endif /* ! NOTUNIX */ 393 /* FALLTHROUGH */ 394 395 case MS_HEADER: 396 if (!isheader(buf)) 397 { 398 mstate = MS_BODY; 399 goto nextstate; 400 } 401 402 /* check for possible continuation line */ 403 do 404 { 405 clearerr(fp); 406 errno = 0; 407 c = getc(fp); 408 } while (c == EOF && errno == EINTR); 409 if (c != EOF) 410 (void) ungetc(c, fp); 411 if (c == ' ' || c == '\t') 412 { 413 /* yep -- defer this */ 414 continue; 415 } 416 417 /* trim off trailing CRLF or NL */ 418 if (*--bp != '\n' || *--bp != '\r') 419 bp++; 420 *bp = '\0'; 421 422 if (bitset(H_EOH, chompheader(buf, 423 CHHDR_CHECK | CHHDR_USER, 424 hdrp, e))) 425 { 426 mstate = MS_BODY; 427 goto nextstate; 428 } 429 numhdrs++; 430 break; 431 432 case MS_BODY: 433 if (tTd(30, 1)) 434 dprintf("EOH\n"); 435 436 if (headeronly) 437 goto readerr; 438 439 /* call the end-of-header check ruleset */ 440 snprintf(hnum, sizeof hnum, "%d", numhdrs); 441 snprintf(hsize, sizeof hsize, "%d", hdrslen); 442 if (tTd(30, 10)) 443 dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n", 444 hnum, hsize); 445 rstat = rscheck("check_eoh", hnum, hsize, e, FALSE, 446 TRUE, 4, NULL); 447 448 bp = buf; 449 450 /* toss blank line */ 451 if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) && 452 bp[0] == '\r' && bp[1] == '\n') || 453 (!bitset(EF_NL_NOT_EOL, e->e_flags) && 454 bp[0] == '\n')) 455 { 456 break; 457 } 458 459 /* if not a blank separator, write it out */ 460 if (!bitset(EF_TOOBIG, e->e_flags)) 461 { 462 while (*bp != '\0') 463 (void) putc(*bp++, df); 464 } 465 break; 466 } 467 bp = buf; 468 } 469 470 readerr: 471 if ((feof(fp) && smtpmode) || ferror(fp)) 472 { 473 const char *errmsg = errstring(errno); 474 475 if (tTd(30, 1)) 476 dprintf("collect: premature EOM: %s\n", errmsg); 477 if (LogLevel >= 2) 478 sm_syslog(LOG_WARNING, e->e_id, 479 "collect: premature EOM: %s", errmsg); 480 inputerr = TRUE; 481 } 482 483 /* reset global timer */ 484 if (CollectTimeout != NULL) 485 clrevent(CollectTimeout); 486 487 if (headeronly) 488 return; 489 490 if (df == NULL) 491 { 492 /* skip next few clauses */ 493 /* EMPTY */ 494 } 495 else if (fflush(df) != 0 || ferror(df)) 496 { 497 dferror(df, "fflush||ferror", e); 498 flush_errors(TRUE); 499 finis(TRUE, ExitStat); 500 /* NOTREACHED */ 501 } 502 else if (!SuperSafe) 503 { 504 /* skip next few clauses */ 505 /* EMPTY */ 506 } 507 else if (bfcommit(df) < 0) 508 { 509 int save_errno = errno; 510 511 if (save_errno == EEXIST) 512 { 513 char *dfile; 514 struct stat st; 515 516 dfile = queuename(e, 'd'); 517 if (stat(dfile, &st) < 0) 518 st.st_size = -1; 519 errno = EEXIST; 520 syserr("collect: bfcommit(%s): already on disk, size = %ld", 521 dfile, (long) st.st_size); 522 dfd = fileno(df); 523 if (dfd >= 0) 524 dumpfd(dfd, TRUE, TRUE); 525 } 526 errno = save_errno; 527 dferror(df, "bfcommit", e); 528 flush_errors(TRUE); 529 finis(save_errno != EEXIST, ExitStat); 530 } 531 else if (bffsync(df) < 0) 532 { 533 dferror(df, "bffsync", e); 534 flush_errors(TRUE); 535 finis(TRUE, ExitStat); 536 /* NOTREACHED */ 537 } 538 else if (bfclose(df) < 0) 539 { 540 dferror(df, "bfclose", e); 541 flush_errors(TRUE); 542 finis(TRUE, ExitStat); 543 /* NOTREACHED */ 544 } 545 else 546 { 547 /* everything is happily flushed to disk */ 548 df = NULL; 549 } 550 551 /* An EOF when running SMTP is an error */ 552 if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 553 { 554 char *host; 555 char *problem; 556 557 host = RealHostName; 558 if (host == NULL) 559 host = "localhost"; 560 561 if (feof(fp)) 562 problem = "unexpected close"; 563 else if (ferror(fp)) 564 problem = "I/O error"; 565 else 566 problem = "read timeout"; 567 if (LogLevel > 0 && feof(fp)) 568 sm_syslog(LOG_NOTICE, e->e_id, 569 "collect: %s on connection from %.100s, sender=%s: %s", 570 problem, host, 571 shortenstring(e->e_from.q_paddr, MAXSHORTSTR), 572 errstring(errno)); 573 if (feof(fp)) 574 usrerr("451 4.4.1 collect: %s on connection from %s, from=%s", 575 problem, host, 576 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 577 else 578 syserr("451 4.4.1 collect: %s on connection from %s, from=%s", 579 problem, host, 580 shortenstring(e->e_from.q_paddr, MAXSHORTSTR)); 581 582 /* don't return an error indication */ 583 e->e_to = NULL; 584 e->e_flags &= ~EF_FATALERRS; 585 e->e_flags |= EF_CLRQUEUE; 586 587 /* and don't try to deliver the partial message either */ 588 if (InChild) 589 ExitStat = EX_QUIT; 590 finis(TRUE, ExitStat); 591 /* NOTREACHED */ 592 } 593 594 /* 595 ** Find out some information from the headers. 596 ** Examples are who is the from person & the date. 597 */ 598 599 eatheader(e, TRUE); 600 601 if (GrabTo && e->e_sendqueue == NULL) 602 usrerr("No recipient addresses found in header"); 603 604 /* collect statistics */ 605 if (OpMode != MD_VERIFY) 606 markstats(e, (ADDRESS *) NULL, FALSE); 607 608 /* 609 ** If we have a Return-Receipt-To:, turn it into a DSN. 610 */ 611 612 if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL) 613 { 614 ADDRESS *q; 615 616 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 617 if (!bitset(QHASNOTIFY, q->q_flags)) 618 q->q_flags |= QHASNOTIFY|QPINGONSUCCESS; 619 } 620 621 /* 622 ** Add an Apparently-To: line if we have no recipient lines. 623 */ 624 625 if (hvalue("to", e->e_header) != NULL || 626 hvalue("cc", e->e_header) != NULL || 627 hvalue("apparently-to", e->e_header) != NULL) 628 { 629 /* have a valid recipient header -- delete Bcc: headers */ 630 e->e_flags |= EF_DELETE_BCC; 631 } 632 else if (hvalue("bcc", e->e_header) == NULL) 633 { 634 /* no valid recipient headers */ 635 register ADDRESS *q; 636 char *hdr = NULL; 637 638 /* create an Apparently-To: field */ 639 /* that or reject the message.... */ 640 switch (NoRecipientAction) 641 { 642 case NRA_ADD_APPARENTLY_TO: 643 hdr = "Apparently-To"; 644 break; 645 646 case NRA_ADD_TO: 647 hdr = "To"; 648 break; 649 650 case NRA_ADD_BCC: 651 addheader("Bcc", " ", 0, &e->e_header); 652 break; 653 654 case NRA_ADD_TO_UNDISCLOSED: 655 addheader("To", "undisclosed-recipients:;", 0, &e->e_header); 656 break; 657 } 658 659 if (hdr != NULL) 660 { 661 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 662 { 663 if (q->q_alias != NULL) 664 continue; 665 if (tTd(30, 3)) 666 dprintf("Adding %s: %s\n", 667 hdr, q->q_paddr); 668 addheader(hdr, q->q_paddr, 0, &e->e_header); 669 } 670 } 671 } 672 673 /* check for message too large */ 674 if (bitset(EF_TOOBIG, e->e_flags)) 675 { 676 e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE; 677 e->e_status = "5.2.3"; 678 usrerrenh(e->e_status, 679 "552 Message exceeds maximum fixed size (%ld)", 680 MaxMessageSize); 681 if (LogLevel > 6) 682 sm_syslog(LOG_NOTICE, e->e_id, 683 "message size (%ld) exceeds maximum (%ld)", 684 e->e_msgsize, MaxMessageSize); 685 } 686 687 /* check for illegal 8-bit data */ 688 if (HasEightBits) 689 { 690 e->e_flags |= EF_HAS8BIT; 691 if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && 692 !bitset(EF_IS_MIME, e->e_flags)) 693 { 694 e->e_status = "5.6.1"; 695 usrerrenh(e->e_status, "554 Eight bit data not allowed"); 696 } 697 } 698 else 699 { 700 /* if it claimed to be 8 bits, well, it lied.... */ 701 if (e->e_bodytype != NULL && 702 strcasecmp(e->e_bodytype, "8BITMIME") == 0) 703 e->e_bodytype = "7BIT"; 704 } 705 706 if (SuperSafe) 707 { 708 if ((e->e_dfp = fopen(dfname, "r")) == NULL) 709 { 710 /* we haven't acked receipt yet, so just chuck this */ 711 syserr("Cannot reopen %s", dfname); 712 finis(TRUE, ExitStat); 713 /* NOTREACHED */ 714 } 715 } 716 else 717 e->e_dfp = df; 718 if (e->e_dfp == NULL) 719 syserr("!collect: no e_dfp"); 720 } 721 722 723 static void 724 collecttimeout(timeout) 725 time_t timeout; 726 { 727 int save_errno = errno; 728 729 /* 730 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 731 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 732 ** DOING. 733 */ 734 735 if (CollectProgress) 736 { 737 /* reset the timeout */ 738 CollectTimeout = sigsafe_setevent(timeout, collecttimeout, 739 timeout); 740 CollectProgress = FALSE; 741 } 742 else 743 { 744 /* event is done */ 745 CollectTimeout = NULL; 746 } 747 748 /* if no progress was made or problem resetting event, die now */ 749 if (CollectTimeout == NULL) 750 { 751 errno = ETIMEDOUT; 752 longjmp(CtxCollectTimeout, 1); 753 } 754 755 errno = save_errno; 756 } 757 /* 758 ** DFERROR -- signal error on writing the data file. 759 ** 760 ** Parameters: 761 ** df -- the file pointer for the data file. 762 ** msg -- detailed message. 763 ** e -- the current envelope. 764 ** 765 ** Returns: 766 ** none. 767 ** 768 ** Side Effects: 769 ** Gives an error message. 770 ** Arranges for following output to go elsewhere. 771 */ 772 773 static void 774 dferror(df, msg, e) 775 FILE *volatile df; 776 char *msg; 777 register ENVELOPE *e; 778 { 779 char *dfname; 780 781 dfname = queuename(e, 'd'); 782 setstat(EX_IOERR); 783 if (errno == ENOSPC) 784 { 785 #if STAT64 > 0 786 struct stat64 st; 787 #else /* STAT64 > 0 */ 788 struct stat st; 789 #endif /* STAT64 > 0 */ 790 long avail; 791 long bsize; 792 793 e->e_flags |= EF_NO_BODY_RETN; 794 795 if ( 796 #if STAT64 > 0 797 fstat64(fileno(df), &st) 798 #else /* STAT64 > 0 */ 799 fstat(fileno(df), &st) 800 #endif /* STAT64 > 0 */ 801 < 0) 802 st.st_size = 0; 803 (void) freopen(dfname, "w", df); 804 if (st.st_size <= 0) 805 fprintf(df, "\n*** Mail could not be accepted"); 806 /*CONSTCOND*/ 807 else if (sizeof st.st_size > sizeof (long)) 808 fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n", 809 quad_to_string(st.st_size)); 810 else 811 fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n", 812 (unsigned long) st.st_size); 813 fprintf(df, "*** at %s due to lack of disk space for temp file.\n", 814 MyHostName); 815 avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize); 816 if (avail > 0) 817 { 818 if (bsize > 1024) 819 avail *= bsize / 1024; 820 else if (bsize < 1024) 821 avail /= 1024 / bsize; 822 fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n", 823 avail); 824 } 825 e->e_status = "4.3.1"; 826 usrerrenh(e->e_status, "452 Out of disk space for temp file"); 827 } 828 else 829 syserr("collect: Cannot write %s (%s, uid=%d)", 830 dfname, msg, geteuid()); 831 if (freopen("/dev/null", "w", df) == NULL) 832 sm_syslog(LOG_ERR, e->e_id, 833 "dferror: freopen(\"/dev/null\") failed: %s", 834 errstring(errno)); 835 } 836 /* 837 ** EATFROM -- chew up a UNIX style from line and process 838 ** 839 ** This does indeed make some assumptions about the format 840 ** of UNIX messages. 841 ** 842 ** Parameters: 843 ** fm -- the from line. 844 ** 845 ** Returns: 846 ** none. 847 ** 848 ** Side Effects: 849 ** extracts what information it can from the header, 850 ** such as the date. 851 */ 852 853 #ifndef NOTUNIX 854 855 static char *DowList[] = 856 { 857 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL 858 }; 859 860 static char *MonthList[] = 861 { 862 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 863 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 864 NULL 865 }; 866 867 static void 868 eatfrom(fm, e) 869 char *volatile fm; 870 register ENVELOPE *e; 871 { 872 register char *p; 873 register char **dt; 874 875 if (tTd(30, 2)) 876 dprintf("eatfrom(%s)\n", fm); 877 878 /* find the date part */ 879 p = fm; 880 while (*p != '\0') 881 { 882 /* skip a word */ 883 while (*p != '\0' && *p != ' ') 884 p++; 885 while (*p == ' ') 886 p++; 887 if (strlen(p) < 17) 888 { 889 /* no room for the date */ 890 return; 891 } 892 if (!(isascii(*p) && isupper(*p)) || 893 p[3] != ' ' || p[13] != ':' || p[16] != ':') 894 continue; 895 896 /* we have a possible date */ 897 for (dt = DowList; *dt != NULL; dt++) 898 if (strncmp(*dt, p, 3) == 0) 899 break; 900 if (*dt == NULL) 901 continue; 902 903 for (dt = MonthList; *dt != NULL; dt++) 904 { 905 if (strncmp(*dt, &p[4], 3) == 0) 906 break; 907 } 908 if (*dt != NULL) 909 break; 910 } 911 912 if (*p != '\0') 913 { 914 char *q; 915 916 /* we have found a date */ 917 q = xalloc(25); 918 (void) strlcpy(q, p, 25); 919 q = arpadate(q); 920 define('a', newstr(q), e); 921 } 922 } 923 #endif /* ! NOTUNIX */ 924