|
|
1.1 root 1: /*
2: **
3: ** Resolve.c
4: **
5: ** Routes then resolves addresses into UUCP or LOCAL.
6: **
7: */
8: #ifndef lint
9: static char *sccsid="@(#)resolve.c 2.5 (smail) 9/15/87";
10: #endif
11:
12: #include <ctype.h>
13: #include <stdio.h>
14: #include "defs.h"
15:
16: extern int exitstat; /* set if address doesn't resolve */
17: extern enum ehandle handle; /* what mail we can handle */
18: extern enum edebug debug; /* verbose and debug modes */
19: extern enum erouting routing; /* when to route addresses */
20: extern char hostdomain[]; /* */
21: extern char hostname[]; /* */
22: extern char *pathfile; /* location of path database */
23: extern int getcost; /* get path cost even if not routing */
24:
25: char *sform();
26:
27: /*
28: **
29: ** rsvp(): how to resolve addresses.
30: **
31: ** After parsing an address into <form>, the resolved form will be
32: ** rsvp( form ). If == ROUTE, we route the parsed address and parse again.
33: **
34: */
35:
36: # define rsvp(a) table[(int)a][(int)handle]
37:
38: enum eform table[5][3] = {
39: /* all justuucp none */
40: { ERROR, ERROR, ERROR }, /* error */
41: { LOCAL, LOCAL, LOCAL }, /* local */
42: { ROUTE, LOCAL, LOCAL }, /* domain */
43: { UUCP, UUCP, LOCAL }, /* uucp */
44: { ERROR, ERROR, ERROR }}; /* route */
45:
46: /*
47: **
48: ** resolve(): resolve addresses to <host, user, form>.
49: **
50: ** This is a gnarly piece of code, but it does it all. Each section
51: ** is documented.
52: **
53: */
54:
55: enum eform
56: resolve( address, domain, user , cost)
57: char *address; /* the input address */
58: char *domain; /* the returned domain */
59: char *user; /* the returned user */
60: int *cost; /* the returned cost */
61: {
62: enum eform form; /* the returned form */
63: enum eform parse(); /* to crack addresses */
64: int parts; /* to ssplit addresses */
65: char *partv[MAXPATH]; /* " " " */
66: char temp[SMLBUF]; /* " " " */
67: int i;
68:
69:
70: /*
71: ** If we set REROUTE and are prepared to deliver UUCP mail, we split the
72: ** address apart at !'s and try to resolve successively larger righthand
73: ** substrings until we succeed. Otherwise, we just resolve the whole thing
74: ** once.
75: */
76: if ((routing == REROUTE) && (rsvp( UUCP ) == UUCP)) {
77: parts = ssplit( address, '!', partv );
78: } else {
79: parts = 1;
80: partv[0] = address;
81: }
82: /*
83: ** This for(i) loop selects successively larger
84: ** righthand substrings of the address.
85: */
86: for( i = parts - 1; i >= 0; i-- ) {
87: /*
88: ** Parse the address.
89: */
90: (void) strcpy( temp, partv[i] );
91: form = parse( temp, domain, user );
92:
93: DEBUG("resolve: parse address '%s' = '%s' @ '%s' (%s)\n",
94: temp,user,domain,sform(form));
95:
96: /*
97: ** If we are looking at a substring (that's not the entire string)
98: ** which parses to a LOCAL address, we skip to the next larger substring.
99: */
100: if((i != 0) && (form == LOCAL))
101: continue;
102: /*
103: ** Routing, when required, is the next step.
104: ** We route the address if we have a ROUTE form
105: ** or if we have a UUCP form and we are told to
106: ** route ALWAYS or REROUTE (i.e., routing != JUSTDOMAIN)
107: */
108: if((rsvp( form ) == ROUTE)
109: ||((rsvp( form ) == UUCP) && (routing != JUSTDOMAIN ))) {
110:
111: int look_smart = 0;
112:
113: if((routing == REROUTE) && (i == 0)) {
114: look_smart = 1; /* last chance */
115: }
116:
117: DEBUG("route(dom: '%s', user: '%s', smart: %d ...)\n",
118: domain, user, look_smart);
119: /* route() puts the new route in 'temp' */
120: if(route(domain,user,look_smart,temp,cost) != EX_OK) {
121: continue; /* If routing fails, try
122: /* next larger substring.
123: /* */
124: }
125: /*
126: ** After routing, reparse the new route into domain and user.
127: */
128: form = parse( temp, domain, user );
129:
130: DEBUG("resolve: parse route '%s' = '%s' @ '%s' (%s)\n",
131: temp,user,domain,sform(form));
132:
133: } else if((getcost) && (rsvp(form) == UUCP)) {
134: /* get the cost of the route
135: ** even if we're not going route the mail.
136: ** this allows smart decisions about using
137: ** the -r flag to uux when we're not routing.
138: */
139: char junk[SMLBUF];
140: if(route(domain,user,0,junk,cost) != EX_OK) {
141: continue; /* If routing fails, try
142: /* next larger substring.
143: /* */
144: }
145: }
146: break; /* route is resolved */
147: }
148: /*
149: ** For LOCAL mail in non-local format, we rewrite the full address into
150: ** <user> and leave <domain> blank.
151: */
152: if ((rsvp( form ) == LOCAL) && (form != LOCAL )) {
153: build( domain, user, form, temp );
154: (void) strcpy( user, temp );
155: (void) strcpy( domain, "" );
156: form = LOCAL;
157: }
158: /*
159: ** If we were supposed to route an address but failed (form == ERROR),
160: ** or after routing we are left with an address that still needs to
161: ** be routed (rsvp( form ) == ROUTE), complain.
162: */
163: if ((form == ERROR) || (rsvp( form ) == ROUTE )) {
164: exitstat = EX_NOHOST;
165: ADVISE("resolve failed '%s' = '%s' @ '%s' (%s)\n",
166: address, user, domain, sform(form));
167: form = ERROR;
168: } else {
169: ADVISE("resolve '%s' = '%s' @ '%s' (%s)\n",
170: address, user, domain, sform(form));
171: }
172: return ( form );
173: }
174:
175: /*
176: **
177: ** route(): route domain, plug in user.
178: **
179: ** Less complicated than it looks. Each section is documented.
180: **
181: */
182:
183: route(domain, user, look_smart, result, cost)
184: char *domain; /* domain or host name */
185: char *user; /* user name */
186: int look_smart; /* do we try to route through a smarter host? */
187: char *result; /* output route */
188: int *cost; /* cost of output route */
189: {
190: int uucpdom = 0;
191: int domains, step; /* to split domain */
192: char *domainv[MAXDOMS]; /* " " " */
193: char temp[SMLBUF], path[SMLBUF];
194: char *tdom;
195:
196: /*
197: ** Fully qualify the domain, and then strip the last (top level domain)
198: ** component off, so that we look it up separately.
199: */
200: temp[0] = '.';
201: (void) strcpy(temp+1, domain );
202:
203: domains = ssplit( temp+1, '.', domainv );
204:
205: /*
206: ** check target domain for the local host name and host domain.
207: ** if it matches, then skip the lookup in the database.
208: ** this prevents mail loops for cases where SMARTHOST is defined
209: ** in the routing table, but the local host is not. It also is
210: ** a little faster when the local host is the target domain.
211: */
212: if((strcmpic(domain, hostname) == 0)
213: || (strcmpic(domain, hostdomain) == 0)) {
214: step = 0;
215: *cost = 0;
216: (void) strcpy(path, "%s");
217: DEBUG("route: '%s' is local\n", domain);
218: goto route_complete;
219: }
220:
221: /* If the domain ends in .UUCP, trim that off. */
222: if((domains > 0) && isuucp(domainv[domains-1])) {
223: domains--;
224: domainv[domains][-1] = '\0';
225: uucpdom = 1;
226: }
227: /*
228: ** Try to get the path for successive components of the domain.
229: ** Example for osgd.cb.att.uucp:
230: ** osgd.cb.att
231: ** cb.att
232: ** att
233: ** uucp ( remember stripping top level? )
234: ** SMARTHOST
235: ** Returns with error if we find no path.
236: */
237: for(step = 0; (step < domains); step++) {
238: if((getpath(domainv[step]-1, path, cost) == EX_OK) /* w/ dot */
239: || (getpath(domainv[step] , path, cost) == EX_OK))/* no dot */
240: break;
241: }
242:
243: if(step == domains) {
244: /*
245: ** we've looked at each component of the domain without success
246: */
247: /*
248: ** If domain is a UUCP address, look for a UUCP gateway.
249: */
250: if((uucpdom == 0) || (getpath(".UUCP", path, cost) != EX_OK)) {
251: /*
252: ** The domain not is a UUCP address, or we can't
253: ** find a UUCP gateway. If this is our last chance,
254: ** look for a smarter host to deliver the mail.
255: */
256: if((look_smart == 0)
257: || (getpath(SMARTHOST, path, cost) != EX_OK)) {
258: /*
259: ** All our efforts have been in vain.
260: ** Tell them the bad news.
261: */
262: DEBUG("route '%s' failed\n", domain);
263: return( EX_NOHOST );
264: }
265: }
266: }
267:
268: route_complete:
269:
270: DEBUG("route: '%s' (%s) = '%s' (%d)\n", domain, domainv[step]?domainv[step]:"NULL", path, *cost);
271:
272: /*
273: ** If we matched on the entire domain name, this address is fully resolved,
274: ** and we plug <user> into it. If we matched on only part of the domain
275: ** name, we plug <domain>!<user> in.
276: */
277: if ((strcmp(path,"%s")) == 0 && (step != 0))
278: {
279: /*
280: ** part of the right-hand side of the entire domain name has
281: ** been matched. This portion needs to be stripped out, and
282: ** the remainder of the left-hand side needs to be used in
283: ** building up the address to which the mail will be delivered.
284: **
285: ** The right-hand portion to be stripped off is contained in
286: ** domainv[step]-1.
287: */
288: for (tdom = domain; strcmp(tdom,domainv[step]-1) != 0; tdom++);
289:
290: *tdom = '\0';
291:
292: }
293: build(domain, user, (step == 0) ? LOCAL : UUCP, temp);
294: (void) sprintf(result, path, temp);
295: return( EX_OK );
296: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.