1 # include "sendmail.h" 2 3 SCCSID(@(#)parseaddr.c 3.47 08/21/82); 4 5 /* 6 ** PARSE -- Parse an address 7 ** 8 ** Parses an address and breaks it up into three parts: a 9 ** net to transmit the message on, the host to transmit it 10 ** to, and a user on that host. These are loaded into an 11 ** ADDRESS header with the values squirreled away if necessary. 12 ** The "user" part may not be a real user; the process may 13 ** just reoccur on that machine. For example, on a machine 14 ** with an arpanet connection, the address 15 ** csvax.bill@berkeley 16 ** will break up to a "user" of 'csvax.bill' and a host 17 ** of 'berkeley' -- to be transmitted over the arpanet. 18 ** 19 ** Parameters: 20 ** addr -- the address to parse. 21 ** a -- a pointer to the address descriptor buffer. 22 ** If NULL, a header will be created. 23 ** copyf -- determines what shall be copied: 24 ** -1 -- don't copy anything. The printname 25 ** (q_paddr) is just addr, and the 26 ** user & host are allocated internally 27 ** to parse. 28 ** 0 -- copy out the parsed user & host, but 29 ** don't copy the printname. 30 ** +1 -- copy everything. 31 ** 32 ** Returns: 33 ** A pointer to the address descriptor header (`a' if 34 ** `a' is non-NULL). 35 ** NULL on error. 36 ** 37 ** Side Effects: 38 ** none 39 */ 40 41 # define DELIMCHARS "$()<>,;\\\"\r\n" /* word delimiters */ 42 43 ADDRESS * 44 parse(addr, a, copyf) 45 char *addr; 46 register ADDRESS *a; 47 int copyf; 48 { 49 register char **pvp; 50 register struct mailer *m; 51 extern char **prescan(); 52 extern ADDRESS *buildaddr(); 53 54 /* 55 ** Initialize and prescan address. 56 */ 57 58 CurEnv->e_to = addr; 59 # ifdef DEBUG 60 if (tTd(20, 1)) 61 printf("\n--parse(%s)\n", addr); 62 # endif DEBUG 63 64 pvp = prescan(addr, '\0'); 65 if (pvp == NULL) 66 return (NULL); 67 68 /* 69 ** Apply rewriting rules. 70 */ 71 72 rewrite(pvp, 0); 73 74 /* 75 ** See if we resolved to a real mailer. 76 */ 77 78 if (pvp[0][0] != CANONNET) 79 { 80 setstat(EX_USAGE); 81 usrerr("cannot resolve name"); 82 return (NULL); 83 } 84 85 /* 86 ** Build canonical address from pvp. 87 */ 88 89 a = buildaddr(pvp, a); 90 if (a == NULL) 91 return (NULL); 92 m = a->q_mailer; 93 94 /* 95 ** Make local copies of the host & user and then 96 ** transport them out. 97 */ 98 99 if (copyf > 0) 100 a->q_paddr = newstr(addr); 101 else 102 a->q_paddr = addr; 103 104 if (copyf >= 0) 105 { 106 if (a->q_host != NULL) 107 a->q_host = newstr(a->q_host); 108 else 109 a->q_host = ""; 110 if (a->q_user != a->q_paddr) 111 a->q_user = newstr(a->q_user); 112 } 113 114 /* 115 ** Do UPPER->lower case mapping unless inhibited. 116 */ 117 118 if (!bitset(M_HST_UPPER, m->m_flags)) 119 makelower(a->q_host); 120 if (!bitset(M_USR_UPPER, m->m_flags)) 121 makelower(a->q_user); 122 123 /* 124 ** Compute return value. 125 */ 126 127 # ifdef DEBUG 128 if (tTd(20, 1)) 129 { 130 printf("parse-->"); 131 printaddr(a, FALSE); 132 } 133 # endif DEBUG 134 135 return (a); 136 } 137 /* 138 ** PRESCAN -- Prescan name and make it canonical 139 ** 140 ** Scans a name and turns it into canonical form. This involves 141 ** deleting blanks, comments (in parentheses), and turning the 142 ** word "at" into an at-sign ("@"). The name is copied as this 143 ** is done; it is legal to copy a name onto itself, since this 144 ** process can only make things smaller. 145 ** 146 ** This routine knows about quoted strings and angle brackets. 147 ** 148 ** There are certain subtleties to this routine. The one that 149 ** comes to mind now is that backslashes on the ends of names 150 ** are silently stripped off; this is intentional. The problem 151 ** is that some versions of sndmsg (like at LBL) set the kill 152 ** character to something other than @ when reading addresses; 153 ** so people type "csvax.eric\@berkeley" -- which screws up the 154 ** berknet mailer. 155 ** 156 ** Parameters: 157 ** addr -- the name to chomp. 158 ** delim -- the delimiter for the address, normally 159 ** '\0' or ','; \0 is accepted in any case. 160 ** are moving in place; set buflim to high core. 161 ** 162 ** Returns: 163 ** A pointer to a vector of tokens. 164 ** NULL on error. 165 ** 166 ** Side Effects: 167 ** none. 168 */ 169 170 # define OPER 1 171 # define ATOM 2 172 # define EOTOK 3 173 # define QSTRING 4 174 # define SPACE 5 175 # define ONEMORE 6 176 # define GETONE 7 177 # define MACRO 8 178 179 char ** 180 prescan(addr, delim) 181 char *addr; 182 char delim; 183 { 184 register char *p; 185 static char buf[MAXNAME+MAXATOM]; 186 static char *av[MAXATOM+1]; 187 char **avp; 188 bool bslashmode; 189 int cmntcnt; 190 register char c; 191 char *tok; 192 register char *q; 193 register int state; 194 int nstate; 195 extern char lower(); 196 197 q = buf; 198 bslashmode = FALSE; 199 cmntcnt = 0; 200 avp = av; 201 state = OPER; 202 for (p = addr; *p != '\0' && *p != delim; ) 203 { 204 /* read a token */ 205 tok = q; 206 while ((c = *p++) != '\0' && c != delim) 207 { 208 /* chew up special characters */ 209 c &= ~0200; 210 *q = '\0'; 211 if (bslashmode) 212 { 213 c |= 0200; 214 bslashmode = FALSE; 215 } 216 else if (c == '\\') 217 { 218 bslashmode = TRUE; 219 continue; 220 } 221 else if (c == '"') 222 { 223 if (state == QSTRING) 224 state = OPER; 225 else 226 state = QSTRING; 227 break; 228 } 229 230 nstate = toktype(c); 231 switch (state) 232 { 233 case QSTRING: /* in quoted string */ 234 break; 235 236 case ATOM: /* regular atom */ 237 if (nstate != ATOM) 238 { 239 state = EOTOK; 240 p--; 241 } 242 break; 243 244 case GETONE: /* grab one character */ 245 state = OPER; 246 break; 247 248 case EOTOK: /* after atom or q-string */ 249 state = nstate; 250 if (state == SPACE) 251 continue; 252 break; 253 254 case SPACE: /* linear white space */ 255 state = nstate; 256 break; 257 258 case OPER: /* operator */ 259 if (nstate == SPACE) 260 continue; 261 state = nstate; 262 break; 263 264 case ONEMORE: /* $- etc. */ 265 state = GETONE; 266 break; 267 268 default: 269 syserr("prescan: unknown state %d", state); 270 } 271 272 if (state == EOTOK || state == SPACE) 273 break; 274 275 /* squirrel it away */ 276 if (q >= &buf[sizeof buf - 5]) 277 { 278 usrerr("Address too long"); 279 return (NULL); 280 } 281 *q++ = c; 282 283 /* decide whether this represents end of token */ 284 if (state == OPER || state == GETONE) 285 break; 286 } 287 if (c == '\0' || c == delim) 288 p--; 289 290 /* new token */ 291 if (tok == q) 292 continue; 293 *q++ = '\0'; 294 295 c = tok[0]; 296 if (c == '(') 297 { 298 cmntcnt++; 299 continue; 300 } 301 else if (c == ')') 302 { 303 if (cmntcnt <= 0) 304 { 305 usrerr("Unbalanced ')'"); 306 return (NULL); 307 } 308 else 309 { 310 cmntcnt--; 311 continue; 312 } 313 } 314 else if (cmntcnt > 0) 315 continue; 316 317 if (avp >= &av[MAXATOM]) 318 { 319 syserr("prescan: too many tokens"); 320 return (NULL); 321 } 322 *avp++ = tok; 323 } 324 *avp = NULL; 325 if (cmntcnt > 0) 326 usrerr("Unbalanced '('"); 327 else if (state == QSTRING) 328 usrerr("Unbalanced '\"'"); 329 else if (av[0] != NULL) 330 return (av); 331 return (NULL); 332 } 333 /* 334 ** TOKTYPE -- return token type 335 ** 336 ** Parameters: 337 ** c -- the character in question. 338 ** 339 ** Returns: 340 ** Its type. 341 ** 342 ** Side Effects: 343 ** none. 344 */ 345 346 toktype(c) 347 register char c; 348 { 349 static char buf[50]; 350 static bool firstime = TRUE; 351 352 if (firstime) 353 { 354 firstime = FALSE; 355 expand("$o", buf, &buf[sizeof buf - 1], CurEnv); 356 (void) strcat(buf, DELIMCHARS); 357 } 358 if (c == MATCHCLASS || c == MATCHREPL) 359 return (ONEMORE); 360 if (!isascii(c)) 361 return (ATOM); 362 if (isspace(c)) 363 return (SPACE); 364 if (iscntrl(c) || index(buf, c) != NULL) 365 return (OPER); 366 return (ATOM); 367 } 368 /* 369 ** REWRITE -- apply rewrite rules to token vector. 370 ** 371 ** This routine is an ordered production system. Each rewrite 372 ** rule has a LHS (called the pattern) and a RHS (called the 373 ** rewrite); 'rwr' points the the current rewrite rule. 374 ** 375 ** For each rewrite rule, 'avp' points the address vector we 376 ** are trying to match against, and 'pvp' points to the pattern. 377 ** If pvp points to a special match value (MATCHANY, MATCHONE, 378 ** MATCHCLASS) then the address in avp matched is saved away 379 ** in the match vector (pointed to by 'mvp'). 380 ** 381 ** When a match between avp & pvp does not match, we try to 382 ** back out. If we back up over a MATCHONE or a MATCHCLASS 383 ** we must also back out the match in mvp. If we reach a 384 ** MATCHANY we just extend the match and start over again. 385 ** 386 ** When we finally match, we rewrite the address vector 387 ** and try over again. 388 ** 389 ** Parameters: 390 ** pvp -- pointer to token vector. 391 ** 392 ** Returns: 393 ** none. 394 ** 395 ** Side Effects: 396 ** pvp is modified. 397 */ 398 399 struct match 400 { 401 char **first; /* first token matched */ 402 char **last; /* last token matched */ 403 }; 404 405 # define MAXMATCH 9 /* max params per rewrite */ 406 407 408 rewrite(pvp, ruleset) 409 char **pvp; 410 int ruleset; 411 { 412 register char *ap; /* address pointer */ 413 register char *rp; /* rewrite pointer */ 414 register char **avp; /* address vector pointer */ 415 register char **rvp; /* rewrite vector pointer */ 416 struct rewrite *rwr; /* pointer to current rewrite rule */ 417 struct match mlist[MAXMATCH]; /* stores match on LHS */ 418 struct match *mlp; /* cur ptr into mlist */ 419 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 420 extern bool sameword(); 421 422 # ifdef DEBUG 423 if (tTd(21, 9)) 424 { 425 printf("rewrite: original pvp:\n"); 426 printav(pvp); 427 } 428 # endif DEBUG 429 430 /* 431 ** Run through the list of rewrite rules, applying 432 ** any that match. 433 */ 434 435 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 436 { 437 # ifdef DEBUG 438 if (tTd(21, 12)) 439 { 440 printf("-----trying rule:\n"); 441 printav(rwr->r_lhs); 442 } 443 # endif DEBUG 444 445 /* try to match on this rule */ 446 mlp = mlist; 447 for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 448 { 449 ap = *avp; 450 rp = *rvp; 451 452 if (rp == NULL) 453 { 454 /* end-of-pattern before end-of-address */ 455 goto fail; 456 } 457 458 switch (*rp) 459 { 460 register STAB *s; 461 register int class; 462 463 case MATCHCLASS: 464 /* match any token in a class */ 465 class = rp[1]; 466 if (!isalpha(class)) 467 goto fail; 468 if (isupper(class)) 469 class -= 'A'; 470 else 471 class -= 'a'; 472 s = stab(ap, ST_CLASS, ST_FIND); 473 if (s == NULL || (s->s_class & (1L << class)) == 0) 474 goto fail; 475 476 /* explicit fall-through */ 477 478 case MATCHONE: 479 case MATCHANY: 480 /* match exactly one token */ 481 mlp->first = mlp->last = avp++; 482 mlp++; 483 break; 484 485 default: 486 /* must have exact match */ 487 if (!sameword(rp, ap)) 488 goto fail; 489 avp++; 490 break; 491 } 492 493 /* successful match on this token */ 494 rvp++; 495 continue; 496 497 fail: 498 /* match failed -- back up */ 499 while (--rvp >= rwr->r_lhs) 500 { 501 rp = *rvp; 502 if (*rp == MATCHANY) 503 { 504 /* extend binding and continue */ 505 mlp[-1].last = avp++; 506 rvp++; 507 break; 508 } 509 avp--; 510 if (*rp == MATCHONE || *rp == MATCHCLASS) 511 { 512 /* back out binding */ 513 mlp--; 514 } 515 } 516 517 if (rvp < rwr->r_lhs) 518 { 519 /* total failure to match */ 520 break; 521 } 522 } 523 524 /* 525 ** See if we successfully matched 526 */ 527 528 if (rvp >= rwr->r_lhs && *rvp == NULL) 529 { 530 # ifdef DEBUG 531 if (tTd(21, 12)) 532 { 533 printf("-----rule matches:\n"); 534 printav(rwr->r_rhs); 535 } 536 # endif DEBUG 537 538 /* substitute */ 539 for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 540 { 541 rp = *rvp; 542 if (*rp == MATCHREPL) 543 { 544 register struct match *m; 545 register char **pp; 546 547 m = &mlist[rp[1] - '1']; 548 # ifdef DEBUG 549 if (tTd(21, 15)) 550 { 551 printf("$%c:", rp[1]); 552 pp = m->first; 553 do 554 { 555 printf(" %x=\"", *pp); 556 (void) fflush(stdout); 557 printf("%s\"", *pp); 558 } while (pp++ != m->last); 559 printf("\n"); 560 } 561 # endif DEBUG 562 pp = m->first; 563 do 564 { 565 if (avp >= &npvp[MAXATOM]) 566 { 567 syserr("rewrite: expansion too long"); 568 return; 569 } 570 *avp++ = *pp; 571 } while (pp++ != m->last); 572 } 573 else 574 { 575 if (avp >= &npvp[MAXATOM]) 576 { 577 syserr("rewrite: expansion too long"); 578 return; 579 } 580 *avp++ = rp; 581 } 582 } 583 *avp++ = NULL; 584 bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 585 # ifdef DEBUG 586 if (tTd(21, 4)) 587 { 588 char **vp; 589 590 printf("rewritten as `"); 591 for (vp = pvp; *vp != NULL; vp++) 592 { 593 if (vp != pvp) 594 printf("_"); 595 xputs(*vp); 596 } 597 printf("'\n"); 598 } 599 # endif DEBUG 600 if (pvp[0][0] == CANONNET) 601 break; 602 } 603 else 604 { 605 # ifdef DEBUG 606 if (tTd(21, 10)) 607 printf("----- rule fails\n"); 608 # endif DEBUG 609 rwr = rwr->r_next; 610 } 611 } 612 } 613 /* 614 ** BUILDADDR -- build address from token vector. 615 ** 616 ** Parameters: 617 ** tv -- token vector. 618 ** a -- pointer to address descriptor to fill. 619 ** If NULL, one will be allocated. 620 ** 621 ** Returns: 622 ** NULL if there was an error. 623 ** 'a' otherwise. 624 ** 625 ** Side Effects: 626 ** fills in 'a' 627 */ 628 629 ADDRESS * 630 buildaddr(tv, a) 631 register char **tv; 632 register ADDRESS *a; 633 { 634 static char buf[MAXNAME]; 635 struct mailer **mp; 636 register struct mailer *m; 637 extern bool sameword(); 638 639 if (a == NULL) 640 a = (ADDRESS *) xalloc(sizeof *a); 641 clear((char *) a, sizeof *a); 642 643 /* figure out what net/mailer to use */ 644 if (**tv != CANONNET) 645 { 646 syserr("buildaddr: no net"); 647 return (NULL); 648 } 649 tv++; 650 if (sameword(*tv, "error")) 651 { 652 if (**++tv != CANONUSER) 653 syserr("buildaddr: error: no user"); 654 buf[0] = '\0'; 655 while (*++tv != NULL) 656 { 657 if (buf[0] != '\0') 658 (void) strcat(buf, " "); 659 (void) strcat(buf, *tv); 660 } 661 usrerr(buf); 662 return (NULL); 663 } 664 for (mp = Mailer; (m = *mp++) != NULL; ) 665 { 666 if (sameword(m->m_name, *tv)) 667 break; 668 } 669 if (m == NULL) 670 { 671 syserr("buildaddr: unknown net %s", *tv); 672 return (NULL); 673 } 674 a->q_mailer = m; 675 676 /* figure out what host (if any) */ 677 tv++; 678 if (!bitset(M_LOCAL, m->m_flags)) 679 { 680 if (**tv++ != CANONHOST) 681 { 682 syserr("buildaddr: no host"); 683 return (NULL); 684 } 685 buf[0] = '\0'; 686 while (*tv != NULL && **tv != CANONUSER) 687 (void) strcat(buf, *tv++); 688 a->q_host = newstr(buf); 689 } 690 else 691 a->q_host = NULL; 692 693 /* figure out the user */ 694 if (**tv != CANONUSER) 695 { 696 syserr("buildaddr: no user"); 697 return (NULL); 698 } 699 cataddr(++tv, buf, sizeof buf); 700 a->q_user = buf; 701 702 return (a); 703 } 704 /* 705 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 706 ** 707 ** Parameters: 708 ** pvp -- parameter vector to rebuild. 709 ** buf -- buffer to build the string into. 710 ** sz -- size of buf. 711 ** 712 ** Returns: 713 ** none. 714 ** 715 ** Side Effects: 716 ** Destroys buf. 717 */ 718 719 cataddr(pvp, buf, sz) 720 char **pvp; 721 char *buf; 722 register int sz; 723 { 724 bool oatomtok = FALSE; 725 bool natomtok = FALSE; 726 register int i; 727 register char *p; 728 729 p = buf; 730 sz--; 731 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 732 { 733 natomtok = (toktype(**pvp) == ATOM); 734 if (oatomtok && natomtok) 735 *p++ = SPACESUB; 736 (void) strcpy(p, *pvp); 737 oatomtok = natomtok; 738 p += i; 739 sz -= i; 740 pvp++; 741 } 742 *p = '\0'; 743 } 744 /* 745 ** SAMEADDR -- Determine if two addresses are the same 746 ** 747 ** This is not just a straight comparison -- if the mailer doesn't 748 ** care about the host we just ignore it, etc. 749 ** 750 ** Parameters: 751 ** a, b -- pointers to the internal forms to compare. 752 ** wildflg -- if TRUE, 'a' may have no user specified, 753 ** in which case it is to match anything. 754 ** 755 ** Returns: 756 ** TRUE -- they represent the same mailbox. 757 ** FALSE -- they don't. 758 ** 759 ** Side Effects: 760 ** none. 761 */ 762 763 bool 764 sameaddr(a, b, wildflg) 765 register ADDRESS *a; 766 register ADDRESS *b; 767 bool wildflg; 768 { 769 /* if they don't have the same mailer, forget it */ 770 if (a->q_mailer != b->q_mailer) 771 return (FALSE); 772 773 /* if the user isn't the same, we can drop out */ 774 if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 775 return (FALSE); 776 777 /* if the mailer ignores hosts, we have succeeded! */ 778 if (bitset(M_LOCAL, a->q_mailer->m_flags)) 779 return (TRUE); 780 781 /* otherwise compare hosts (but be careful for NULL ptrs) */ 782 if (a->q_host == NULL || b->q_host == NULL) 783 return (FALSE); 784 if (strcmp(a->q_host, b->q_host) != 0) 785 return (FALSE); 786 787 return (TRUE); 788 } 789 /* 790 ** PRINTADDR -- print address (for debugging) 791 ** 792 ** Parameters: 793 ** a -- the address to print 794 ** follow -- follow the q_next chain. 795 ** 796 ** Returns: 797 ** none. 798 ** 799 ** Side Effects: 800 ** none. 801 */ 802 803 # ifdef DEBUG 804 805 printaddr(a, follow) 806 register ADDRESS *a; 807 bool follow; 808 { 809 bool first = TRUE; 810 811 while (a != NULL) 812 { 813 first = FALSE; 814 printf("%x=", a); 815 (void) fflush(stdout); 816 printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 817 a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, a->q_user); 818 printf("\tnext=%x, flags=%o, rmailer %d, alias %x\n", a->q_next, 819 a->q_flags, a->q_rmailer, a->q_alias); 820 printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, a->q_fullname); 821 822 if (!follow) 823 return; 824 a = a->q_next; 825 } 826 if (first) 827 printf("[NULL]\n"); 828 } 829 830 # endif DEBUG 831 /* 832 ** REMOTENAME -- return the name relative to the current mailer 833 ** 834 ** Parameters: 835 ** name -- the name to translate. 836 ** force -- if set, forces rewriting even if the mailer 837 ** does not request it. Used for rewriting 838 ** sender addresses. 839 ** 840 ** Returns: 841 ** the text string representing this address relative to 842 ** the receiving mailer. 843 ** 844 ** Side Effects: 845 ** none. 846 ** 847 ** Warnings: 848 ** The text string returned is tucked away locally; 849 ** copy it if you intend to save it. 850 */ 851 852 char * 853 remotename(name, m, force) 854 char *name; 855 struct mailer *m; 856 bool force; 857 { 858 static char buf[MAXNAME]; 859 char lbuf[MAXNAME]; 860 extern char *macvalue(); 861 char *oldf = macvalue('f'); 862 char *oldx = macvalue('x'); 863 char *oldg = macvalue('g'); 864 extern char **prescan(); 865 register char **pvp; 866 extern char *getxpart(); 867 extern ADDRESS *buildaddr(); 868 869 # ifdef DEBUG 870 if (tTd(12, 1)) 871 printf("remotename(%s)\n", name); 872 # endif DEBUG 873 874 /* 875 ** See if this mailer wants the name to be rewritten. There are 876 ** many problems here, owing to the standards for doing replies. 877 ** In general, these names should only be rewritten if we are 878 ** sending to another host that runs sendmail. 879 */ 880 881 if (!bitset(M_RELRCPT, m->m_flags) && !force) 882 { 883 # ifdef DEBUG 884 if (tTd(12, 1)) 885 printf("remotename [ditto]\n"); 886 # endif DEBUG 887 return (name); 888 } 889 890 /* 891 ** Do general rewriting of name. 892 ** This will also take care of doing global name translation. 893 */ 894 895 define('x', getxpart(name)); 896 pvp = prescan(name, '\0'); 897 if (pvp == NULL) 898 return (name); 899 rewrite(pvp, 1); 900 rewrite(pvp, 3); 901 if (**pvp == CANONNET) 902 { 903 /* oops... resolved to something */ 904 return (name); 905 } 906 cataddr(pvp, lbuf, sizeof lbuf); 907 908 /* make the name relative to the receiving mailer */ 909 define('f', lbuf); 910 expand(m->m_from, buf, &buf[sizeof buf - 1], CurEnv); 911 912 /* rewrite to get rid of garbage we added in the expand above */ 913 pvp = prescan(buf, '\0'); 914 if (pvp == NULL) 915 return (name); 916 rewrite(pvp, 2); 917 cataddr(pvp, lbuf, sizeof lbuf); 918 919 /* now add any comment info we had before back */ 920 define('g', lbuf); 921 expand("$q", buf, &buf[sizeof buf - 1], CurEnv); 922 923 define('f', oldf); 924 define('g', oldg); 925 define('x', oldx); 926 927 # ifdef DEBUG 928 if (tTd(12, 1)) 929 printf("remotename => `%s'\n", buf); 930 # endif DEBUG 931 return (buf); 932 } 933 /* 934 ** CANONNAME -- make name canonical 935 ** 936 ** This is used for SMTP and misc. printing. Given a print 937 ** address, it strips out comments, etc., and puts on exactly 938 ** one set of brackets. 939 ** 940 ** Parameters: 941 ** name -- the name to make canonical. 942 ** 943 ** Returns: 944 ** pointer to canonical name. 945 ** 946 ** Side Effects: 947 ** none. 948 ** 949 ** Warning: 950 ** result is saved in static buf; future calls will trash it. 951 */ 952 953 char * 954 canonname(name) 955 char *name; 956 { 957 static char nbuf[MAXNAME + 2]; 958 959 if (name[0] == '<') 960 return (name); 961 strcpy(nbuf, "<"); 962 strcat(nbuf, name); 963 strcat(nbuf, ">"); 964 return (nbuf); 965 } 966