|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Eric P. Allman
3: * Copyright (c) 1988 Regents of the University of California.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms are permitted provided
7: * that: (1) source distributions retain this entire copyright notice and
8: * comment, and (2) distributions including binaries display the following
9: * acknowledgement: ``This product includes software developed by the
10: * University of California, Berkeley and its contributors'' in the
11: * documentation or other materials provided with the distribution and in
12: * all advertising materials mentioning features or use of this software.
13: * Neither the name of the University nor the names of its contributors may
14: * be used to endorse or promote products derived from this software without
15: * specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: */
20:
21: #ifndef lint
22: static char sccsid[] = "@(#)parseaddr.c 5.13 (Berkeley) 6/1/90";
23: #endif /* not lint */
24:
25: # include "sendmail.h"
26:
27: /*
28: ** PARSEADDR -- Parse an address
29: **
30: ** Parses an address and breaks it up into three parts: a
31: ** net to transmit the message on, the host to transmit it
32: ** to, and a user on that host. These are loaded into an
33: ** ADDRESS header with the values squirreled away if necessary.
34: ** The "user" part may not be a real user; the process may
35: ** just reoccur on that machine. For example, on a machine
36: ** with an arpanet connection, the address
37: ** csvax.bill@berkeley
38: ** will break up to a "user" of 'csvax.bill' and a host
39: ** of 'berkeley' -- to be transmitted over the arpanet.
40: **
41: ** Parameters:
42: ** addr -- the address to parse.
43: ** a -- a pointer to the address descriptor buffer.
44: ** If NULL, a header will be created.
45: ** copyf -- determines what shall be copied:
46: ** -1 -- don't copy anything. The printname
47: ** (q_paddr) is just addr, and the
48: ** user & host are allocated internally
49: ** to parse.
50: ** 0 -- copy out the parsed user & host, but
51: ** don't copy the printname.
52: ** +1 -- copy everything.
53: ** delim -- the character to terminate the address, passed
54: ** to prescan.
55: **
56: ** Returns:
57: ** A pointer to the address descriptor header (`a' if
58: ** `a' is non-NULL).
59: ** NULL on error.
60: **
61: ** Side Effects:
62: ** none
63: */
64:
65: /* following delimiters are inherent to the internal algorithms */
66: # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */
67:
68: ADDRESS *
69: parseaddr(addr, a, copyf, delim)
70: char *addr;
71: register ADDRESS *a;
72: int copyf;
73: char delim;
74: {
75: register char **pvp;
76: register struct mailer *m;
77: char pvpbuf[PSBUFSIZE];
78: extern char **prescan();
79: extern ADDRESS *buildaddr();
80:
81: /*
82: ** Initialize and prescan address.
83: */
84:
85: CurEnv->e_to = addr;
86: if (tTd(20, 1))
87: printf("\n--parseaddr(%s)\n", addr);
88:
89: pvp = prescan(addr, delim, pvpbuf);
90: if (pvp == NULL)
91: return (NULL);
92:
93: /*
94: ** Apply rewriting rules.
95: ** Ruleset 0 does basic parsing. It must resolve.
96: */
97:
98: rewrite(pvp, 3);
99: rewrite(pvp, 0);
100:
101: /*
102: ** See if we resolved to a real mailer.
103: */
104:
105: if (pvp[0][0] != CANONNET)
106: {
107: setstat(EX_USAGE);
108: usrerr("cannot resolve name");
109: return (NULL);
110: }
111:
112: /*
113: ** Build canonical address from pvp.
114: */
115:
116: a = buildaddr(pvp, a);
117: if (a == NULL)
118: return (NULL);
119: m = a->q_mailer;
120:
121: /*
122: ** Make local copies of the host & user and then
123: ** transport them out.
124: */
125:
126: if (copyf > 0)
127: {
128: extern char *DelimChar;
129: char savec = *DelimChar;
130:
131: *DelimChar = '\0';
132: a->q_paddr = newstr(addr);
133: *DelimChar = savec;
134: }
135: else
136: a->q_paddr = addr;
137:
138: if (a->q_user == NULL)
139: a->q_user = "";
140: if (a->q_host == NULL)
141: a->q_host = "";
142:
143: if (copyf >= 0)
144: {
145: a->q_host = newstr(a->q_host);
146: if (a->q_user != a->q_paddr)
147: a->q_user = newstr(a->q_user);
148: }
149:
150: /*
151: ** Convert host name to lower case if requested.
152: ** User name will be done later.
153: */
154:
155: if (!bitnset(M_HST_UPPER, m->m_flags))
156: makelower(a->q_host);
157:
158: /*
159: ** Compute return value.
160: */
161:
162: if (tTd(20, 1))
163: {
164: printf("parseaddr-->");
165: printaddr(a, FALSE);
166: }
167:
168: return (a);
169: }
170: /*
171: ** LOWERADDR -- map UPPER->lower case on addresses as requested.
172: **
173: ** Parameters:
174: ** a -- address to be mapped.
175: **
176: ** Returns:
177: ** none.
178: **
179: ** Side Effects:
180: ** none.
181: */
182:
183: loweraddr(a)
184: register ADDRESS *a;
185: {
186: register MAILER *m = a->q_mailer;
187:
188: if (!bitnset(M_USR_UPPER, m->m_flags))
189: makelower(a->q_user);
190: }
191: /*
192: ** PRESCAN -- Prescan name and make it canonical
193: **
194: ** Scans a name and turns it into a set of tokens. This process
195: ** deletes blanks and comments (in parentheses).
196: **
197: ** This routine knows about quoted strings and angle brackets.
198: **
199: ** There are certain subtleties to this routine. The one that
200: ** comes to mind now is that backslashes on the ends of names
201: ** are silently stripped off; this is intentional. The problem
202: ** is that some versions of sndmsg (like at LBL) set the kill
203: ** character to something other than @ when reading addresses;
204: ** so people type "csvax.eric\@berkeley" -- which screws up the
205: ** berknet mailer.
206: **
207: ** Parameters:
208: ** addr -- the name to chomp.
209: ** delim -- the delimiter for the address, normally
210: ** '\0' or ','; \0 is accepted in any case.
211: ** If '\t' then we are reading the .cf file.
212: ** pvpbuf -- place to put the saved text -- note that
213: ** the pointers are static.
214: **
215: ** Returns:
216: ** A pointer to a vector of tokens.
217: ** NULL on error.
218: **
219: ** Side Effects:
220: ** sets DelimChar to point to the character matching 'delim'.
221: */
222:
223: /* states and character types */
224: # define OPR 0 /* operator */
225: # define ATM 1 /* atom */
226: # define QST 2 /* in quoted string */
227: # define SPC 3 /* chewing up spaces */
228: # define ONE 4 /* pick up one character */
229:
230: # define NSTATES 5 /* number of states */
231: # define TYPE 017 /* mask to select state type */
232:
233: /* meta bits for table */
234: # define M 020 /* meta character; don't pass through */
235: # define B 040 /* cause a break */
236: # define MB M|B /* meta-break */
237:
238: static short StateTab[NSTATES][NSTATES] =
239: {
240: /* oldst chtype> OPR ATM QST SPC ONE */
241: /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B,
242: /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B,
243: /*QST*/ QST, QST, OPR, QST, QST,
244: /*SPC*/ OPR, ATM, QST, SPC|M, ONE,
245: /*ONE*/ OPR, OPR, OPR, OPR, OPR,
246: };
247:
248: # define NOCHAR -1 /* signal nothing in lookahead token */
249:
250: char *DelimChar; /* set to point to the delimiter */
251:
252: char **
253: prescan(addr, delim, pvpbuf)
254: char *addr;
255: char delim;
256: char pvpbuf[];
257: {
258: register char *p;
259: register char *q;
260: register int c;
261: char **avp;
262: bool bslashmode;
263: int cmntcnt;
264: int anglecnt;
265: char *tok;
266: int state;
267: int newstate;
268: static char *av[MAXATOM+1];
269: extern int errno;
270:
271: /* make sure error messages don't have garbage on them */
272: errno = 0;
273:
274: q = pvpbuf;
275: bslashmode = FALSE;
276: cmntcnt = 0;
277: anglecnt = 0;
278: avp = av;
279: state = OPR;
280: c = NOCHAR;
281: p = addr;
282: if (tTd(22, 45))
283: {
284: printf("prescan: ");
285: xputs(p);
286: (void) putchar('\n');
287: }
288:
289: do
290: {
291: /* read a token */
292: tok = q;
293: for (;;)
294: {
295: /* store away any old lookahead character */
296: if (c != NOCHAR)
297: {
298: /* see if there is room */
299: if (q >= &pvpbuf[PSBUFSIZE - 5])
300: {
301: usrerr("Address too long");
302: DelimChar = p;
303: return (NULL);
304: }
305:
306: /* squirrel it away */
307: *q++ = c;
308: }
309:
310: /* read a new input character */
311: c = *p++;
312: if (c == '\0')
313: break;
314: c &= ~0200;
315:
316: if (tTd(22, 101))
317: printf("c=%c, s=%d; ", c, state);
318:
319: /* chew up special characters */
320: *q = '\0';
321: if (bslashmode)
322: {
323: /* kludge \! for naive users */
324: if (c != '!')
325: c |= 0200;
326: bslashmode = FALSE;
327: }
328: else if (c == '\\')
329: {
330: bslashmode = TRUE;
331: c = NOCHAR;
332: }
333: else if (state == QST)
334: {
335: /* do nothing, just avoid next clauses */
336: }
337: else if (c == '(')
338: {
339: cmntcnt++;
340: c = NOCHAR;
341: }
342: else if (c == ')')
343: {
344: if (cmntcnt <= 0)
345: {
346: usrerr("Unbalanced ')'");
347: DelimChar = p;
348: return (NULL);
349: }
350: else
351: cmntcnt--;
352: }
353: else if (cmntcnt > 0)
354: c = NOCHAR;
355: else if (c == '<')
356: anglecnt++;
357: else if (c == '>')
358: {
359: if (anglecnt <= 0)
360: {
361: usrerr("Unbalanced '>'");
362: DelimChar = p;
363: return (NULL);
364: }
365: anglecnt--;
366: }
367: else if (delim == ' ' && isspace(c))
368: c = ' ';
369:
370: if (c == NOCHAR)
371: continue;
372:
373: /* see if this is end of input */
374: if (c == delim && anglecnt <= 0 && state != QST)
375: break;
376:
377: newstate = StateTab[state][toktype(c)];
378: if (tTd(22, 101))
379: printf("ns=%02o\n", newstate);
380: state = newstate & TYPE;
381: if (bitset(M, newstate))
382: c = NOCHAR;
383: if (bitset(B, newstate))
384: break;
385: }
386:
387: /* new token */
388: if (tok != q)
389: {
390: *q++ = '\0';
391: if (tTd(22, 36))
392: {
393: printf("tok=");
394: xputs(tok);
395: (void) putchar('\n');
396: }
397: if (avp >= &av[MAXATOM])
398: {
399: syserr("prescan: too many tokens");
400: DelimChar = p;
401: return (NULL);
402: }
403: *avp++ = tok;
404: }
405: } while (c != '\0' && (c != delim || anglecnt > 0));
406: *avp = NULL;
407: DelimChar = --p;
408: if (cmntcnt > 0)
409: usrerr("Unbalanced '('");
410: else if (anglecnt > 0)
411: usrerr("Unbalanced '<'");
412: else if (state == QST)
413: usrerr("Unbalanced '\"'");
414: else if (av[0] != NULL)
415: return (av);
416: return (NULL);
417: }
418: /*
419: ** TOKTYPE -- return token type
420: **
421: ** Parameters:
422: ** c -- the character in question.
423: **
424: ** Returns:
425: ** Its type.
426: **
427: ** Side Effects:
428: ** none.
429: */
430:
431: toktype(c)
432: register char c;
433: {
434: static char buf[50];
435: static bool firstime = TRUE;
436:
437: if (firstime)
438: {
439: firstime = FALSE;
440: expand("\001o", buf, &buf[sizeof buf - 1], CurEnv);
441: (void) strcat(buf, DELIMCHARS);
442: }
443: if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)
444: return (ONE);
445: if (c == '"')
446: return (QST);
447: if (!isascii(c))
448: return (ATM);
449: if (isspace(c) || c == ')')
450: return (SPC);
451: if (iscntrl(c) || index(buf, c) != NULL)
452: return (OPR);
453: return (ATM);
454: }
455: /*
456: ** REWRITE -- apply rewrite rules to token vector.
457: **
458: ** This routine is an ordered production system. Each rewrite
459: ** rule has a LHS (called the pattern) and a RHS (called the
460: ** rewrite); 'rwr' points the the current rewrite rule.
461: **
462: ** For each rewrite rule, 'avp' points the address vector we
463: ** are trying to match against, and 'pvp' points to the pattern.
464: ** If pvp points to a special match value (MATCHZANY, MATCHANY,
465: ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
466: ** matched is saved away in the match vector (pointed to by 'mvp').
467: **
468: ** When a match between avp & pvp does not match, we try to
469: ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
470: ** we must also back out the match in mvp. If we reach a
471: ** MATCHANY or MATCHZANY we just extend the match and start
472: ** over again.
473: **
474: ** When we finally match, we rewrite the address vector
475: ** and try over again.
476: **
477: ** Parameters:
478: ** pvp -- pointer to token vector.
479: **
480: ** Returns:
481: ** none.
482: **
483: ** Side Effects:
484: ** pvp is modified.
485: */
486:
487: struct match
488: {
489: char **first; /* first token matched */
490: char **last; /* last token matched */
491: };
492:
493: # define MAXMATCH 9 /* max params per rewrite */
494:
495:
496: rewrite(pvp, ruleset)
497: char **pvp;
498: int ruleset;
499: {
500: register char *ap; /* address pointer */
501: register char *rp; /* rewrite pointer */
502: register char **avp; /* address vector pointer */
503: register char **rvp; /* rewrite vector pointer */
504: register struct match *mlp; /* cur ptr into mlist */
505: register struct rewrite *rwr; /* pointer to current rewrite rule */
506: struct match mlist[MAXMATCH]; /* stores match on LHS */
507: char *npvp[MAXATOM+1]; /* temporary space for rebuild */
508:
509: if (OpMode == MD_TEST || tTd(21, 2))
510: {
511: printf("rewrite: ruleset %2d input:", ruleset);
512: printav(pvp);
513: }
514: if (pvp == NULL)
515: return;
516:
517: /*
518: ** Run through the list of rewrite rules, applying
519: ** any that match.
520: */
521:
522: for (rwr = RewriteRules[ruleset]; rwr != NULL; )
523: {
524: if (tTd(21, 12))
525: {
526: printf("-----trying rule:");
527: printav(rwr->r_lhs);
528: }
529:
530: /* try to match on this rule */
531: mlp = mlist;
532: rvp = rwr->r_lhs;
533: avp = pvp;
534: while ((ap = *avp) != NULL || *rvp != NULL)
535: {
536: rp = *rvp;
537: if (tTd(21, 35))
538: {
539: printf("ap=");
540: xputs(ap);
541: printf(", rp=");
542: xputs(rp);
543: printf("\n");
544: }
545: if (rp == NULL)
546: {
547: /* end-of-pattern before end-of-address */
548: goto backup;
549: }
550: if (ap == NULL && *rp != MATCHZANY)
551: {
552: /* end-of-input */
553: break;
554: }
555:
556: switch (*rp)
557: {
558: register STAB *s;
559:
560: case MATCHCLASS:
561: case MATCHNCLASS:
562: /* match any token in (not in) a class */
563: s = stab(ap, ST_CLASS, ST_FIND);
564: if (s == NULL || !bitnset(rp[1], s->s_class))
565: {
566: if (*rp == MATCHCLASS)
567: goto backup;
568: }
569: else if (*rp == MATCHNCLASS)
570: goto backup;
571:
572: /* explicit fall-through */
573:
574: case MATCHONE:
575: case MATCHANY:
576: /* match exactly one token */
577: mlp->first = avp;
578: mlp->last = avp++;
579: mlp++;
580: break;
581:
582: case MATCHZANY:
583: /* match zero or more tokens */
584: mlp->first = avp;
585: mlp->last = avp - 1;
586: mlp++;
587: break;
588:
589: default:
590: /* must have exact match */
591: if (strcasecmp(rp, ap))
592: goto backup;
593: avp++;
594: break;
595: }
596:
597: /* successful match on this token */
598: rvp++;
599: continue;
600:
601: backup:
602: /* match failed -- back up */
603: while (--rvp >= rwr->r_lhs)
604: {
605: rp = *rvp;
606: if (*rp == MATCHANY || *rp == MATCHZANY)
607: {
608: /* extend binding and continue */
609: avp = ++mlp[-1].last;
610: avp++;
611: rvp++;
612: break;
613: }
614: avp--;
615: if (*rp == MATCHONE || *rp == MATCHCLASS ||
616: *rp == MATCHNCLASS)
617: {
618: /* back out binding */
619: mlp--;
620: }
621: }
622:
623: if (rvp < rwr->r_lhs)
624: {
625: /* total failure to match */
626: break;
627: }
628: }
629:
630: /*
631: ** See if we successfully matched
632: */
633:
634: if (rvp < rwr->r_lhs || *rvp != NULL)
635: {
636: if (tTd(21, 10))
637: printf("----- rule fails\n");
638: rwr = rwr->r_next;
639: continue;
640: }
641:
642: rvp = rwr->r_rhs;
643: if (tTd(21, 12))
644: {
645: printf("-----rule matches:");
646: printav(rvp);
647: }
648:
649: rp = *rvp;
650: if (*rp == CANONUSER)
651: {
652: rvp++;
653: rwr = rwr->r_next;
654: }
655: else if (*rp == CANONHOST)
656: {
657: rvp++;
658: rwr = NULL;
659: }
660: else if (*rp == CANONNET)
661: rwr = NULL;
662:
663: /* substitute */
664: for (avp = npvp; *rvp != NULL; rvp++)
665: {
666: register struct match *m;
667: register char **pp;
668:
669: rp = *rvp;
670: if (*rp == MATCHREPL)
671: {
672: /* substitute from LHS */
673: m = &mlist[rp[1] - '1'];
674: if (m >= mlp)
675: {
676: syserr("rewrite: ruleset %d: replacement out of bounds", ruleset);
677: return;
678: }
679: if (tTd(21, 15))
680: {
681: printf("$%c:", rp[1]);
682: pp = m->first;
683: while (pp <= m->last)
684: {
685: printf(" %x=\"", *pp);
686: (void) fflush(stdout);
687: printf("%s\"", *pp++);
688: }
689: printf("\n");
690: }
691: pp = m->first;
692: while (pp <= m->last)
693: {
694: if (avp >= &npvp[MAXATOM])
695: {
696: syserr("rewrite: expansion too long");
697: return;
698: }
699: *avp++ = *pp++;
700: }
701: }
702: else
703: {
704: /* vanilla replacement */
705: if (avp >= &npvp[MAXATOM])
706: {
707: toolong:
708: syserr("rewrite: expansion too long");
709: return;
710: }
711: *avp++ = rp;
712: }
713: }
714: *avp++ = NULL;
715:
716: /*
717: ** Check for any hostname lookups.
718: */
719:
720: for (rvp = npvp; *rvp != NULL; rvp++)
721: {
722: char **hbrvp;
723: char **xpvp;
724: int trsize;
725: char *olddelimchar;
726: char buf[MAXNAME + 1];
727: char *pvpb1[MAXATOM + 1];
728: char pvpbuf[PSBUFSIZE];
729: extern char *DelimChar;
730:
731: if (**rvp != HOSTBEGIN)
732: continue;
733:
734: /*
735: ** Got a hostname lookup.
736: **
737: ** This could be optimized fairly easily.
738: */
739:
740: hbrvp = rvp;
741:
742: /* extract the match part */
743: while (*++rvp != NULL && **rvp != HOSTEND)
744: continue;
745: if (*rvp != NULL)
746: *rvp++ = NULL;
747:
748: /* save the remainder of the input string */
749: trsize = (int) (avp - rvp + 1) * sizeof *rvp;
750: bcopy((char *) rvp, (char *) pvpb1, trsize);
751:
752: /* look it up */
753: cataddr(++hbrvp, buf, sizeof buf);
754: maphostname(buf, sizeof buf);
755:
756: /* scan the new host name */
757: olddelimchar = DelimChar;
758: xpvp = prescan(buf, '\0', pvpbuf);
759: DelimChar = olddelimchar;
760: if (xpvp == NULL)
761: {
762: syserr("rewrite: cannot prescan canonical hostname: %s", buf);
763: return;
764: }
765:
766: /* append it to the token list */
767: for (avp = --hbrvp; *xpvp != NULL; xpvp++)
768: {
769: *avp++ = newstr(*xpvp);
770: if (avp >= &npvp[MAXATOM])
771: goto toolong;
772: }
773:
774: /* restore the old trailing information */
775: for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
776: if (avp >= &npvp[MAXATOM])
777: goto toolong;
778:
779: break;
780: }
781:
782: /*
783: ** Check for subroutine calls.
784: */
785:
786: if (*npvp != NULL && **npvp == CALLSUBR)
787: {
788: bcopy((char *) &npvp[2], (char *) pvp,
789: (int) (avp - npvp - 2) * sizeof *avp);
790: if (tTd(21, 3))
791: printf("-----callsubr %s\n", npvp[1]);
792: rewrite(pvp, atoi(npvp[1]));
793: }
794: else
795: {
796: bcopy((char *) npvp, (char *) pvp,
797: (int) (avp - npvp) * sizeof *avp);
798: }
799: if (tTd(21, 4))
800: {
801: printf("rewritten as:");
802: printav(pvp);
803: }
804: }
805:
806: if (OpMode == MD_TEST || tTd(21, 2))
807: {
808: printf("rewrite: ruleset %2d returns:", ruleset);
809: printav(pvp);
810: }
811: }
812: /*
813: ** BUILDADDR -- build address from token vector.
814: **
815: ** Parameters:
816: ** tv -- token vector.
817: ** a -- pointer to address descriptor to fill.
818: ** If NULL, one will be allocated.
819: **
820: ** Returns:
821: ** NULL if there was an error.
822: ** 'a' otherwise.
823: **
824: ** Side Effects:
825: ** fills in 'a'
826: */
827:
828: ADDRESS *
829: buildaddr(tv, a)
830: register char **tv;
831: register ADDRESS *a;
832: {
833: static char buf[MAXNAME];
834: struct mailer **mp;
835: register struct mailer *m;
836:
837: if (a == NULL)
838: a = (ADDRESS *) xalloc(sizeof *a);
839: bzero((char *) a, sizeof *a);
840:
841: /* figure out what net/mailer to use */
842: if (**tv != CANONNET)
843: {
844: syserr("buildaddr: no net");
845: return (NULL);
846: }
847: tv++;
848: if (!strcasecmp(*tv, "error"))
849: {
850: if (**++tv == CANONHOST)
851: {
852: setstat(atoi(*++tv));
853: tv++;
854: }
855: if (**tv != CANONUSER)
856: syserr("buildaddr: error: no user");
857: buf[0] = '\0';
858: while (*++tv != NULL)
859: {
860: if (buf[0] != '\0')
861: (void) strcat(buf, " ");
862: (void) strcat(buf, *tv);
863: }
864: usrerr(buf);
865: return (NULL);
866: }
867: for (mp = Mailer; (m = *mp++) != NULL; )
868: {
869: if (!strcasecmp(m->m_name, *tv))
870: break;
871: }
872: if (m == NULL)
873: {
874: syserr("buildaddr: unknown mailer %s", *tv);
875: return (NULL);
876: }
877: a->q_mailer = m;
878:
879: /* figure out what host (if any) */
880: tv++;
881: if (!bitnset(M_LOCAL, m->m_flags))
882: {
883: if (**tv++ != CANONHOST)
884: {
885: syserr("buildaddr: no host");
886: return (NULL);
887: }
888: buf[0] = '\0';
889: while (*tv != NULL && **tv != CANONUSER)
890: (void) strcat(buf, *tv++);
891: a->q_host = newstr(buf);
892: }
893: else
894: a->q_host = NULL;
895:
896: /* figure out the user */
897: if (*tv == NULL || **tv != CANONUSER)
898: {
899: syserr("buildaddr: no user");
900: return (NULL);
901: }
902:
903: /* rewrite according recipient mailer rewriting rules */
904: rewrite(++tv, 2);
905: if (m->m_r_rwset > 0)
906: rewrite(tv, m->m_r_rwset);
907: rewrite(tv, 4);
908:
909: /* save the result for the command line/RCPT argument */
910: cataddr(tv, buf, sizeof buf);
911: a->q_user = buf;
912:
913: return (a);
914: }
915: /*
916: ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
917: **
918: ** Parameters:
919: ** pvp -- parameter vector to rebuild.
920: ** buf -- buffer to build the string into.
921: ** sz -- size of buf.
922: **
923: ** Returns:
924: ** none.
925: **
926: ** Side Effects:
927: ** Destroys buf.
928: */
929:
930: cataddr(pvp, buf, sz)
931: char **pvp;
932: char *buf;
933: register int sz;
934: {
935: bool oatomtok = FALSE;
936: bool natomtok = FALSE;
937: register int i;
938: register char *p;
939:
940: if (pvp == NULL)
941: {
942: (void) strcpy(buf, "");
943: return;
944: }
945: p = buf;
946: sz -= 2;
947: while (*pvp != NULL && (i = strlen(*pvp)) < sz)
948: {
949: natomtok = (toktype(**pvp) == ATM);
950: if (oatomtok && natomtok)
951: *p++ = SpaceSub;
952: (void) strcpy(p, *pvp);
953: oatomtok = natomtok;
954: p += i;
955: sz -= i + 1;
956: pvp++;
957: }
958: *p = '\0';
959: }
960: /*
961: ** SAMEADDR -- Determine if two addresses are the same
962: **
963: ** This is not just a straight comparison -- if the mailer doesn't
964: ** care about the host we just ignore it, etc.
965: **
966: ** Parameters:
967: ** a, b -- pointers to the internal forms to compare.
968: **
969: ** Returns:
970: ** TRUE -- they represent the same mailbox.
971: ** FALSE -- they don't.
972: **
973: ** Side Effects:
974: ** none.
975: */
976:
977: bool
978: sameaddr(a, b)
979: register ADDRESS *a;
980: register ADDRESS *b;
981: {
982: /* if they don't have the same mailer, forget it */
983: if (a->q_mailer != b->q_mailer)
984: return (FALSE);
985:
986: /* if the user isn't the same, we can drop out */
987: if (strcmp(a->q_user, b->q_user) != 0)
988: return (FALSE);
989:
990: /* if the mailer ignores hosts, we have succeeded! */
991: if (bitnset(M_LOCAL, a->q_mailer->m_flags))
992: return (TRUE);
993:
994: /* otherwise compare hosts (but be careful for NULL ptrs) */
995: if (a->q_host == NULL || b->q_host == NULL)
996: return (FALSE);
997: if (strcmp(a->q_host, b->q_host) != 0)
998: return (FALSE);
999:
1000: return (TRUE);
1001: }
1002: /*
1003: ** PRINTADDR -- print address (for debugging)
1004: **
1005: ** Parameters:
1006: ** a -- the address to print
1007: ** follow -- follow the q_next chain.
1008: **
1009: ** Returns:
1010: ** none.
1011: **
1012: ** Side Effects:
1013: ** none.
1014: */
1015:
1016: printaddr(a, follow)
1017: register ADDRESS *a;
1018: bool follow;
1019: {
1020: bool first = TRUE;
1021:
1022: while (a != NULL)
1023: {
1024: first = FALSE;
1025: printf("%x=", a);
1026: (void) fflush(stdout);
1027: printf("%s: mailer %d (%s), host `%s', user `%s', ruser `%s'\n",
1028: a->q_paddr, a->q_mailer->m_mno, a->q_mailer->m_name,
1029: a->q_host, a->q_user, a->q_ruser? a->q_ruser: "<null>");
1030: printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags,
1031: a->q_alias);
1032: printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home,
1033: a->q_fullname);
1034:
1035: if (!follow)
1036: return;
1037: a = a->q_next;
1038: }
1039: if (first)
1040: printf("[NULL]\n");
1041: }
1042:
1043: /*
1044: ** REMOTENAME -- return the name relative to the current mailer
1045: **
1046: ** Parameters:
1047: ** name -- the name to translate.
1048: ** m -- the mailer that we want to do rewriting relative
1049: ** to.
1050: ** senderaddress -- if set, uses the sender rewriting rules
1051: ** rather than the recipient rewriting rules.
1052: ** canonical -- if set, strip out any comment information,
1053: ** etc.
1054: **
1055: ** Returns:
1056: ** the text string representing this address relative to
1057: ** the receiving mailer.
1058: **
1059: ** Side Effects:
1060: ** none.
1061: **
1062: ** Warnings:
1063: ** The text string returned is tucked away locally;
1064: ** copy it if you intend to save it.
1065: */
1066:
1067: char *
1068: remotename(name, m, senderaddress, canonical)
1069: char *name;
1070: struct mailer *m;
1071: bool senderaddress;
1072: bool canonical;
1073: {
1074: register char **pvp;
1075: char *fancy;
1076: extern char *macvalue();
1077: char *oldg = macvalue('g', CurEnv);
1078: static char buf[MAXNAME];
1079: char lbuf[MAXNAME];
1080: char pvpbuf[PSBUFSIZE];
1081: extern char **prescan();
1082: extern char *crackaddr();
1083:
1084: if (tTd(12, 1))
1085: printf("remotename(%s)\n", name);
1086:
1087: /* don't do anything if we are tagging it as special */
1088: if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0)
1089: return (name);
1090:
1091: /*
1092: ** Do a heuristic crack of this name to extract any comment info.
1093: ** This will leave the name as a comment and a $g macro.
1094: */
1095:
1096: if (canonical)
1097: fancy = "\001g";
1098: else
1099: fancy = crackaddr(name);
1100:
1101: /*
1102: ** Turn the name into canonical form.
1103: ** Normally this will be RFC 822 style, i.e., "user@domain".
1104: ** If this only resolves to "user", and the "C" flag is
1105: ** specified in the sending mailer, then the sender's
1106: ** domain will be appended.
1107: */
1108:
1109: pvp = prescan(name, '\0', pvpbuf);
1110: if (pvp == NULL)
1111: return (name);
1112: rewrite(pvp, 3);
1113: if (CurEnv->e_fromdomain != NULL)
1114: {
1115: /* append from domain to this address */
1116: register char **pxp = pvp;
1117:
1118: /* see if there is an "@domain" in the current name */
1119: while (*pxp != NULL && strcmp(*pxp, "@") != 0)
1120: pxp++;
1121: if (*pxp == NULL)
1122: {
1123: /* no.... append the "@domain" from the sender */
1124: register char **qxq = CurEnv->e_fromdomain;
1125:
1126: while ((*pxp++ = *qxq++) != NULL)
1127: continue;
1128: rewrite(pvp, 3);
1129: }
1130: }
1131:
1132: /*
1133: ** Do more specific rewriting.
1134: ** Rewrite using ruleset 1 or 2 depending on whether this is
1135: ** a sender address or not.
1136: ** Then run it through any receiving-mailer-specific rulesets.
1137: */
1138:
1139: if (senderaddress)
1140: {
1141: rewrite(pvp, 1);
1142: if (m->m_s_rwset > 0)
1143: rewrite(pvp, m->m_s_rwset);
1144: }
1145: else
1146: {
1147: rewrite(pvp, 2);
1148: if (m->m_r_rwset > 0)
1149: rewrite(pvp, m->m_r_rwset);
1150: }
1151:
1152: /*
1153: ** Do any final sanitation the address may require.
1154: ** This will normally be used to turn internal forms
1155: ** (e.g., [email protected]) into external form. This
1156: ** may be used as a default to the above rules.
1157: */
1158:
1159: rewrite(pvp, 4);
1160:
1161: /*
1162: ** Now restore the comment information we had at the beginning.
1163: */
1164:
1165: cataddr(pvp, lbuf, sizeof lbuf);
1166: define('g', lbuf, CurEnv);
1167: expand(fancy, buf, &buf[sizeof buf - 1], CurEnv);
1168: define('g', oldg, CurEnv);
1169:
1170: if (tTd(12, 1))
1171: printf("remotename => `%s'\n", buf);
1172: return (buf);
1173: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.