1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)envelope.c 8.43 (Berkeley) 11/20/94"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 #include <pwd.h> 15 16 /* 17 ** NEWENVELOPE -- allocate a new envelope 18 ** 19 ** Supports inheritance. 20 ** 21 ** Parameters: 22 ** e -- the new envelope to fill in. 23 ** parent -- the envelope to be the parent of e. 24 ** 25 ** Returns: 26 ** e. 27 ** 28 ** Side Effects: 29 ** none. 30 */ 31 32 ENVELOPE * 33 newenvelope(e, parent) 34 register ENVELOPE *e; 35 register ENVELOPE *parent; 36 { 37 extern putheader(), putbody(); 38 extern ENVELOPE BlankEnvelope; 39 40 if (e == parent && e->e_parent != NULL) 41 parent = e->e_parent; 42 clearenvelope(e, TRUE); 43 if (e == CurEnv) 44 bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from); 45 else 46 bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from); 47 e->e_parent = parent; 48 e->e_ctime = curtime(); 49 if (parent != NULL) 50 e->e_msgpriority = parent->e_msgsize; 51 e->e_puthdr = putheader; 52 e->e_putbody = putbody; 53 if (CurEnv->e_xfp != NULL) 54 (void) fflush(CurEnv->e_xfp); 55 56 return (e); 57 } 58 /* 59 ** DROPENVELOPE -- deallocate an envelope. 60 ** 61 ** Parameters: 62 ** e -- the envelope to deallocate. 63 ** 64 ** Returns: 65 ** none. 66 ** 67 ** Side Effects: 68 ** housekeeping necessary to dispose of an envelope. 69 ** Unlocks this queue file. 70 */ 71 72 void 73 dropenvelope(e) 74 register ENVELOPE *e; 75 { 76 bool queueit = FALSE; 77 bool failure_return = FALSE; 78 bool success_return = FALSE; 79 register ADDRESS *q; 80 char *id = e->e_id; 81 bool return_no, return_yes; 82 char buf[MAXLINE]; 83 84 if (tTd(50, 1)) 85 { 86 printf("dropenvelope %x: id=", e); 87 xputs(e->e_id); 88 printf(", flags=0x%x\n", e->e_flags); 89 if (tTd(50, 10)) 90 { 91 printf("sendq="); 92 printaddr(e->e_sendqueue, TRUE); 93 } 94 } 95 96 /* we must have an id to remove disk files */ 97 if (id == NULL) 98 return; 99 100 #ifdef LOG 101 if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) 102 logsender(e, NULL); 103 if (LogLevel > 84) 104 syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=0x%x, pid=%d", 105 id, e->e_flags, getpid()); 106 #endif /* LOG */ 107 e->e_flags &= ~EF_LOGSENDER; 108 109 /* post statistics */ 110 poststats(StatFile); 111 112 /* 113 ** Extract state information from dregs of send list. 114 */ 115 116 e->e_flags &= ~EF_QUEUERUN; 117 return_no = return_yes = FALSE; 118 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 119 { 120 if (bitset(QQUEUEUP, q->q_flags)) 121 queueit = TRUE; 122 123 /* see if a notification is needed */ 124 if (bitset(QBADADDR, q->q_flags) && 125 bitset(QPINGONFAILURE, q->q_flags)) 126 { 127 failure_return = TRUE; 128 if (q->q_owner == NULL && !emptyaddr(&e->e_from)) 129 (void) sendtolist(e->e_from.q_paddr, NULL, 130 &e->e_errorqueue, e); 131 } 132 else if (bitset(QSENT, q->q_flags) && 133 bitnset(M_LOCALMAILER, q->q_mailer->m_flags) && 134 bitset(QPINGONSUCCESS, q->q_flags)) 135 { 136 success_return = TRUE; 137 } 138 else 139 continue; 140 141 /* common code for error returns and return receipts */ 142 143 /* test for returning the body */ 144 if (!bitset(QHASRETPARAM, q->q_flags)) 145 { 146 if (!bitset(EF_NORETURN, e->e_flags)) 147 return_yes = TRUE; 148 } 149 else if (bitset(QNOBODYRETURN, q->q_flags)) 150 return_no = TRUE; 151 else 152 return_yes = TRUE; 153 } 154 if (return_no && !return_yes) 155 e->e_flags |= EF_NORETURN; 156 157 /* 158 ** See if the message timed out. 159 */ 160 161 if (!queueit) 162 /* nothing to do */ ; 163 else if (curtime() > e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]) 164 { 165 (void) sprintf(buf, "Cannot send message for %s", 166 pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); 167 if (e->e_message != NULL) 168 free(e->e_message); 169 e->e_message = newstr(buf); 170 message(buf); 171 e->e_flags |= EF_CLRQUEUE; 172 failure_return = TRUE; 173 fprintf(e->e_xfp, "Message could not be delivered for %s\n", 174 pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); 175 fprintf(e->e_xfp, "Message will be deleted from queue\n"); 176 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 177 { 178 if (bitset(QQUEUEUP, q->q_flags)) 179 q->q_flags |= QBADADDR; 180 } 181 } 182 else if (TimeOuts.to_q_warning[e->e_timeoutclass] > 0 && 183 curtime() > e->e_ctime + TimeOuts.to_q_warning[e->e_timeoutclass]) 184 { 185 if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) && 186 e->e_class >= 0 && 187 strcmp(e->e_from.q_paddr, "<>") != 0 && 188 strncasecmp(e->e_from.q_paddr, "owner-", 6) != 0 && 189 (strlen(e->e_from.q_paddr) <= 8 || 190 strcasecmp(&e->e_from.q_paddr[strlen(e->e_from.q_paddr) - 8], "-request") != 0)) 191 { 192 (void) sprintf(buf, 193 "Warning: cannot send message for %s", 194 pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE)); 195 if (e->e_message != NULL) 196 free(e->e_message); 197 e->e_message = newstr(buf); 198 message(buf); 199 e->e_flags |= EF_WARNING; 200 failure_return = TRUE; 201 } 202 fprintf(e->e_xfp, 203 "Warning: message still undelivered after %s\n", 204 pintvl(TimeOuts.to_q_warning[e->e_timeoutclass], FALSE)); 205 fprintf(e->e_xfp, "Will keep trying until message is %s old\n", 206 pintvl(TimeOuts.to_q_return[e->e_timeoutclass], FALSE)); 207 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 208 { 209 if (bitset(QQUEUEUP, q->q_flags)) 210 q->q_flags |= QREPORT; 211 } 212 } 213 214 if (tTd(50, 2)) 215 printf("failure_return=%d success_return=%d queueit=%d\n", 216 failure_return, success_return, queueit); 217 218 /* 219 ** Send back return receipts as requested. 220 */ 221 222 /* 223 if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags) 224 && !bitset(PRIV_NORECEIPTS, PrivacyFlags)) 225 */ 226 if (e->e_receiptto == NULL) 227 e->e_receiptto = e->e_from.q_paddr; 228 if (success_return && strcmp(e->e_receiptto, "<>") != 0) 229 { 230 auto ADDRESS *rlist = NULL; 231 232 e->e_flags |= EF_SENDRECEIPT; 233 (void) sendtolist(e->e_receiptto, NULLADDR, &rlist, e); 234 (void) returntosender("Return receipt", rlist, FALSE, e); 235 } 236 e->e_flags &= ~EF_SENDRECEIPT; 237 238 /* 239 ** Arrange to send error messages if there are fatal errors. 240 */ 241 242 if (failure_return && e->e_errormode != EM_QUIET) 243 savemail(e); 244 245 /* 246 ** Arrange to send warning messages to postmaster as requested. 247 */ 248 249 if (bitset(EF_PM_NOTIFY, e->e_flags) && PostMasterCopy != NULL && 250 !bitset(EF_RESPONSE, e->e_flags) && e->e_class >= 0) 251 { 252 auto ADDRESS *rlist = NULL; 253 254 (void) sendtolist(PostMasterCopy, NULLADDR, &rlist, e); 255 (void) returntosender(e->e_message, rlist, FALSE, e); 256 } 257 258 /* 259 ** Instantiate or deinstantiate the queue. 260 */ 261 262 if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) || 263 bitset(EF_CLRQUEUE, e->e_flags)) 264 { 265 if (tTd(50, 1)) 266 printf("\n===== Dropping [dq]f%s (queueit=%d, e_flags=%x) =====\n\n", 267 e->e_id, queueit, e->e_flags); 268 if (e->e_df != NULL) 269 xunlink(e->e_df); 270 xunlink(queuename(e, 'q')); 271 272 #ifdef LOG 273 if (LogLevel > 10) 274 syslog(LOG_INFO, "%s: done", id); 275 #endif 276 } 277 else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) 278 { 279 #ifdef QUEUE 280 queueup(e, bitset(EF_KEEPQUEUE, e->e_flags), FALSE); 281 #else /* QUEUE */ 282 syserr("554 dropenvelope: queueup"); 283 #endif /* QUEUE */ 284 } 285 286 /* now unlock the job */ 287 closexscript(e); 288 unlockqueue(e); 289 290 /* make sure that this envelope is marked unused */ 291 if (e->e_dfp != NULL) 292 (void) xfclose(e->e_dfp, "dropenvelope", e->e_df); 293 e->e_dfp = NULL; 294 e->e_id = e->e_df = NULL; 295 } 296 /* 297 ** CLEARENVELOPE -- clear an envelope without unlocking 298 ** 299 ** This is normally used by a child process to get a clean 300 ** envelope without disturbing the parent. 301 ** 302 ** Parameters: 303 ** e -- the envelope to clear. 304 ** fullclear - if set, the current envelope is total 305 ** garbage and should be ignored; otherwise, 306 ** release any resources it may indicate. 307 ** 308 ** Returns: 309 ** none. 310 ** 311 ** Side Effects: 312 ** Closes files associated with the envelope. 313 ** Marks the envelope as unallocated. 314 */ 315 316 void 317 clearenvelope(e, fullclear) 318 register ENVELOPE *e; 319 bool fullclear; 320 { 321 register HDR *bh; 322 register HDR **nhp; 323 extern ENVELOPE BlankEnvelope; 324 325 if (!fullclear) 326 { 327 /* clear out any file information */ 328 if (e->e_xfp != NULL) 329 (void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id); 330 if (e->e_dfp != NULL) 331 (void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_df); 332 e->e_xfp = e->e_dfp = NULL; 333 } 334 335 /* now clear out the data */ 336 STRUCTCOPY(BlankEnvelope, *e); 337 if (Verbose) 338 e->e_sendmode = SM_DELIVER; 339 bh = BlankEnvelope.e_header; 340 nhp = &e->e_header; 341 while (bh != NULL) 342 { 343 *nhp = (HDR *) xalloc(sizeof *bh); 344 bcopy((char *) bh, (char *) *nhp, sizeof *bh); 345 bh = bh->h_link; 346 nhp = &(*nhp)->h_link; 347 } 348 } 349 /* 350 ** INITSYS -- initialize instantiation of system 351 ** 352 ** In Daemon mode, this is done in the child. 353 ** 354 ** Parameters: 355 ** none. 356 ** 357 ** Returns: 358 ** none. 359 ** 360 ** Side Effects: 361 ** Initializes the system macros, some global variables, 362 ** etc. In particular, the current time in various 363 ** forms is set. 364 */ 365 366 void 367 initsys(e) 368 register ENVELOPE *e; 369 { 370 char cbuf[5]; /* holds hop count */ 371 char pbuf[10]; /* holds pid */ 372 #ifdef TTYNAME 373 static char ybuf[60]; /* holds tty id */ 374 register char *p; 375 #endif /* TTYNAME */ 376 extern char *ttyname(); 377 extern void settime(); 378 extern char Version[]; 379 380 /* 381 ** Give this envelope a reality. 382 ** I.e., an id, a transcript, and a creation time. 383 */ 384 385 openxscript(e); 386 e->e_ctime = curtime(); 387 388 /* 389 ** Set OutChannel to something useful if stdout isn't it. 390 ** This arranges that any extra stuff the mailer produces 391 ** gets sent back to the user on error (because it is 392 ** tucked away in the transcript). 393 */ 394 395 if (OpMode == MD_DAEMON && bitset(EF_QUEUERUN, e->e_flags) && 396 e->e_xfp != NULL) 397 OutChannel = e->e_xfp; 398 399 /* 400 ** Set up some basic system macros. 401 */ 402 403 /* process id */ 404 (void) sprintf(pbuf, "%d", getpid()); 405 define('p', newstr(pbuf), e); 406 407 /* hop count */ 408 (void) sprintf(cbuf, "%d", e->e_hopcount); 409 define('c', newstr(cbuf), e); 410 411 /* time as integer, unix time, arpa time */ 412 settime(e); 413 414 #ifdef TTYNAME 415 /* tty name */ 416 if (macvalue('y', e) == NULL) 417 { 418 p = ttyname(2); 419 if (p != NULL) 420 { 421 if (strrchr(p, '/') != NULL) 422 p = strrchr(p, '/') + 1; 423 (void) strcpy(ybuf, p); 424 define('y', ybuf, e); 425 } 426 } 427 #endif /* TTYNAME */ 428 } 429 /* 430 ** SETTIME -- set the current time. 431 ** 432 ** Parameters: 433 ** none. 434 ** 435 ** Returns: 436 ** none. 437 ** 438 ** Side Effects: 439 ** Sets the various time macros -- $a, $b, $d, $t. 440 */ 441 442 void 443 settime(e) 444 register ENVELOPE *e; 445 { 446 register char *p; 447 auto time_t now; 448 char tbuf[20]; /* holds "current" time */ 449 char dbuf[30]; /* holds ctime(tbuf) */ 450 register struct tm *tm; 451 extern char *arpadate(); 452 extern struct tm *gmtime(); 453 454 now = curtime(); 455 tm = gmtime(&now); 456 (void) sprintf(tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900, 457 tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); 458 define('t', newstr(tbuf), e); 459 (void) strcpy(dbuf, ctime(&now)); 460 p = strchr(dbuf, '\n'); 461 if (p != NULL) 462 *p = '\0'; 463 define('d', newstr(dbuf), e); 464 p = arpadate(dbuf); 465 p = newstr(p); 466 if (macvalue('a', e) == NULL) 467 define('a', p, e); 468 define('b', p, e); 469 } 470 /* 471 ** OPENXSCRIPT -- Open transcript file 472 ** 473 ** Creates a transcript file for possible eventual mailing or 474 ** sending back. 475 ** 476 ** Parameters: 477 ** e -- the envelope to create the transcript in/for. 478 ** 479 ** Returns: 480 ** none 481 ** 482 ** Side Effects: 483 ** Creates the transcript file. 484 */ 485 486 #ifndef O_APPEND 487 #define O_APPEND 0 488 #endif 489 490 void 491 openxscript(e) 492 register ENVELOPE *e; 493 { 494 register char *p; 495 int fd; 496 497 if (e->e_xfp != NULL) 498 return; 499 p = queuename(e, 'x'); 500 fd = open(p, O_WRONLY|O_CREAT|O_APPEND, 0644); 501 if (fd < 0) 502 { 503 syserr("Can't create transcript file %s", p); 504 fd = open("/dev/null", O_WRONLY, 0644); 505 if (fd < 0) 506 syserr("!Can't open /dev/null"); 507 } 508 e->e_xfp = fdopen(fd, "w"); 509 if (e->e_xfp == NULL) 510 { 511 syserr("!Can't create transcript stream %s", p); 512 } 513 if (tTd(46, 9)) 514 { 515 printf("openxscript(%s):\n ", p); 516 dumpfd(fileno(e->e_xfp), TRUE, FALSE); 517 } 518 } 519 /* 520 ** CLOSEXSCRIPT -- close the transcript file. 521 ** 522 ** Parameters: 523 ** e -- the envelope containing the transcript to close. 524 ** 525 ** Returns: 526 ** none. 527 ** 528 ** Side Effects: 529 ** none. 530 */ 531 532 void 533 closexscript(e) 534 register ENVELOPE *e; 535 { 536 if (e->e_xfp == NULL) 537 return; 538 (void) xfclose(e->e_xfp, "closexscript", e->e_id); 539 e->e_xfp = NULL; 540 } 541 /* 542 ** SETSENDER -- set the person who this message is from 543 ** 544 ** Under certain circumstances allow the user to say who 545 ** s/he is (using -f or -r). These are: 546 ** 1. The user's uid is zero (root). 547 ** 2. The user's login name is in an approved list (typically 548 ** from a network server). 549 ** 3. The address the user is trying to claim has a 550 ** "!" character in it (since #2 doesn't do it for 551 ** us if we are dialing out for UUCP). 552 ** A better check to replace #3 would be if the 553 ** effective uid is "UUCP" -- this would require me 554 ** to rewrite getpwent to "grab" uucp as it went by, 555 ** make getname more nasty, do another passwd file 556 ** scan, or compile the UID of "UUCP" into the code, 557 ** all of which are reprehensible. 558 ** 559 ** Assuming all of these fail, we figure out something 560 ** ourselves. 561 ** 562 ** Parameters: 563 ** from -- the person we would like to believe this message 564 ** is from, as specified on the command line. 565 ** e -- the envelope in which we would like the sender set. 566 ** delimptr -- if non-NULL, set to the location of the 567 ** trailing delimiter. 568 ** internal -- set if this address is coming from an internal 569 ** source such as an owner alias. 570 ** 571 ** Returns: 572 ** none. 573 ** 574 ** Side Effects: 575 ** sets sendmail's notion of who the from person is. 576 */ 577 578 void 579 setsender(from, e, delimptr, internal) 580 char *from; 581 register ENVELOPE *e; 582 char **delimptr; 583 bool internal; 584 { 585 register char **pvp; 586 char *realname = NULL; 587 register struct passwd *pw; 588 char delimchar; 589 char *bp; 590 char buf[MAXNAME + 2]; 591 char pvpbuf[PSBUFSIZE]; 592 extern struct passwd *getpwnam(); 593 extern char *FullName; 594 595 if (tTd(45, 1)) 596 printf("setsender(%s)\n", from == NULL ? "" : from); 597 598 /* 599 ** Figure out the real user executing us. 600 ** Username can return errno != 0 on non-errors. 601 */ 602 603 if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP || 604 OpMode == MD_ARPAFTP || OpMode == MD_DAEMON) 605 realname = from; 606 if (realname == NULL || realname[0] == '\0') 607 realname = username(); 608 609 if (ConfigLevel < 2) 610 SuprErrs = TRUE; 611 612 delimchar = internal ? '\0' : ' '; 613 e->e_from.q_flags = QBADADDR; 614 if (from == NULL || 615 parseaddr(from, &e->e_from, RF_COPYALL|RF_SENDERADDR, 616 delimchar, delimptr, e) == NULL || 617 bitset(QBADADDR, e->e_from.q_flags) || 618 e->e_from.q_mailer == ProgMailer || 619 e->e_from.q_mailer == FileMailer || 620 e->e_from.q_mailer == InclMailer) 621 { 622 /* log garbage addresses for traceback */ 623 # ifdef LOG 624 if (from != NULL && LogLevel > 2) 625 { 626 char *p; 627 char ebuf[MAXNAME * 2 + 2]; 628 629 p = macvalue('_', e); 630 if (p == NULL) 631 { 632 char *host = RealHostName; 633 if (host == NULL) 634 host = MyHostName; 635 (void) sprintf(ebuf, "%s@%s", realname, host); 636 p = ebuf; 637 } 638 syslog(LOG_NOTICE, 639 "setsender: %s: invalid or unparseable, received from %s", 640 shortenstring(from, 83), p); 641 } 642 # endif /* LOG */ 643 if (from != NULL) 644 { 645 if (!bitset(QBADADDR, e->e_from.q_flags)) 646 { 647 /* it was a bogus mailer in the from addr */ 648 usrerr("553 Invalid sender address"); 649 } 650 SuprErrs = TRUE; 651 } 652 if (from == realname || 653 parseaddr(from = newstr(realname), &e->e_from, 654 RF_COPYALL|RF_SENDERADDR, ' ', NULL, e) == NULL) 655 { 656 char nbuf[100]; 657 658 SuprErrs = TRUE; 659 expand("\201n", nbuf, &nbuf[sizeof nbuf], e); 660 if (parseaddr(from = newstr(nbuf), &e->e_from, 661 RF_COPYALL, ' ', NULL, e) == NULL && 662 parseaddr(from = "postmaster", &e->e_from, 663 RF_COPYALL, ' ', NULL, e) == NULL) 664 syserr("553 setsender: can't even parse postmaster!"); 665 } 666 } 667 else 668 FromFlag = TRUE; 669 e->e_from.q_flags |= QDONTSEND; 670 if (tTd(45, 5)) 671 { 672 printf("setsender: QDONTSEND "); 673 printaddr(&e->e_from, FALSE); 674 } 675 SuprErrs = FALSE; 676 677 # ifdef USERDB 678 if (bitnset(M_CHECKUDB, e->e_from.q_mailer->m_flags)) 679 { 680 register char *p; 681 extern char *udbsender(); 682 683 p = udbsender(e->e_from.q_user); 684 if (p != NULL) 685 from = p; 686 } 687 # endif /* USERDB */ 688 689 if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags)) 690 { 691 if (!internal) 692 { 693 /* if the user already given fullname don't redefine */ 694 if (FullName == NULL) 695 FullName = macvalue('x', e); 696 if (FullName != NULL && FullName[0] == '\0') 697 FullName = NULL; 698 } 699 700 if ((pw = getpwnam(e->e_from.q_user)) != NULL) 701 { 702 /* 703 ** Process passwd file entry. 704 */ 705 706 /* extract home directory */ 707 if (strcmp(pw->pw_dir, "/") == 0) 708 e->e_from.q_home = newstr(""); 709 else 710 e->e_from.q_home = newstr(pw->pw_dir); 711 define('z', e->e_from.q_home, e); 712 713 /* extract user and group id */ 714 e->e_from.q_uid = pw->pw_uid; 715 e->e_from.q_gid = pw->pw_gid; 716 e->e_from.q_flags |= QGOODUID; 717 718 /* extract full name from passwd file */ 719 if (FullName == NULL && pw->pw_gecos != NULL && 720 strcmp(pw->pw_name, e->e_from.q_user) == 0 && 721 !internal) 722 { 723 buildfname(pw->pw_gecos, e->e_from.q_user, buf); 724 if (buf[0] != '\0') 725 FullName = newstr(buf); 726 } 727 } 728 if (FullName != NULL && !internal) 729 define('x', FullName, e); 730 } 731 else if (!internal && OpMode != MD_DAEMON) 732 { 733 if (e->e_from.q_home == NULL) 734 { 735 e->e_from.q_home = getenv("HOME"); 736 if (e->e_from.q_home != NULL && 737 strcmp(e->e_from.q_home, "/") == 0) 738 e->e_from.q_home++; 739 } 740 e->e_from.q_uid = RealUid; 741 e->e_from.q_gid = RealGid; 742 e->e_from.q_flags |= QGOODUID; 743 } 744 745 /* 746 ** Rewrite the from person to dispose of possible implicit 747 ** links in the net. 748 */ 749 750 pvp = prescan(from, delimchar, pvpbuf, sizeof pvpbuf, NULL); 751 if (pvp == NULL) 752 { 753 /* don't need to give error -- prescan did that already */ 754 # ifdef LOG 755 if (LogLevel > 2) 756 syslog(LOG_NOTICE, "cannot prescan from (%s)", from); 757 # endif 758 finis(); 759 } 760 /* 761 (void) rewrite(pvp, 3, 0, e); 762 (void) rewrite(pvp, 1, 0, e); 763 (void) rewrite(pvp, 4, 0, e); 764 */ 765 bp = buf + 1; 766 cataddr(pvp, NULL, bp, sizeof buf - 2, '\0'); 767 if (*bp == '@' && !bitnset(M_NOBRACKET, e->e_from.q_mailer->m_flags)) 768 { 769 /* heuristic: route-addr: add angle brackets */ 770 strcat(bp, ">"); 771 *--bp = '<'; 772 } 773 e->e_sender = newstr(bp); 774 define('f', e->e_sender, e); 775 776 /* save the domain spec if this mailer wants it */ 777 if (e->e_from.q_mailer != NULL && 778 bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags)) 779 { 780 extern char **copyplist(); 781 782 while (*pvp != NULL && strcmp(*pvp, "@") != 0) 783 pvp++; 784 if (*pvp != NULL) 785 e->e_fromdomain = copyplist(pvp, TRUE); 786 } 787 } 788