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