Commit | Line | Data |
---|---|---|
f0e070dc | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
bee79b64 KB |
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 | |
dc45ba8c KB |
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. | |
bee79b64 | 17 | */ |
f0e070dc MAN |
18 | |
19 | #ifndef lint | |
dc45ba8c | 20 | static char sccsid[] = "@(#)parseaddr.c 5.9 (Berkeley) %G%"; |
bee79b64 | 21 | #endif /* not lint */ |
f0e070dc MAN |
22 | |
23 | # include "sendmail.h" | |
916b3375 | 24 | |
b3cbe40f | 25 | /* |
40d27fed | 26 | ** PARSEADDR -- Parse an address |
b3cbe40f EA |
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 | |
406f98bc | 31 | ** ADDRESS header with the values squirreled away if necessary. |
b3cbe40f EA |
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. | |
d3f52e20 EA |
51 | ** delim -- the character to terminate the address, passed |
52 | ** to prescan. | |
b3cbe40f EA |
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 | |
b3cbe40f EA |
61 | */ |
62 | ||
7338e3d4 | 63 | /* following delimiters are inherent to the internal algorithms */ |
a73ae8ac | 64 | # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */ |
ecf90b7d | 65 | |
406f98bc | 66 | ADDRESS * |
d3f52e20 | 67 | parseaddr(addr, a, copyf, delim) |
b3cbe40f | 68 | char *addr; |
406f98bc | 69 | register ADDRESS *a; |
b3cbe40f | 70 | int copyf; |
d3f52e20 | 71 | char delim; |
b3cbe40f | 72 | { |
d6a28dd8 EA |
73 | register char **pvp; |
74 | register struct mailer *m; | |
217a0102 | 75 | char pvpbuf[PSBUFSIZE]; |
d6a28dd8 | 76 | extern char **prescan(); |
d6a28dd8 | 77 | extern ADDRESS *buildaddr(); |
b3cbe40f EA |
78 | |
79 | /* | |
80 | ** Initialize and prescan address. | |
81 | */ | |
82 | ||
2654b031 | 83 | CurEnv->e_to = addr; |
9e3c0a28 | 84 | # ifdef DEBUG |
9678c96d | 85 | if (tTd(20, 1)) |
40d27fed | 86 | printf("\n--parseaddr(%s)\n", addr); |
9e3c0a28 EA |
87 | # endif DEBUG |
88 | ||
217a0102 | 89 | pvp = prescan(addr, delim, pvpbuf); |
d6a28dd8 | 90 | if (pvp == NULL) |
b3cbe40f EA |
91 | return (NULL); |
92 | ||
93 | /* | |
d6a28dd8 | 94 | ** Apply rewriting rules. |
0908f182 | 95 | ** Ruleset 0 does basic parsing. It must resolve. |
b3cbe40f EA |
96 | */ |
97 | ||
857afefe | 98 | rewrite(pvp, 3); |
f65e7ded | 99 | rewrite(pvp, 0); |
b3cbe40f | 100 | |
d6a28dd8 EA |
101 | /* |
102 | ** See if we resolved to a real mailer. | |
103 | */ | |
b3cbe40f | 104 | |
d6a28dd8 EA |
105 | if (pvp[0][0] != CANONNET) |
106 | { | |
107 | setstat(EX_USAGE); | |
108 | usrerr("cannot resolve name"); | |
109 | return (NULL); | |
b3cbe40f EA |
110 | } |
111 | ||
112 | /* | |
d6a28dd8 | 113 | ** Build canonical address from pvp. |
b3cbe40f EA |
114 | */ |
115 | ||
d6a28dd8 | 116 | a = buildaddr(pvp, a); |
fe43b434 EA |
117 | if (a == NULL) |
118 | return (NULL); | |
179c1218 | 119 | m = a->q_mailer; |
b3cbe40f EA |
120 | |
121 | /* | |
d6a28dd8 EA |
122 | ** Make local copies of the host & user and then |
123 | ** transport them out. | |
b3cbe40f EA |
124 | */ |
125 | ||
b3cbe40f | 126 | if (copyf > 0) |
506fc377 EA |
127 | { |
128 | extern char *DelimChar; | |
129 | char savec = *DelimChar; | |
130 | ||
131 | *DelimChar = '\0'; | |
406f98bc | 132 | a->q_paddr = newstr(addr); |
506fc377 EA |
133 | *DelimChar = savec; |
134 | } | |
b3cbe40f EA |
135 | else |
136 | a->q_paddr = addr; | |
2e3062fe EA |
137 | |
138 | if (a->q_user == NULL) | |
139 | a->q_user = ""; | |
140 | if (a->q_host == NULL) | |
141 | a->q_host = ""; | |
142 | ||
d6a28dd8 | 143 | if (copyf >= 0) |
b3cbe40f | 144 | { |
2e3062fe | 145 | a->q_host = newstr(a->q_host); |
d6a28dd8 EA |
146 | if (a->q_user != a->q_paddr) |
147 | a->q_user = newstr(a->q_user); | |
b3cbe40f EA |
148 | } |
149 | ||
1ae66bfb EA |
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 | ||
b3cbe40f EA |
158 | /* |
159 | ** Compute return value. | |
160 | */ | |
161 | ||
162 | # ifdef DEBUG | |
9678c96d | 163 | if (tTd(20, 1)) |
331b7c9f | 164 | { |
40d27fed | 165 | printf("parseaddr-->"); |
331b7c9f EA |
166 | printaddr(a, FALSE); |
167 | } | |
b3cbe40f EA |
168 | # endif DEBUG |
169 | ||
170 | return (a); | |
171 | } | |
172 | \f/* | |
0fe3917f EA |
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 | ||
0fe3917f EA |
190 | if (!bitnset(M_USR_UPPER, m->m_flags)) |
191 | makelower(a->q_user); | |
192 | } | |
193 | \f/* | |
b3cbe40f EA |
194 | ** PRESCAN -- Prescan name and make it canonical |
195 | ** | |
7338e3d4 EA |
196 | ** Scans a name and turns it into a set of tokens. This process |
197 | ** deletes blanks and comments (in parentheses). | |
b3cbe40f EA |
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. | |
b3cbe40f EA |
211 | ** delim -- the delimiter for the address, normally |
212 | ** '\0' or ','; \0 is accepted in any case. | |
f12f79be | 213 | ** If '\t' then we are reading the .cf file. |
217a0102 EA |
214 | ** pvpbuf -- place to put the saved text -- note that |
215 | ** the pointers are static. | |
b3cbe40f EA |
216 | ** |
217 | ** Returns: | |
d6a28dd8 | 218 | ** A pointer to a vector of tokens. |
b3cbe40f EA |
219 | ** NULL on error. |
220 | ** | |
221 | ** Side Effects: | |
3312f93c | 222 | ** sets DelimChar to point to the character matching 'delim'. |
b3cbe40f EA |
223 | */ |
224 | ||
506fc377 EA |
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 | { | |
921e1125 | 242 | /* oldst chtype> OPR ATM QST SPC ONE */ |
1f513630 EA |
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, | |
506fc377 EA |
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 */ | |
d6a28dd8 EA |
253 | |
254 | char ** | |
217a0102 | 255 | prescan(addr, delim, pvpbuf) |
b3cbe40f | 256 | char *addr; |
b3cbe40f | 257 | char delim; |
217a0102 | 258 | char pvpbuf[]; |
b3cbe40f EA |
259 | { |
260 | register char *p; | |
506fc377 | 261 | register char *q; |
611b763d | 262 | register int c; |
d6a28dd8 | 263 | char **avp; |
b3cbe40f EA |
264 | bool bslashmode; |
265 | int cmntcnt; | |
e93460a9 | 266 | int anglecnt; |
d6a28dd8 | 267 | char *tok; |
506fc377 EA |
268 | int state; |
269 | int newstate; | |
506fc377 | 270 | static char *av[MAXATOM+1]; |
15cd119d EA |
271 | extern int errno; |
272 | ||
273 | /* make sure error messages don't have garbage on them */ | |
274 | errno = 0; | |
b3cbe40f | 275 | |
217a0102 | 276 | q = pvpbuf; |
d6a28dd8 | 277 | bslashmode = FALSE; |
43ff8bb5 | 278 | cmntcnt = 0; |
e93460a9 | 279 | anglecnt = 0; |
d6a28dd8 | 280 | avp = av; |
506fc377 EA |
281 | state = OPR; |
282 | c = NOCHAR; | |
283 | p = addr; | |
284 | # ifdef DEBUG | |
285 | if (tTd(22, 45)) | |
286 | { | |
287 | printf("prescan: "); | |
288 | xputs(p); | |
03388044 | 289 | (void) putchar('\n'); |
506fc377 EA |
290 | } |
291 | # endif DEBUG | |
292 | ||
293 | do | |
b3cbe40f | 294 | { |
d6a28dd8 EA |
295 | /* read a token */ |
296 | tok = q; | |
506fc377 | 297 | for (;;) |
b3cbe40f | 298 | { |
506fc377 EA |
299 | /* store away any old lookahead character */ |
300 | if (c != NOCHAR) | |
301 | { | |
f12f79be | 302 | /* see if there is room */ |
217a0102 | 303 | if (q >= &pvpbuf[PSBUFSIZE - 5]) |
506fc377 EA |
304 | { |
305 | usrerr("Address too long"); | |
306 | DelimChar = p; | |
307 | return (NULL); | |
308 | } | |
f12f79be EA |
309 | |
310 | /* squirrel it away */ | |
506fc377 EA |
311 | *q++ = c; |
312 | } | |
313 | ||
314 | /* read a new input character */ | |
315 | c = *p++; | |
316 | if (c == '\0') | |
317 | break; | |
f12f79be EA |
318 | c &= ~0200; |
319 | ||
506fc377 EA |
320 | # ifdef DEBUG |
321 | if (tTd(22, 101)) | |
322 | printf("c=%c, s=%d; ", c, state); | |
323 | # endif DEBUG | |
324 | ||
d6a28dd8 EA |
325 | /* chew up special characters */ |
326 | *q = '\0'; | |
327 | if (bslashmode) | |
328 | { | |
2e3062fe EA |
329 | /* kludge \! for naive users */ |
330 | if (c != '!') | |
331 | c |= 0200; | |
d6a28dd8 EA |
332 | bslashmode = FALSE; |
333 | } | |
334 | else if (c == '\\') | |
335 | { | |
336 | bslashmode = TRUE; | |
506fc377 | 337 | c = NOCHAR; |
d6a28dd8 | 338 | } |
63a35680 EA |
339 | else if (state == QST) |
340 | { | |
341 | /* do nothing, just avoid next clauses */ | |
342 | } | |
506fc377 | 343 | else if (c == '(') |
cdb17311 | 344 | { |
506fc377 EA |
345 | cmntcnt++; |
346 | c = NOCHAR; | |
cdb17311 | 347 | } |
506fc377 | 348 | else if (c == ')') |
d6a28dd8 | 349 | { |
506fc377 | 350 | if (cmntcnt <= 0) |
d6a28dd8 | 351 | { |
506fc377 EA |
352 | usrerr("Unbalanced ')'"); |
353 | DelimChar = p; | |
354 | return (NULL); | |
d6a28dd8 | 355 | } |
506fc377 EA |
356 | else |
357 | cmntcnt--; | |
d6a28dd8 | 358 | } |
506fc377 EA |
359 | else if (cmntcnt > 0) |
360 | c = NOCHAR; | |
e93460a9 EA |
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 | } | |
926671ee EA |
373 | else if (delim == ' ' && isspace(c)) |
374 | c = ' '; | |
7b955214 EA |
375 | else if (c == ':' && !CurEnv->e_oldstyle) |
376 | { | |
377 | /* consume characters until a semicolon */ | |
378 | while (*p != '\0' && *p != ';') | |
379 | p++; | |
380 | if (*p == '\0') | |
381 | usrerr("Unbalanced ':...;' group spec"); | |
382 | else | |
383 | p++; | |
384 | c = ' '; | |
385 | } | |
d6a28dd8 | 386 | |
506fc377 EA |
387 | if (c == NOCHAR) |
388 | continue; | |
d6a28dd8 | 389 | |
506fc377 | 390 | /* see if this is end of input */ |
f115fb3a | 391 | if (c == delim && anglecnt <= 0 && state != QST) |
506fc377 | 392 | break; |
d6a28dd8 | 393 | |
506fc377 EA |
394 | newstate = StateTab[state][toktype(c)]; |
395 | # ifdef DEBUG | |
396 | if (tTd(22, 101)) | |
397 | printf("ns=%02o\n", newstate); | |
398 | # endif DEBUG | |
399 | state = newstate & TYPE; | |
400 | if (bitset(M, newstate)) | |
401 | c = NOCHAR; | |
402 | if (bitset(B, newstate)) | |
d6a28dd8 | 403 | break; |
b3cbe40f | 404 | } |
d6a28dd8 EA |
405 | |
406 | /* new token */ | |
506fc377 | 407 | if (tok != q) |
2a119b55 | 408 | { |
506fc377 EA |
409 | *q++ = '\0'; |
410 | # ifdef DEBUG | |
411 | if (tTd(22, 36)) | |
b3cbe40f | 412 | { |
506fc377 EA |
413 | printf("tok="); |
414 | xputs(tok); | |
03388044 | 415 | (void) putchar('\n'); |
b3cbe40f | 416 | } |
506fc377 EA |
417 | # endif DEBUG |
418 | if (avp >= &av[MAXATOM]) | |
b3cbe40f | 419 | { |
506fc377 EA |
420 | syserr("prescan: too many tokens"); |
421 | DelimChar = p; | |
422 | return (NULL); | |
b3cbe40f | 423 | } |
506fc377 | 424 | *avp++ = tok; |
b3cbe40f | 425 | } |
e93460a9 | 426 | } while (c != '\0' && (c != delim || anglecnt > 0)); |
d6a28dd8 | 427 | *avp = NULL; |
506fc377 | 428 | DelimChar = --p; |
d6a28dd8 EA |
429 | if (cmntcnt > 0) |
430 | usrerr("Unbalanced '('"); | |
e93460a9 EA |
431 | else if (anglecnt > 0) |
432 | usrerr("Unbalanced '<'"); | |
506fc377 | 433 | else if (state == QST) |
d6a28dd8 EA |
434 | usrerr("Unbalanced '\"'"); |
435 | else if (av[0] != NULL) | |
436 | return (av); | |
437 | return (NULL); | |
438 | } | |
439 | \f/* | |
440 | ** TOKTYPE -- return token type | |
441 | ** | |
442 | ** Parameters: | |
443 | ** c -- the character in question. | |
444 | ** | |
445 | ** Returns: | |
446 | ** Its type. | |
447 | ** | |
448 | ** Side Effects: | |
449 | ** none. | |
450 | */ | |
b3cbe40f | 451 | |
d6a28dd8 EA |
452 | toktype(c) |
453 | register char c; | |
454 | { | |
05f1e115 | 455 | static char buf[50]; |
e232ff47 | 456 | static bool firstime = TRUE; |
05f1e115 | 457 | |
e232ff47 | 458 | if (firstime) |
05f1e115 | 459 | { |
e232ff47 | 460 | firstime = FALSE; |
a73ae8ac | 461 | expand("\001o", buf, &buf[sizeof buf - 1], CurEnv); |
f9566d23 | 462 | (void) strcat(buf, DELIMCHARS); |
05f1e115 | 463 | } |
9f39d7cd | 464 | if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) |
506fc377 EA |
465 | return (ONE); |
466 | if (c == '"') | |
467 | return (QST); | |
cdb17311 | 468 | if (!isascii(c)) |
506fc377 EA |
469 | return (ATM); |
470 | if (isspace(c) || c == ')') | |
471 | return (SPC); | |
05f1e115 | 472 | if (iscntrl(c) || index(buf, c) != NULL) |
506fc377 EA |
473 | return (OPR); |
474 | return (ATM); | |
d6a28dd8 EA |
475 | } |
476 | \f/* | |
477 | ** REWRITE -- apply rewrite rules to token vector. | |
478 | ** | |
2258fda6 EA |
479 | ** This routine is an ordered production system. Each rewrite |
480 | ** rule has a LHS (called the pattern) and a RHS (called the | |
481 | ** rewrite); 'rwr' points the the current rewrite rule. | |
482 | ** | |
483 | ** For each rewrite rule, 'avp' points the address vector we | |
484 | ** are trying to match against, and 'pvp' points to the pattern. | |
792a6b53 | 485 | ** If pvp points to a special match value (MATCHZANY, MATCHANY, |
9f39d7cd EA |
486 | ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp |
487 | ** matched is saved away in the match vector (pointed to by 'mvp'). | |
2258fda6 EA |
488 | ** |
489 | ** When a match between avp & pvp does not match, we try to | |
9f39d7cd | 490 | ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS |
2258fda6 | 491 | ** we must also back out the match in mvp. If we reach a |
792a6b53 EA |
492 | ** MATCHANY or MATCHZANY we just extend the match and start |
493 | ** over again. | |
2258fda6 EA |
494 | ** |
495 | ** When we finally match, we rewrite the address vector | |
496 | ** and try over again. | |
497 | ** | |
d6a28dd8 EA |
498 | ** Parameters: |
499 | ** pvp -- pointer to token vector. | |
500 | ** | |
501 | ** Returns: | |
502 | ** none. | |
503 | ** | |
504 | ** Side Effects: | |
505 | ** pvp is modified. | |
506 | */ | |
507 | ||
508 | struct match | |
509 | { | |
54e8e18d EA |
510 | char **first; /* first token matched */ |
511 | char **last; /* last token matched */ | |
d6a28dd8 EA |
512 | }; |
513 | ||
54e8e18d | 514 | # define MAXMATCH 9 /* max params per rewrite */ |
d6a28dd8 EA |
515 | |
516 | ||
f65e7ded | 517 | rewrite(pvp, ruleset) |
d6a28dd8 | 518 | char **pvp; |
f65e7ded | 519 | int ruleset; |
d6a28dd8 EA |
520 | { |
521 | register char *ap; /* address pointer */ | |
522 | register char *rp; /* rewrite pointer */ | |
523 | register char **avp; /* address vector pointer */ | |
524 | register char **rvp; /* rewrite vector pointer */ | |
792a6b53 EA |
525 | register struct match *mlp; /* cur ptr into mlist */ |
526 | register struct rewrite *rwr; /* pointer to current rewrite rule */ | |
41173b8f EA |
527 | int subr; /* subroutine number if >= 0 */ |
528 | bool dolookup; /* do host aliasing */ | |
54e8e18d | 529 | struct match mlist[MAXMATCH]; /* stores match on LHS */ |
d6a28dd8 EA |
530 | char *npvp[MAXATOM+1]; /* temporary space for rebuild */ |
531 | ||
75f95954 | 532 | if (OpMode == MD_TEST || tTd(21, 2)) |
d6a28dd8 | 533 | { |
b726abe3 | 534 | printf("rewrite: ruleset %2d input:", ruleset); |
d6a28dd8 EA |
535 | printav(pvp); |
536 | } | |
e93460a9 EA |
537 | if (pvp == NULL) |
538 | return; | |
d6a28dd8 EA |
539 | |
540 | /* | |
541 | ** Run through the list of rewrite rules, applying | |
542 | ** any that match. | |
543 | */ | |
544 | ||
f65e7ded | 545 | for (rwr = RewriteRules[ruleset]; rwr != NULL; ) |
d6a28dd8 | 546 | { |
cdb17311 | 547 | # ifdef DEBUG |
9678c96d | 548 | if (tTd(21, 12)) |
d6a28dd8 | 549 | { |
b00e6882 | 550 | printf("-----trying rule:"); |
d6a28dd8 EA |
551 | printav(rwr->r_lhs); |
552 | } | |
cdb17311 | 553 | # endif DEBUG |
ecf90b7d | 554 | |
d6a28dd8 | 555 | /* try to match on this rule */ |
54e8e18d | 556 | mlp = mlist; |
792a6b53 EA |
557 | rvp = rwr->r_lhs; |
558 | avp = pvp; | |
559 | while ((ap = *avp) != NULL || *rvp != NULL) | |
b3cbe40f | 560 | { |
d6a28dd8 | 561 | rp = *rvp; |
792a6b53 EA |
562 | # ifdef DEBUG |
563 | if (tTd(21, 35)) | |
564 | { | |
b00e6882 | 565 | printf("ap="); |
792a6b53 | 566 | xputs(ap); |
b00e6882 | 567 | printf(", rp="); |
792a6b53 | 568 | xputs(rp); |
b00e6882 | 569 | printf("\n"); |
792a6b53 EA |
570 | } |
571 | # endif DEBUG | |
d6a28dd8 | 572 | if (rp == NULL) |
b3cbe40f | 573 | { |
d6a28dd8 | 574 | /* end-of-pattern before end-of-address */ |
792a6b53 EA |
575 | goto backup; |
576 | } | |
577 | if (ap == NULL && *rp != MATCHZANY) | |
578 | { | |
579 | /* end-of-input */ | |
580 | break; | |
d6a28dd8 EA |
581 | } |
582 | ||
583 | switch (*rp) | |
584 | { | |
13834bfc | 585 | register STAB *s; |
13834bfc | 586 | |
13834bfc | 587 | case MATCHCLASS: |
9f39d7cd EA |
588 | case MATCHNCLASS: |
589 | /* match any token in (not in) a class */ | |
cdb17311 | 590 | s = stab(ap, ST_CLASS, ST_FIND); |
1dbda134 | 591 | if (s == NULL || !bitnset(rp[1], s->s_class)) |
9f39d7cd EA |
592 | { |
593 | if (*rp == MATCHCLASS) | |
594 | goto backup; | |
595 | } | |
596 | else if (*rp == MATCHNCLASS) | |
792a6b53 | 597 | goto backup; |
54e8e18d | 598 | |
2258fda6 EA |
599 | /* explicit fall-through */ |
600 | ||
601 | case MATCHONE: | |
602 | case MATCHANY: | |
603 | /* match exactly one token */ | |
792a6b53 EA |
604 | mlp->first = avp; |
605 | mlp->last = avp++; | |
606 | mlp++; | |
607 | break; | |
608 | ||
609 | case MATCHZANY: | |
610 | /* match zero or more tokens */ | |
611 | mlp->first = avp; | |
612 | mlp->last = avp - 1; | |
54e8e18d | 613 | mlp++; |
13834bfc EA |
614 | break; |
615 | ||
d6a28dd8 EA |
616 | default: |
617 | /* must have exact match */ | |
ed73ef1d | 618 | if (strcasecmp(rp, ap)) |
792a6b53 | 619 | goto backup; |
54e8e18d | 620 | avp++; |
d6a28dd8 EA |
621 | break; |
622 | } | |
623 | ||
624 | /* successful match on this token */ | |
d6a28dd8 EA |
625 | rvp++; |
626 | continue; | |
627 | ||
792a6b53 | 628 | backup: |
d6a28dd8 EA |
629 | /* match failed -- back up */ |
630 | while (--rvp >= rwr->r_lhs) | |
631 | { | |
632 | rp = *rvp; | |
792a6b53 | 633 | if (*rp == MATCHANY || *rp == MATCHZANY) |
54e8e18d | 634 | { |
2258fda6 | 635 | /* extend binding and continue */ |
792a6b53 EA |
636 | avp = ++mlp[-1].last; |
637 | avp++; | |
2258fda6 | 638 | rvp++; |
d6a28dd8 | 639 | break; |
54e8e18d | 640 | } |
2258fda6 | 641 | avp--; |
9f39d7cd EA |
642 | if (*rp == MATCHONE || *rp == MATCHCLASS || |
643 | *rp == MATCHNCLASS) | |
d6a28dd8 | 644 | { |
54e8e18d | 645 | /* back out binding */ |
54e8e18d | 646 | mlp--; |
d6a28dd8 EA |
647 | } |
648 | } | |
649 | ||
650 | if (rvp < rwr->r_lhs) | |
651 | { | |
652 | /* total failure to match */ | |
653 | break; | |
b3cbe40f | 654 | } |
b3cbe40f | 655 | } |
d6a28dd8 EA |
656 | |
657 | /* | |
658 | ** See if we successfully matched | |
659 | */ | |
660 | ||
7338e3d4 | 661 | if (rvp < rwr->r_lhs || *rvp != NULL) |
d6a28dd8 | 662 | { |
cdb17311 | 663 | # ifdef DEBUG |
7338e3d4 EA |
664 | if (tTd(21, 10)) |
665 | printf("----- rule fails\n"); | |
cdb17311 | 666 | # endif DEBUG |
7338e3d4 EA |
667 | rwr = rwr->r_next; |
668 | continue; | |
669 | } | |
d6a28dd8 | 670 | |
7338e3d4 EA |
671 | rvp = rwr->r_rhs; |
672 | # ifdef DEBUG | |
673 | if (tTd(21, 12)) | |
674 | { | |
675 | printf("-----rule matches:"); | |
676 | printav(rvp); | |
677 | } | |
678 | # endif DEBUG | |
679 | ||
680 | rp = *rvp; | |
681 | if (*rp == CANONUSER) | |
682 | { | |
683 | rvp++; | |
684 | rwr = rwr->r_next; | |
685 | } | |
686 | else if (*rp == CANONHOST) | |
687 | { | |
688 | rvp++; | |
689 | rwr = NULL; | |
690 | } | |
691 | else if (*rp == CANONNET) | |
692 | rwr = NULL; | |
693 | ||
694 | /* substitute */ | |
41173b8f | 695 | dolookup = FALSE; |
7338e3d4 EA |
696 | for (avp = npvp; *rvp != NULL; rvp++) |
697 | { | |
698 | register struct match *m; | |
699 | register char **pp; | |
792a6b53 | 700 | |
7338e3d4 | 701 | rp = *rvp; |
41173b8f EA |
702 | |
703 | /* check to see if we should do a lookup */ | |
704 | if (*rp == MATCHLOOKUP) | |
705 | dolookup = TRUE; | |
706 | ||
707 | /* see if there is substitution here */ | |
217a0102 | 708 | if (*rp == MATCHREPL) |
d6a28dd8 | 709 | { |
217a0102 EA |
710 | /* substitute from LHS */ |
711 | m = &mlist[rp[1] - '1']; | |
712 | if (m >= mlp) | |
d6a28dd8 | 713 | { |
41173b8f | 714 | toolong: |
217a0102 | 715 | syserr("rewrite: ruleset %d: replacement out of bounds", ruleset); |
7338e3d4 EA |
716 | return; |
717 | } | |
2258fda6 | 718 | # ifdef DEBUG |
217a0102 EA |
719 | if (tTd(21, 15)) |
720 | { | |
721 | printf("$%c:", rp[1]); | |
722 | pp = m->first; | |
723 | while (pp <= m->last) | |
724 | { | |
725 | printf(" %x=\"", *pp); | |
726 | (void) fflush(stdout); | |
727 | printf("%s\"", *pp++); | |
728 | } | |
729 | printf("\n"); | |
730 | } | |
731 | # endif DEBUG | |
7338e3d4 EA |
732 | pp = m->first; |
733 | while (pp <= m->last) | |
e96bade8 | 734 | { |
217a0102 EA |
735 | if (avp >= &npvp[MAXATOM]) |
736 | { | |
737 | syserr("rewrite: expansion too long"); | |
738 | return; | |
739 | } | |
740 | *avp++ = *pp++; | |
e96bade8 | 741 | } |
d6a28dd8 | 742 | } |
217a0102 | 743 | else |
45ecb1bf | 744 | { |
217a0102 | 745 | /* vanilla replacement */ |
7338e3d4 | 746 | if (avp >= &npvp[MAXATOM]) |
41173b8f | 747 | goto toolong; |
217a0102 | 748 | *avp++ = rp; |
45ecb1bf | 749 | } |
7338e3d4 EA |
750 | } |
751 | *avp++ = NULL; | |
41173b8f | 752 | |
217a0102 EA |
753 | /* |
754 | ** Check for any hostname lookups. | |
755 | */ | |
756 | ||
757 | for (rvp = npvp; *rvp != NULL; rvp++) | |
758 | { | |
759 | char **hbrvp; | |
760 | char **xpvp; | |
761 | int trsize; | |
560a80d9 | 762 | char *olddelimchar; |
c0ef545b | 763 | char buf[MAXNAME + 1]; |
217a0102 | 764 | char *pvpb1[MAXATOM + 1]; |
7ac75266 | 765 | char pvpbuf[PSBUFSIZE]; |
560a80d9 | 766 | extern char *DelimChar; |
217a0102 EA |
767 | |
768 | if (**rvp != HOSTBEGIN) | |
769 | continue; | |
770 | ||
771 | /* | |
772 | ** Got a hostname lookup. | |
773 | ** | |
774 | ** This could be optimized fairly easily. | |
775 | */ | |
776 | ||
777 | hbrvp = rvp; | |
778 | ||
779 | /* extract the match part */ | |
780 | while (*++rvp != NULL && **rvp != HOSTEND) | |
781 | continue; | |
782 | if (*rvp != NULL) | |
783 | *rvp++ = NULL; | |
784 | ||
785 | /* save the remainder of the input string */ | |
786 | trsize = (int) (avp - rvp + 1) * sizeof *rvp; | |
787 | bcopy((char *) rvp, (char *) pvpb1, trsize); | |
788 | ||
789 | /* look it up */ | |
790 | cataddr(++hbrvp, buf, sizeof buf); | |
791 | maphostname(buf, sizeof buf); | |
792 | ||
793 | /* scan the new host name */ | |
560a80d9 | 794 | olddelimchar = DelimChar; |
217a0102 | 795 | xpvp = prescan(buf, '\0', pvpbuf); |
560a80d9 | 796 | DelimChar = olddelimchar; |
217a0102 EA |
797 | if (xpvp == NULL) |
798 | { | |
799 | syserr("rewrite: cannot prescan canonical hostname: %s", buf); | |
f0e070dc | 800 | return; |
217a0102 EA |
801 | } |
802 | ||
803 | /* append it to the token list */ | |
7ac75266 EA |
804 | for (avp = --hbrvp; *xpvp != NULL; xpvp++) |
805 | { | |
806 | *avp++ = newstr(*xpvp); | |
c0ef545b | 807 | if (avp >= &npvp[MAXATOM]) |
217a0102 | 808 | goto toolong; |
7ac75266 | 809 | } |
217a0102 EA |
810 | |
811 | /* restore the old trailing information */ | |
7c560c3f | 812 | for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) |
c0ef545b | 813 | if (avp >= &npvp[MAXATOM]) |
217a0102 | 814 | goto toolong; |
7ac75266 EA |
815 | |
816 | break; | |
217a0102 EA |
817 | } |
818 | ||
819 | /* | |
820 | ** Check for subroutine calls. | |
821 | */ | |
822 | ||
823 | ||
41173b8f EA |
824 | /* |
825 | ** Do hostname lookup if requested. | |
826 | */ | |
827 | ||
828 | if (dolookup) | |
7338e3d4 | 829 | { |
41173b8f EA |
830 | extern char **maphost(); |
831 | ||
832 | rvp = maphost(npvp); | |
d6a28dd8 EA |
833 | } |
834 | else | |
41173b8f EA |
835 | rvp = npvp; |
836 | ||
837 | /* | |
838 | ** See if this is a subroutine call. | |
839 | */ | |
840 | ||
841 | if (**rvp == CALLSUBR) | |
d6a28dd8 | 842 | { |
41173b8f EA |
843 | subr = atoi(*++rvp); |
844 | rvp++; | |
7338e3d4 | 845 | } |
41173b8f EA |
846 | else |
847 | subr = -1; | |
848 | ||
849 | /* | |
850 | ** Copy result back to original string. | |
851 | */ | |
852 | ||
853 | for (avp = pvp; *rvp != NULL; rvp++) | |
854 | *avp++ = *rvp; | |
855 | *avp = NULL; | |
856 | ||
857 | /* | |
858 | ** If this specified a subroutine, call it. | |
859 | */ | |
860 | ||
861 | if (subr >= 0) | |
862 | { | |
863 | # ifdef DEBUG | |
864 | if (tTd(21, 3)) | |
865 | printf("-----callsubr %s\n", subr); | |
866 | # endif DEBUG | |
867 | rewrite(pvp, subr); | |
868 | } | |
869 | ||
870 | /* | |
871 | ** Done with rewriting this pass. | |
872 | */ | |
873 | ||
cdb17311 | 874 | # ifdef DEBUG |
7338e3d4 EA |
875 | if (tTd(21, 4)) |
876 | { | |
877 | printf("rewritten as:"); | |
878 | printav(pvp); | |
d6a28dd8 | 879 | } |
7338e3d4 | 880 | # endif DEBUG |
b3cbe40f | 881 | } |
b00e6882 | 882 | |
75f95954 | 883 | if (OpMode == MD_TEST || tTd(21, 2)) |
b00e6882 | 884 | { |
b726abe3 | 885 | printf("rewrite: ruleset %2d returns:", ruleset); |
b00e6882 EA |
886 | printav(pvp); |
887 | } | |
d6a28dd8 EA |
888 | } |
889 | \f/* | |
d6a28dd8 EA |
890 | ** BUILDADDR -- build address from token vector. |
891 | ** | |
892 | ** Parameters: | |
893 | ** tv -- token vector. | |
894 | ** a -- pointer to address descriptor to fill. | |
895 | ** If NULL, one will be allocated. | |
896 | ** | |
897 | ** Returns: | |
fe43b434 EA |
898 | ** NULL if there was an error. |
899 | ** 'a' otherwise. | |
d6a28dd8 EA |
900 | ** |
901 | ** Side Effects: | |
902 | ** fills in 'a' | |
903 | */ | |
904 | ||
905 | ADDRESS * | |
906 | buildaddr(tv, a) | |
907 | register char **tv; | |
908 | register ADDRESS *a; | |
909 | { | |
d6a28dd8 EA |
910 | static char buf[MAXNAME]; |
911 | struct mailer **mp; | |
912 | register struct mailer *m; | |
d6a28dd8 EA |
913 | |
914 | if (a == NULL) | |
915 | a = (ADDRESS *) xalloc(sizeof *a); | |
abae7b2d | 916 | clear((char *) a, sizeof *a); |
d6a28dd8 EA |
917 | |
918 | /* figure out what net/mailer to use */ | |
919 | if (**tv != CANONNET) | |
fe43b434 | 920 | { |
d6a28dd8 | 921 | syserr("buildaddr: no net"); |
fe43b434 EA |
922 | return (NULL); |
923 | } | |
d6a28dd8 | 924 | tv++; |
ed73ef1d | 925 | if (!strcasecmp(*tv, "error")) |
fe43b434 | 926 | { |
4fd73cf9 EA |
927 | if (**++tv == CANONHOST) |
928 | { | |
929 | setstat(atoi(*++tv)); | |
930 | tv++; | |
931 | } | |
932 | if (**tv != CANONUSER) | |
fe43b434 EA |
933 | syserr("buildaddr: error: no user"); |
934 | buf[0] = '\0'; | |
935 | while (*++tv != NULL) | |
936 | { | |
937 | if (buf[0] != '\0') | |
f9566d23 EA |
938 | (void) strcat(buf, " "); |
939 | (void) strcat(buf, *tv); | |
fe43b434 EA |
940 | } |
941 | usrerr(buf); | |
942 | return (NULL); | |
943 | } | |
179c1218 | 944 | for (mp = Mailer; (m = *mp++) != NULL; ) |
d6a28dd8 | 945 | { |
ed73ef1d | 946 | if (!strcasecmp(m->m_name, *tv)) |
d6a28dd8 EA |
947 | break; |
948 | } | |
949 | if (m == NULL) | |
fe43b434 | 950 | { |
2e3062fe | 951 | syserr("buildaddr: unknown mailer %s", *tv); |
fe43b434 EA |
952 | return (NULL); |
953 | } | |
179c1218 | 954 | a->q_mailer = m; |
d6a28dd8 EA |
955 | |
956 | /* figure out what host (if any) */ | |
957 | tv++; | |
1dbda134 | 958 | if (!bitnset(M_LOCAL, m->m_flags)) |
d6a28dd8 | 959 | { |
35cc3fad | 960 | if (**tv++ != CANONHOST) |
fe43b434 | 961 | { |
d6a28dd8 | 962 | syserr("buildaddr: no host"); |
fe43b434 EA |
963 | return (NULL); |
964 | } | |
35cc3fad EA |
965 | buf[0] = '\0'; |
966 | while (*tv != NULL && **tv != CANONUSER) | |
f9566d23 | 967 | (void) strcat(buf, *tv++); |
35cc3fad | 968 | a->q_host = newstr(buf); |
d6a28dd8 EA |
969 | } |
970 | else | |
971 | a->q_host = NULL; | |
972 | ||
973 | /* figure out the user */ | |
974 | if (**tv != CANONUSER) | |
fe43b434 | 975 | { |
d6a28dd8 | 976 | syserr("buildaddr: no user"); |
fe43b434 EA |
977 | return (NULL); |
978 | } | |
5108b0cc EA |
979 | |
980 | /* rewrite according recipient mailer rewriting rules */ | |
981 | rewrite(++tv, 2); | |
982 | if (m->m_r_rwset > 0) | |
983 | rewrite(tv, m->m_r_rwset); | |
984 | rewrite(tv, 4); | |
985 | ||
986 | /* save the result for the command line/RCPT argument */ | |
f5811c6c | 987 | cataddr(tv, buf, sizeof buf); |
d6a28dd8 EA |
988 | a->q_user = buf; |
989 | ||
990 | return (a); | |
991 | } | |
9e3c0a28 | 992 | \f/* |
31b33174 EA |
993 | ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) |
994 | ** | |
995 | ** Parameters: | |
996 | ** pvp -- parameter vector to rebuild. | |
997 | ** buf -- buffer to build the string into. | |
998 | ** sz -- size of buf. | |
999 | ** | |
1000 | ** Returns: | |
1001 | ** none. | |
1002 | ** | |
1003 | ** Side Effects: | |
1004 | ** Destroys buf. | |
1005 | */ | |
1006 | ||
1007 | cataddr(pvp, buf, sz) | |
1008 | char **pvp; | |
1009 | char *buf; | |
1010 | register int sz; | |
1011 | { | |
1012 | bool oatomtok = FALSE; | |
1013 | bool natomtok = FALSE; | |
1014 | register int i; | |
1015 | register char *p; | |
1016 | ||
e93460a9 EA |
1017 | if (pvp == NULL) |
1018 | { | |
03388044 | 1019 | (void) strcpy(buf, ""); |
e93460a9 EA |
1020 | return; |
1021 | } | |
31b33174 | 1022 | p = buf; |
89dd4c8f | 1023 | sz -= 2; |
31b33174 EA |
1024 | while (*pvp != NULL && (i = strlen(*pvp)) < sz) |
1025 | { | |
506fc377 | 1026 | natomtok = (toktype(**pvp) == ATM); |
31b33174 | 1027 | if (oatomtok && natomtok) |
1744384a | 1028 | *p++ = SpaceSub; |
31b33174 EA |
1029 | (void) strcpy(p, *pvp); |
1030 | oatomtok = natomtok; | |
1031 | p += i; | |
89dd4c8f | 1032 | sz -= i + 1; |
31b33174 EA |
1033 | pvp++; |
1034 | } | |
1035 | *p = '\0'; | |
1036 | } | |
1037 | \f/* | |
9e3c0a28 EA |
1038 | ** SAMEADDR -- Determine if two addresses are the same |
1039 | ** | |
1040 | ** This is not just a straight comparison -- if the mailer doesn't | |
1041 | ** care about the host we just ignore it, etc. | |
1042 | ** | |
1043 | ** Parameters: | |
1044 | ** a, b -- pointers to the internal forms to compare. | |
9e3c0a28 EA |
1045 | ** |
1046 | ** Returns: | |
1047 | ** TRUE -- they represent the same mailbox. | |
1048 | ** FALSE -- they don't. | |
1049 | ** | |
1050 | ** Side Effects: | |
1051 | ** none. | |
1052 | */ | |
1053 | ||
1054 | bool | |
7338e3d4 | 1055 | sameaddr(a, b) |
9e3c0a28 EA |
1056 | register ADDRESS *a; |
1057 | register ADDRESS *b; | |
9e3c0a28 EA |
1058 | { |
1059 | /* if they don't have the same mailer, forget it */ | |
1060 | if (a->q_mailer != b->q_mailer) | |
1061 | return (FALSE); | |
1062 | ||
1063 | /* if the user isn't the same, we can drop out */ | |
7338e3d4 | 1064 | if (strcmp(a->q_user, b->q_user) != 0) |
9e3c0a28 EA |
1065 | return (FALSE); |
1066 | ||
1067 | /* if the mailer ignores hosts, we have succeeded! */ | |
1dbda134 | 1068 | if (bitnset(M_LOCAL, a->q_mailer->m_flags)) |
9e3c0a28 EA |
1069 | return (TRUE); |
1070 | ||
1071 | /* otherwise compare hosts (but be careful for NULL ptrs) */ | |
1072 | if (a->q_host == NULL || b->q_host == NULL) | |
1073 | return (FALSE); | |
1074 | if (strcmp(a->q_host, b->q_host) != 0) | |
1075 | return (FALSE); | |
1076 | ||
1077 | return (TRUE); | |
1078 | } | |
779597d8 EA |
1079 | \f/* |
1080 | ** PRINTADDR -- print address (for debugging) | |
1081 | ** | |
1082 | ** Parameters: | |
1083 | ** a -- the address to print | |
1084 | ** follow -- follow the q_next chain. | |
1085 | ** | |
1086 | ** Returns: | |
1087 | ** none. | |
1088 | ** | |
1089 | ** Side Effects: | |
1090 | ** none. | |
1091 | */ | |
1092 | ||
74c5fe7c EA |
1093 | # ifdef DEBUG |
1094 | ||
779597d8 EA |
1095 | printaddr(a, follow) |
1096 | register ADDRESS *a; | |
1097 | bool follow; | |
1098 | { | |
d4f42161 EA |
1099 | bool first = TRUE; |
1100 | ||
abae7b2d EA |
1101 | static int indent; |
1102 | register int i; | |
1103 | ||
779597d8 EA |
1104 | while (a != NULL) |
1105 | { | |
d4f42161 | 1106 | first = FALSE; |
abae7b2d EA |
1107 | for (i = indent; i > 0; i--) |
1108 | printf("\t"); | |
331b7c9f | 1109 | printf("%x=", a); |
29871fef | 1110 | (void) fflush(stdout); |
779597d8 | 1111 | printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, |
abae7b2d EA |
1112 | for (i = indent; i > 0; i--) |
1113 | printf("\t"); | |
1114 | printf("\tnext=%x, flags=%o, rmailer %d, alias=%x, sibling=%x, child=%x\n", | |
1115 | a->q_next, a->q_flags, a->q_rmailer, a->q_alias, | |
1116 | a->q_sibling, a->q_child); | |
1117 | ||
1118 | /* follow the chain if appropriate */ | |
779597d8 EA |
1119 | if (!follow) |
1120 | return; | |
abae7b2d EA |
1121 | |
1122 | indent++; | |
1123 | printaddr(a->q_child, TRUE); | |
1124 | indent--; | |
1125 | a = a->q_sibling; | |
779597d8 | 1126 | } |
d4f42161 | 1127 | if (first) |
331b7c9f | 1128 | printf("[NULL]\n"); |
779597d8 | 1129 | } |
74c5fe7c EA |
1130 | |
1131 | # endif DEBUG | |
22892d62 EA |
1132 | \f/* |
1133 | ** REMOTENAME -- return the name relative to the current mailer | |
1134 | ** | |
1135 | ** Parameters: | |
1136 | ** name -- the name to translate. | |
b00e6882 EA |
1137 | ** m -- the mailer that we want to do rewriting relative |
1138 | ** to. | |
1139 | ** senderaddress -- if set, uses the sender rewriting rules | |
1140 | ** rather than the recipient rewriting rules. | |
532c9874 EA |
1141 | ** canonical -- if set, strip out any comment information, |
1142 | ** etc. | |
22892d62 EA |
1143 | ** |
1144 | ** Returns: | |
1145 | ** the text string representing this address relative to | |
1146 | ** the receiving mailer. | |
1147 | ** | |
1148 | ** Side Effects: | |
1149 | ** none. | |
1150 | ** | |
1151 | ** Warnings: | |
1152 | ** The text string returned is tucked away locally; | |
1153 | ** copy it if you intend to save it. | |
1154 | */ | |
1155 | ||
1156 | char * | |
532c9874 | 1157 | remotename(name, m, senderaddress, canonical) |
22892d62 EA |
1158 | char *name; |
1159 | struct mailer *m; | |
b00e6882 | 1160 | bool senderaddress; |
532c9874 | 1161 | bool canonical; |
22892d62 | 1162 | { |
b00e6882 EA |
1163 | register char **pvp; |
1164 | char *fancy; | |
22892d62 | 1165 | extern char *macvalue(); |
857afefe | 1166 | char *oldg = macvalue('g', CurEnv); |
b00e6882 EA |
1167 | static char buf[MAXNAME]; |
1168 | char lbuf[MAXNAME]; | |
217a0102 | 1169 | char pvpbuf[PSBUFSIZE]; |
22892d62 | 1170 | extern char **prescan(); |
0908f182 | 1171 | extern char *crackaddr(); |
22892d62 | 1172 | |
e4b94f39 EA |
1173 | # ifdef DEBUG |
1174 | if (tTd(12, 1)) | |
1175 | printf("remotename(%s)\n", name); | |
1176 | # endif DEBUG | |
1177 | ||
4db45bf1 EA |
1178 | /* don't do anything if we are tagging it as special */ |
1179 | if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) | |
1180 | return (name); | |
1181 | ||
22892d62 | 1182 | /* |
857afefe EA |
1183 | ** Do a heuristic crack of this name to extract any comment info. |
1184 | ** This will leave the name as a comment and a $g macro. | |
22892d62 EA |
1185 | */ |
1186 | ||
532c9874 | 1187 | if (canonical) |
a73ae8ac | 1188 | fancy = "\001g"; |
532c9874 EA |
1189 | else |
1190 | fancy = crackaddr(name); | |
0908f182 | 1191 | |
857afefe EA |
1192 | /* |
1193 | ** Turn the name into canonical form. | |
1194 | ** Normally this will be RFC 822 style, i.e., "user@domain". | |
1195 | ** If this only resolves to "user", and the "C" flag is | |
1196 | ** specified in the sending mailer, then the sender's | |
1197 | ** domain will be appended. | |
1198 | */ | |
1199 | ||
217a0102 | 1200 | pvp = prescan(name, '\0', pvpbuf); |
0908f182 | 1201 | if (pvp == NULL) |
22892d62 | 1202 | return (name); |
857afefe EA |
1203 | rewrite(pvp, 3); |
1204 | if (CurEnv->e_fromdomain != NULL) | |
1205 | { | |
1206 | /* append from domain to this address */ | |
1207 | register char **pxp = pvp; | |
1208 | ||
18c3cee9 | 1209 | /* see if there is an "@domain" in the current name */ |
857afefe EA |
1210 | while (*pxp != NULL && strcmp(*pxp, "@") != 0) |
1211 | pxp++; | |
1212 | if (*pxp == NULL) | |
1213 | { | |
18c3cee9 | 1214 | /* no.... append the "@domain" from the sender */ |
857afefe EA |
1215 | register char **qxq = CurEnv->e_fromdomain; |
1216 | ||
18c3cee9 EA |
1217 | while ((*pxp++ = *qxq++) != NULL) |
1218 | continue; | |
82eade9e | 1219 | rewrite(pvp, 3); |
857afefe EA |
1220 | } |
1221 | } | |
1222 | ||
1223 | /* | |
b726abe3 | 1224 | ** Do more specific rewriting. |
857afefe EA |
1225 | ** Rewrite using ruleset 1 or 2 depending on whether this is |
1226 | ** a sender address or not. | |
1227 | ** Then run it through any receiving-mailer-specific rulesets. | |
1228 | */ | |
1229 | ||
b00e6882 | 1230 | if (senderaddress) |
22892d62 | 1231 | { |
0908f182 | 1232 | rewrite(pvp, 1); |
b00e6882 EA |
1233 | if (m->m_s_rwset > 0) |
1234 | rewrite(pvp, m->m_s_rwset); | |
1235 | } | |
1236 | else | |
1237 | { | |
0908f182 | 1238 | rewrite(pvp, 2); |
b00e6882 EA |
1239 | if (m->m_r_rwset > 0) |
1240 | rewrite(pvp, m->m_r_rwset); | |
0908f182 | 1241 | } |
22892d62 | 1242 | |
b726abe3 EA |
1243 | /* |
1244 | ** Do any final sanitation the address may require. | |
1245 | ** This will normally be used to turn internal forms | |
1246 | ** (e.g., user@host.LOCAL) into external form. This | |
1247 | ** may be used as a default to the above rules. | |
1248 | */ | |
1249 | ||
1250 | rewrite(pvp, 4); | |
1251 | ||
857afefe EA |
1252 | /* |
1253 | ** Now restore the comment information we had at the beginning. | |
1254 | */ | |
1255 | ||
0908f182 | 1256 | cataddr(pvp, lbuf, sizeof lbuf); |
7338e3d4 | 1257 | define('g', lbuf, CurEnv); |
0908f182 | 1258 | expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); |
7338e3d4 | 1259 | define('g', oldg, CurEnv); |
22892d62 EA |
1260 | |
1261 | # ifdef DEBUG | |
1262 | if (tTd(12, 1)) | |
e4b94f39 | 1263 | printf("remotename => `%s'\n", buf); |
22892d62 EA |
1264 | # endif DEBUG |
1265 | return (buf); | |
1266 | } |