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