Commit | Line | Data |
---|---|---|
f0e070dc | 1 | /* |
792e6158 | 2 | * Copyright (c) 1983, 1995 Eric P. Allman |
c1f0acb8 KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
f0e070dc MAN |
8 | |
9 | #ifndef lint | |
2293b217 | 10 | static char sccsid[] = "@(#)parseaddr.c 8.72 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
f0e070dc | 12 | |
fd6cfc53 EA |
13 | #include "sendmail.h" |
14 | ||
d30b0654 EA |
15 | static int callsubr __P((char **, int, ENVELOPE *)); |
16 | ||
fd6cfc53 EA |
17 | #ifdef CC_WONT_PROMOTE |
18 | static int toktype __P((char)); | |
19 | #else /* !CC_WONT_PROMOTE */ | |
20 | static int toktype __P((int)); /* char -> int */ | |
21 | #endif /* CC_WONT_PROMOTE */ | |
22 | static void _rewrite __P((char **, int)); | |
23 | static void callsubr __P((char **)); | |
24 | static ADDRESS * buildaddr __P((char **, ADDRESS *)); | |
25 | static void uurelativize __P((const char *, const char *, char **)); | |
26 | ||
27 | char *DelimChar; /* set to point to the delimiter */ | |
916b3375 | 28 | |
b3cbe40f | 29 | /* |
40d27fed | 30 | ** PARSEADDR -- Parse an address |
b3cbe40f EA |
31 | ** |
32 | ** Parses an address and breaks it up into three parts: a | |
33 | ** net to transmit the message on, the host to transmit it | |
34 | ** to, and a user on that host. These are loaded into an | |
406f98bc | 35 | ** ADDRESS header with the values squirreled away if necessary. |
b3cbe40f EA |
36 | ** The "user" part may not be a real user; the process may |
37 | ** just reoccur on that machine. For example, on a machine | |
38 | ** with an arpanet connection, the address | |
39 | ** csvax.bill@berkeley | |
40 | ** will break up to a "user" of 'csvax.bill' and a host | |
41 | ** of 'berkeley' -- to be transmitted over the arpanet. | |
42 | ** | |
43 | ** Parameters: | |
44 | ** addr -- the address to parse. | |
45 | ** a -- a pointer to the address descriptor buffer. | |
46 | ** If NULL, a header will be created. | |
28f94061 EA |
47 | ** flags -- describe detail for parsing. See RF_ definitions |
48 | ** in sendmail.h. | |
d3f52e20 EA |
49 | ** delim -- the character to terminate the address, passed |
50 | ** to prescan. | |
9e2cf26f EA |
51 | ** delimptr -- if non-NULL, set to the location of the |
52 | ** delim character that was found. | |
a4076aed | 53 | ** e -- the envelope that will contain this address. |
b3cbe40f EA |
54 | ** |
55 | ** Returns: | |
56 | ** A pointer to the address descriptor header (`a' if | |
57 | ** `a' is non-NULL). | |
58 | ** NULL on error. | |
59 | ** | |
60 | ** Side Effects: | |
61 | ** none | |
b3cbe40f EA |
62 | */ |
63 | ||
7338e3d4 | 64 | /* following delimiters are inherent to the internal algorithms */ |
3f99edce | 65 | # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ |
ecf90b7d | 66 | |
406f98bc | 67 | ADDRESS * |
28f94061 | 68 | parseaddr(addr, a, flags, delim, delimptr, e) |
b3cbe40f | 69 | char *addr; |
406f98bc | 70 | register ADDRESS *a; |
28f94061 | 71 | int flags; |
ef3bc6b1 | 72 | int delim; |
9e2cf26f | 73 | char **delimptr; |
a4076aed | 74 | register ENVELOPE *e; |
b3cbe40f | 75 | { |
d6a28dd8 | 76 | register char **pvp; |
9e2cf26f | 77 | auto char *delimptrbuf; |
d1db7a89 | 78 | bool queueup; |
217a0102 | 79 | char pvpbuf[PSBUFSIZE]; |
b3cbe40f EA |
80 | |
81 | /* | |
82 | ** Initialize and prescan address. | |
83 | */ | |
84 | ||
a4076aed | 85 | e->e_to = addr; |
9678c96d | 86 | if (tTd(20, 1)) |
40d27fed | 87 | printf("\n--parseaddr(%s)\n", addr); |
9e3c0a28 | 88 | |
fd6cfc53 EA |
89 | { |
90 | extern char *DelimChar; /* parseaddr.c */ | |
91 | char savec; | |
92 | bool invalid; | |
c40bef63 EA |
93 | extern char *finddelim(); |
94 | extern bool invalidaddr(); | |
fd6cfc53 EA |
95 | |
96 | DelimChar = finddelim(addr, delim); | |
97 | savec = *DelimChar; | |
98 | *DelimChar = '\0'; | |
99 | invalid = invalidaddr(addr); | |
100 | *DelimChar = savec; | |
101 | if (invalid) | |
102 | return (NULL); | |
103 | } | |
104 | ||
9e2cf26f EA |
105 | if (delimptr == NULL) |
106 | delimptr = &delimptrbuf; | |
107 | ||
800c836f | 108 | pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL); |
d6a28dd8 | 109 | if (pvp == NULL) |
a17692a9 EA |
110 | { |
111 | if (tTd(20, 1)) | |
112 | printf("parseaddr-->NULL\n"); | |
b3cbe40f | 113 | return (NULL); |
a17692a9 | 114 | } |
b3cbe40f | 115 | |
7c40218a EA |
116 | if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) |
117 | { | |
118 | if (tTd(20, 1)) | |
119 | printf("parseaddr-->bad address\n"); | |
120 | return NULL; | |
121 | } | |
122 | ||
dab5fedb EA |
123 | /* |
124 | ** Save addr if we are going to have to. | |
125 | ** | |
126 | ** We have to do this early because there is a chance that | |
127 | ** the map lookups in the rewriting rules could clobber | |
128 | ** static memory somewhere. | |
129 | */ | |
130 | ||
131 | if (bitset(RF_COPYPADDR, flags) && addr != NULL) | |
132 | { | |
133 | char savec = **delimptr; | |
134 | ||
135 | if (savec != '\0') | |
136 | **delimptr = '\0'; | |
55168534 | 137 | e->e_to = addr = newstr(addr); |
dab5fedb EA |
138 | if (savec != '\0') |
139 | **delimptr = savec; | |
140 | } | |
141 | ||
b3cbe40f | 142 | /* |
d6a28dd8 | 143 | ** Apply rewriting rules. |
0908f182 | 144 | ** Ruleset 0 does basic parsing. It must resolve. |
b3cbe40f EA |
145 | */ |
146 | ||
d1db7a89 | 147 | queueup = FALSE; |
b141a9b6 | 148 | if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) |
d1db7a89 | 149 | queueup = TRUE; |
b141a9b6 | 150 | if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) |
d1db7a89 | 151 | queueup = TRUE; |
b3cbe40f | 152 | |
b3cbe40f EA |
153 | |
154 | /* | |
d6a28dd8 | 155 | ** Build canonical address from pvp. |
b3cbe40f EA |
156 | */ |
157 | ||
28f94061 | 158 | a = buildaddr(pvp, a, flags, e); |
b3cbe40f EA |
159 | |
160 | /* | |
d6a28dd8 EA |
161 | ** Make local copies of the host & user and then |
162 | ** transport them out. | |
b3cbe40f EA |
163 | */ |
164 | ||
dab5fedb | 165 | allocaddr(a, flags, addr); |
9577b1df EA |
166 | if (bitset(QBADADDR, a->q_flags)) |
167 | return a; | |
d13779b1 | 168 | |
d1db7a89 EA |
169 | /* |
170 | ** If there was a parsing failure, mark it for queueing. | |
171 | */ | |
172 | ||
173 | if (queueup) | |
c281eee3 | 174 | { |
7ffb494c EA |
175 | char *msg = "Transient parse error -- message queued for future delivery"; |
176 | ||
c281eee3 EA |
177 | if (tTd(20, 1)) |
178 | printf("parseaddr: queuing message\n"); | |
7ffb494c EA |
179 | message(msg); |
180 | if (e->e_message == NULL) | |
f10d3e38 | 181 | e->e_message = newstr(msg); |
d1db7a89 | 182 | a->q_flags |= QQUEUEUP; |
09d45ea9 | 183 | a->q_status = "4.4.3"; |
c281eee3 | 184 | } |
d1db7a89 | 185 | |
d13779b1 EA |
186 | /* |
187 | ** Compute return value. | |
188 | */ | |
189 | ||
190 | if (tTd(20, 1)) | |
191 | { | |
192 | printf("parseaddr-->"); | |
193 | printaddr(a, FALSE); | |
194 | } | |
195 | ||
196 | return (a); | |
197 | } | |
198 | \f/* | |
ab542b8f EA |
199 | ** INVALIDADDR -- check for address containing meta-characters |
200 | ** | |
201 | ** Parameters: | |
202 | ** addr -- the address to check. | |
203 | ** | |
204 | ** Returns: | |
205 | ** TRUE -- if the address has any "wierd" characters | |
206 | ** FALSE -- otherwise. | |
207 | */ | |
208 | ||
209 | bool | |
7c40218a | 210 | invalidaddr(addr, delimptr) |
ab542b8f | 211 | register char *addr; |
7c40218a | 212 | char *delimptr; |
ab542b8f | 213 | { |
ea07b2d2 | 214 | char savedelim = '\0'; |
7c40218a EA |
215 | |
216 | if (delimptr != NULL) | |
46275151 | 217 | { |
7c40218a | 218 | savedelim = *delimptr; |
46275151 EA |
219 | if (savedelim != '\0') |
220 | *delimptr = '\0'; | |
221 | } | |
7c40218a EA |
222 | #if 0 |
223 | /* for testing.... */ | |
224 | if (strcmp(addr, "INvalidADDR") == 0) | |
ab542b8f | 225 | { |
7c40218a | 226 | usrerr("553 INvalid ADDRess"); |
46275151 | 227 | goto addrfailure; |
ab542b8f | 228 | } |
7c40218a EA |
229 | #endif |
230 | for (; *addr != '\0'; addr++) | |
231 | { | |
232 | if ((*addr & 0340) == 0200) | |
233 | break; | |
234 | } | |
7c40218a | 235 | if (*addr == '\0') |
46275151 | 236 | { |
c0f381db | 237 | if (delimptr != NULL && savedelim != '\0') |
46275151 | 238 | *delimptr = savedelim; |
7c40218a | 239 | return FALSE; |
46275151 | 240 | } |
7c40218a EA |
241 | setstat(EX_USAGE); |
242 | usrerr("553 Address contained invalid control characters"); | |
46275151 | 243 | addrfailure: |
b758423c | 244 | if (delimptr != NULL && savedelim != '\0') |
46275151 | 245 | *delimptr = savedelim; |
7c40218a | 246 | return TRUE; |
ab542b8f EA |
247 | } |
248 | \f/* | |
d13779b1 EA |
249 | ** ALLOCADDR -- do local allocations of address on demand. |
250 | ** | |
251 | ** Also lowercases the host name if requested. | |
252 | ** | |
253 | ** Parameters: | |
254 | ** a -- the address to reallocate. | |
28f94061 EA |
255 | ** flags -- the copy flag (see RF_ definitions in sendmail.h |
256 | ** for a description). | |
d13779b1 EA |
257 | ** paddr -- the printname of the address. |
258 | ** | |
259 | ** Returns: | |
260 | ** none. | |
261 | ** | |
262 | ** Side Effects: | |
263 | ** Copies portions of a into local buffers as requested. | |
264 | */ | |
265 | ||
179d940c | 266 | void |
dab5fedb | 267 | allocaddr(a, flags, paddr) |
d13779b1 | 268 | register ADDRESS *a; |
28f94061 | 269 | int flags; |
d13779b1 EA |
270 | char *paddr; |
271 | { | |
7002d4e7 | 272 | if (tTd(24, 4)) |
d6474f90 | 273 | printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); |
7002d4e7 | 274 | |
dab5fedb | 275 | a->q_paddr = paddr; |
2e3062fe EA |
276 | |
277 | if (a->q_user == NULL) | |
278 | a->q_user = ""; | |
279 | if (a->q_host == NULL) | |
280 | a->q_host = ""; | |
281 | ||
28f94061 | 282 | if (bitset(RF_COPYPARSE, flags)) |
b3cbe40f | 283 | { |
2e3062fe | 284 | a->q_host = newstr(a->q_host); |
d6a28dd8 EA |
285 | if (a->q_user != a->q_paddr) |
286 | a->q_user = newstr(a->q_user); | |
b3cbe40f EA |
287 | } |
288 | ||
d13779b1 EA |
289 | if (a->q_paddr == NULL) |
290 | a->q_paddr = a->q_user; | |
0fe3917f EA |
291 | } |
292 | \f/* | |
fd6cfc53 EA |
293 | ** INVALIDADDR -- check an address string for invalid control characters. |
294 | ** | |
295 | ** Parameters: | |
296 | ** addr -- address string to be checked. | |
297 | ** | |
298 | ** Returns: | |
299 | ** TRUE if address string could cause problems, FALSE o/w. | |
300 | ** | |
301 | ** Side Effects: | |
302 | ** ExitStat may be changed and an error message generated. | |
303 | */ | |
304 | ||
305 | bool | |
306 | invalidaddr(addr) | |
307 | const char *addr; | |
308 | { | |
309 | register const char *cp; | |
310 | ||
311 | /* make sure error messages don't have garbage on them */ | |
312 | errno = 0; | |
313 | ||
314 | /* | |
315 | ** Sendmail reserves characters 020 - 036 for rewriting rules | |
316 | ** which can cause havoc (e.g. infinite rewriting loops) if | |
317 | ** one shows up at the wrong time. If any of these characters | |
318 | ** appear in an address, the address is deemed "invalid" and | |
319 | ** an error message is generated. | |
320 | */ | |
321 | ||
322 | for (cp = addr; *cp; cp++) | |
323 | if ((*cp >= MATCHZANY && *cp <= HOSTEND) || *cp == '\001') | |
324 | { | |
325 | setstat(EX_USAGE); | |
326 | usrerr("address contained invalid control char(s)"); | |
327 | return (TRUE); | |
328 | } | |
329 | return (FALSE); | |
330 | } | |
331 | \f/* | |
b3cbe40f EA |
332 | ** PRESCAN -- Prescan name and make it canonical |
333 | ** | |
7338e3d4 EA |
334 | ** Scans a name and turns it into a set of tokens. This process |
335 | ** deletes blanks and comments (in parentheses). | |
b3cbe40f EA |
336 | ** |
337 | ** This routine knows about quoted strings and angle brackets. | |
338 | ** | |
339 | ** There are certain subtleties to this routine. The one that | |
340 | ** comes to mind now is that backslashes on the ends of names | |
341 | ** are silently stripped off; this is intentional. The problem | |
342 | ** is that some versions of sndmsg (like at LBL) set the kill | |
343 | ** character to something other than @ when reading addresses; | |
344 | ** so people type "csvax.eric\@berkeley" -- which screws up the | |
345 | ** berknet mailer. | |
346 | ** | |
347 | ** Parameters: | |
348 | ** addr -- the name to chomp. | |
b3cbe40f EA |
349 | ** delim -- the delimiter for the address, normally |
350 | ** '\0' or ','; \0 is accepted in any case. | |
f12f79be | 351 | ** If '\t' then we are reading the .cf file. |
217a0102 EA |
352 | ** pvpbuf -- place to put the saved text -- note that |
353 | ** the pointers are static. | |
148ea694 | 354 | ** pvpbsize -- size of pvpbuf. |
9e2cf26f EA |
355 | ** delimptr -- if non-NULL, set to the location of the |
356 | ** terminating delimiter. | |
800c836f EA |
357 | ** toktab -- if set, a token table to use for parsing. |
358 | ** If NULL, use the default table. | |
b3cbe40f EA |
359 | ** |
360 | ** Returns: | |
d6a28dd8 | 361 | ** A pointer to a vector of tokens. |
b3cbe40f | 362 | ** NULL on error. |
b3cbe40f EA |
363 | */ |
364 | ||
506fc377 EA |
365 | /* states and character types */ |
366 | # define OPR 0 /* operator */ | |
367 | # define ATM 1 /* atom */ | |
368 | # define QST 2 /* in quoted string */ | |
369 | # define SPC 3 /* chewing up spaces */ | |
370 | # define ONE 4 /* pick up one character */ | |
800c836f | 371 | # define ILL 5 /* illegal character */ |
506fc377 | 372 | |
800c836f | 373 | # define NSTATES 6 /* number of states */ |
506fc377 EA |
374 | # define TYPE 017 /* mask to select state type */ |
375 | ||
376 | /* meta bits for table */ | |
377 | # define M 020 /* meta character; don't pass through */ | |
378 | # define B 040 /* cause a break */ | |
379 | # define MB M|B /* meta-break */ | |
380 | ||
381 | static short StateTab[NSTATES][NSTATES] = | |
382 | { | |
800c836f EA |
383 | /* oldst chtype> OPR ATM QST SPC ONE ILL */ |
384 | /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB, | |
385 | /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB, | |
386 | /*QST*/ QST, QST, OPR, QST, QST, QST, | |
387 | /*SPC*/ OPR, ATM, QST, SPC|M, ONE, ILL|MB, | |
388 | /*ONE*/ OPR, OPR, OPR, OPR, OPR, ILL|MB, | |
389 | /*ILL*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M, | |
506fc377 EA |
390 | }; |
391 | ||
1954e81b | 392 | /* token type table -- it gets modified with $o characters */ |
179d940c | 393 | static u_char TokTypeTab[256] = |
1954e81b | 394 | { |
800c836f EA |
395 | /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ |
396 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, | |
397 | /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ | |
398 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
399 | /* sp ! " # $ % & ' ( ) * + , - . / */ | |
400 | SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM, | |
401 | /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ | |
402 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
403 | /* @ A B C D E F G H I J K L M N O */ | |
404 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
405 | /* P Q R S T U V W X Y Z [ \ ] ^ _ */ | |
406 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
407 | /* ` a b c d e f g h i j k l m n o */ | |
408 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
409 | /* p q r s t u v w x y z { | } ~ del */ | |
410 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
411 | ||
412 | /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ | |
413 | OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, | |
414 | /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ | |
415 | OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, | |
416 | /* sp ! " # $ % & ' ( ) * + , - . / */ | |
417 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
418 | /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ | |
419 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
420 | /* @ A B C D E F G H I J K L M N O */ | |
421 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
422 | /* P Q R S T U V W X Y Z [ \ ] ^ _ */ | |
423 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
424 | /* ` a b c d e f g h i j k l m n o */ | |
425 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
426 | /* p q r s t u v w x y z { | } ~ del */ | |
427 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
1954e81b EA |
428 | }; |
429 | ||
800c836f | 430 | /* token type table for MIME parsing */ |
179d940c | 431 | u_char MimeTokenTab[256] = |
800c836f EA |
432 | { |
433 | /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ | |
434 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, | |
435 | /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ | |
436 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
437 | /* sp ! " # $ % & ' ( ) * + , - . / */ | |
438 | SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR, | |
439 | /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ | |
440 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, | |
441 | /* @ A B C D E F G H I J K L M N O */ | |
442 | OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
443 | /* P Q R S T U V W X Y Z [ \ ] ^ _ */ | |
444 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, | |
445 | /* ` a b c d e f g h i j k l m n o */ | |
446 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
447 | /* p q r s t u v w x y z { | } ~ del */ | |
448 | ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, | |
449 | ||
450 | /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ | |
451 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
452 | /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ | |
453 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
454 | /* sp ! " # $ % & ' ( ) * + , - . / */ | |
455 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
456 | /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ | |
457 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
458 | /* @ A B C D E F G H I J K L M N O */ | |
459 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
460 | /* P Q R S T U V W X Y Z [ \ ] ^ _ */ | |
461 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
462 | /* ` a b c d e f g h i j k l m n o */ | |
463 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
464 | /* p q r s t u v w x y z { | } ~ del */ | |
465 | ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, | |
466 | }; | |
1954e81b EA |
467 | |
468 | ||
506fc377 EA |
469 | # define NOCHAR -1 /* signal nothing in lookahead token */ |
470 | ||
d6a28dd8 | 471 | char ** |
800c836f | 472 | prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) |
b3cbe40f | 473 | char *addr; |
ae9a1656 | 474 | int delim; |
217a0102 | 475 | char pvpbuf[]; |
9e2cf26f | 476 | char **delimptr; |
179d940c | 477 | u_char *toktab; |
b3cbe40f EA |
478 | { |
479 | register char *p; | |
506fc377 | 480 | register char *q; |
611b763d | 481 | register int c; |
d6a28dd8 | 482 | char **avp; |
b3cbe40f EA |
483 | bool bslashmode; |
484 | int cmntcnt; | |
e93460a9 | 485 | int anglecnt; |
d6a28dd8 | 486 | char *tok; |
506fc377 EA |
487 | int state; |
488 | int newstate; | |
fba945cd | 489 | char *saveto = CurEnv->e_to; |
506fc377 | 490 | static char *av[MAXATOM+1]; |
1954e81b EA |
491 | static char firsttime = TRUE; |
492 | ||
493 | if (firsttime) | |
494 | { | |
495 | /* initialize the token type table */ | |
496 | char obuf[50]; | |
497 | ||
498 | firsttime = FALSE; | |
832e8a27 | 499 | expand("\201o", obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv); |
1954e81b EA |
500 | strcat(obuf, DELIMCHARS); |
501 | for (p = obuf; *p != '\0'; p++) | |
502 | { | |
503 | if (TokTypeTab[*p & 0xff] == ATM) | |
504 | TokTypeTab[*p & 0xff] = OPR; | |
505 | } | |
506 | } | |
800c836f EA |
507 | if (toktab == NULL) |
508 | toktab = TokTypeTab; | |
15cd119d EA |
509 | |
510 | /* make sure error messages don't have garbage on them */ | |
511 | errno = 0; | |
b3cbe40f | 512 | |
217a0102 | 513 | q = pvpbuf; |
d6a28dd8 | 514 | bslashmode = FALSE; |
43ff8bb5 | 515 | cmntcnt = 0; |
e93460a9 | 516 | anglecnt = 0; |
d6a28dd8 | 517 | avp = av; |
85c61679 | 518 | state = ATM; |
506fc377 EA |
519 | c = NOCHAR; |
520 | p = addr; | |
fba945cd | 521 | CurEnv->e_to = p; |
97a521ff | 522 | if (tTd(22, 11)) |
506fc377 EA |
523 | { |
524 | printf("prescan: "); | |
525 | xputs(p); | |
03388044 | 526 | (void) putchar('\n'); |
506fc377 | 527 | } |
506fc377 EA |
528 | |
529 | do | |
b3cbe40f | 530 | { |
d6a28dd8 EA |
531 | /* read a token */ |
532 | tok = q; | |
506fc377 | 533 | for (;;) |
b3cbe40f | 534 | { |
506fc377 | 535 | /* store away any old lookahead character */ |
e9937bb7 | 536 | if (c != NOCHAR && !bslashmode) |
506fc377 | 537 | { |
f12f79be | 538 | /* see if there is room */ |
148ea694 | 539 | if (q >= &pvpbuf[pvpbsize - 5]) |
506fc377 | 540 | { |
b6edea3d | 541 | usrerr("553 Address too long"); |
10f9a8a5 EA |
542 | if (strlen(addr) > MAXNAME) |
543 | addr[MAXNAME] = '\0'; | |
77779257 | 544 | returnnull: |
9e2cf26f EA |
545 | if (delimptr != NULL) |
546 | *delimptr = p; | |
fba945cd | 547 | CurEnv->e_to = saveto; |
506fc377 EA |
548 | return (NULL); |
549 | } | |
f12f79be EA |
550 | |
551 | /* squirrel it away */ | |
506fc377 EA |
552 | *q++ = c; |
553 | } | |
554 | ||
555 | /* read a new input character */ | |
556 | c = *p++; | |
422bed79 | 557 | if (c == '\0') |
97a521ff EA |
558 | { |
559 | /* diagnose and patch up bad syntax */ | |
560 | if (state == QST) | |
561 | { | |
ec14f23c | 562 | usrerr("653 Unbalanced '\"'"); |
97a521ff EA |
563 | c = '"'; |
564 | } | |
565 | else if (cmntcnt > 0) | |
566 | { | |
ec14f23c | 567 | usrerr("653 Unbalanced '('"); |
97a521ff EA |
568 | c = ')'; |
569 | } | |
570 | else if (anglecnt > 0) | |
571 | { | |
572 | c = '>'; | |
ec14f23c | 573 | usrerr("653 Unbalanced '<'"); |
97a521ff EA |
574 | } |
575 | else | |
576 | break; | |
577 | ||
578 | p--; | |
579 | } | |
422bed79 EA |
580 | else if (c == delim && anglecnt <= 0 && |
581 | cmntcnt <= 0 && state != QST) | |
582 | break; | |
f12f79be | 583 | |
506fc377 EA |
584 | if (tTd(22, 101)) |
585 | printf("c=%c, s=%d; ", c, state); | |
506fc377 | 586 | |
d6a28dd8 EA |
587 | /* chew up special characters */ |
588 | *q = '\0'; | |
589 | if (bslashmode) | |
590 | { | |
ff54f632 EA |
591 | bslashmode = FALSE; |
592 | ||
2e3062fe | 593 | /* kludge \! for naive users */ |
5d41b806 | 594 | if (cmntcnt > 0) |
ff54f632 | 595 | { |
5d41b806 | 596 | c = NOCHAR; |
ff54f632 EA |
597 | continue; |
598 | } | |
599 | else if (c != '!' || state == QST) | |
600 | { | |
85c61679 | 601 | *q++ = '\\'; |
ff54f632 EA |
602 | continue; |
603 | } | |
d6a28dd8 | 604 | } |
048264ae EA |
605 | |
606 | if (c == '\\') | |
d6a28dd8 EA |
607 | { |
608 | bslashmode = TRUE; | |
d6a28dd8 | 609 | } |
fd6cfc53 | 610 | if (state == QST) |
63a35680 EA |
611 | { |
612 | /* do nothing, just avoid next clauses */ | |
613 | } | |
506fc377 | 614 | else if (c == '(') |
cdb17311 | 615 | { |
506fc377 EA |
616 | cmntcnt++; |
617 | c = NOCHAR; | |
cdb17311 | 618 | } |
506fc377 | 619 | else if (c == ')') |
d6a28dd8 | 620 | { |
506fc377 | 621 | if (cmntcnt <= 0) |
d6a28dd8 | 622 | { |
ec14f23c | 623 | usrerr("653 Unbalanced ')'"); |
64b7394c | 624 | c = NOCHAR; |
d6a28dd8 | 625 | } |
506fc377 EA |
626 | else |
627 | cmntcnt--; | |
d6a28dd8 | 628 | } |
506fc377 EA |
629 | else if (cmntcnt > 0) |
630 | c = NOCHAR; | |
e93460a9 EA |
631 | else if (c == '<') |
632 | anglecnt++; | |
633 | else if (c == '>') | |
634 | { | |
635 | if (anglecnt <= 0) | |
636 | { | |
ec14f23c | 637 | usrerr("653 Unbalanced '>'"); |
64b7394c | 638 | c = NOCHAR; |
e93460a9 | 639 | } |
64b7394c EA |
640 | else |
641 | anglecnt--; | |
e93460a9 | 642 | } |
2bee003d | 643 | else if (delim == ' ' && isascii(c) && isspace(c)) |
926671ee | 644 | c = ' '; |
7b955214 EA |
645 | else if (c == ':' && !CurEnv->e_oldstyle) |
646 | { | |
647 | /* consume characters until a semicolon */ | |
648 | while (*p != '\0' && *p != ';') | |
649 | p++; | |
650 | if (*p == '\0') | |
651 | usrerr("Unbalanced ':...;' group spec"); | |
652 | else | |
653 | p++; | |
654 | c = ' '; | |
655 | } | |
d6a28dd8 | 656 | |
fd6cfc53 EA |
657 | else if (c == ';') /* semicolons are not tokens */ |
658 | c = NOCHAR; | |
659 | ||
506fc377 EA |
660 | if (c == NOCHAR) |
661 | continue; | |
d6a28dd8 | 662 | |
506fc377 | 663 | /* see if this is end of input */ |
f115fb3a | 664 | if (c == delim && anglecnt <= 0 && state != QST) |
506fc377 | 665 | break; |
d6a28dd8 | 666 | |
800c836f | 667 | newstate = StateTab[state][toktab[c & 0xff]]; |
506fc377 EA |
668 | if (tTd(22, 101)) |
669 | printf("ns=%02o\n", newstate); | |
506fc377 | 670 | state = newstate & TYPE; |
800c836f EA |
671 | if (state == ILL) |
672 | { | |
673 | if (isascii(c) && isprint(c)) | |
674 | usrerr("653 Illegal character %c", c); | |
675 | else | |
676 | usrerr("653 Illegal character 0x%02x", c); | |
677 | } | |
506fc377 EA |
678 | if (bitset(M, newstate)) |
679 | c = NOCHAR; | |
680 | if (bitset(B, newstate)) | |
d6a28dd8 | 681 | break; |
b3cbe40f | 682 | } |
d6a28dd8 EA |
683 | |
684 | /* new token */ | |
506fc377 | 685 | if (tok != q) |
2a119b55 | 686 | { |
506fc377 | 687 | *q++ = '\0'; |
506fc377 | 688 | if (tTd(22, 36)) |
b3cbe40f | 689 | { |
506fc377 EA |
690 | printf("tok="); |
691 | xputs(tok); | |
03388044 | 692 | (void) putchar('\n'); |
b3cbe40f | 693 | } |
506fc377 | 694 | if (avp >= &av[MAXATOM]) |
b3cbe40f | 695 | { |
b6edea3d | 696 | syserr("553 prescan: too many tokens"); |
77779257 EA |
697 | goto returnnull; |
698 | } | |
699 | if (q - tok > MAXNAME) | |
700 | { | |
701 | syserr("553 prescan: token too long"); | |
702 | goto returnnull; | |
b3cbe40f | 703 | } |
506fc377 | 704 | *avp++ = tok; |
b3cbe40f | 705 | } |
e93460a9 | 706 | } while (c != '\0' && (c != delim || anglecnt > 0)); |
d6a28dd8 | 707 | *avp = NULL; |
9e2cf26f EA |
708 | p--; |
709 | if (delimptr != NULL) | |
710 | *delimptr = p; | |
97a521ff EA |
711 | if (tTd(22, 12)) |
712 | { | |
713 | printf("prescan==>"); | |
714 | printav(av); | |
715 | } | |
fba945cd | 716 | CurEnv->e_to = saveto; |
6cb17374 | 717 | if (av[0] == NULL) |
c2d0b04b EA |
718 | { |
719 | if (tTd(22, 1)) | |
720 | printf("prescan: null leading token\n"); | |
6cb17374 | 721 | return (NULL); |
c2d0b04b | 722 | } |
1c4d5753 | 723 | return (av); |
d6a28dd8 EA |
724 | } |
725 | \f/* | |
d6a28dd8 EA |
726 | ** REWRITE -- apply rewrite rules to token vector. |
727 | ** | |
2258fda6 EA |
728 | ** This routine is an ordered production system. Each rewrite |
729 | ** rule has a LHS (called the pattern) and a RHS (called the | |
730 | ** rewrite); 'rwr' points the the current rewrite rule. | |
731 | ** | |
732 | ** For each rewrite rule, 'avp' points the address vector we | |
733 | ** are trying to match against, and 'pvp' points to the pattern. | |
792a6b53 | 734 | ** If pvp points to a special match value (MATCHZANY, MATCHANY, |
9f39d7cd EA |
735 | ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp |
736 | ** matched is saved away in the match vector (pointed to by 'mvp'). | |
2258fda6 EA |
737 | ** |
738 | ** When a match between avp & pvp does not match, we try to | |
9f39d7cd | 739 | ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS |
2258fda6 | 740 | ** we must also back out the match in mvp. If we reach a |
792a6b53 EA |
741 | ** MATCHANY or MATCHZANY we just extend the match and start |
742 | ** over again. | |
2258fda6 EA |
743 | ** |
744 | ** When we finally match, we rewrite the address vector | |
745 | ** and try over again. | |
746 | ** | |
d6a28dd8 EA |
747 | ** Parameters: |
748 | ** pvp -- pointer to token vector. | |
1ac3479f | 749 | ** ruleset -- the ruleset to use for rewriting. |
b141a9b6 | 750 | ** reclevel -- recursion level (to catch loops). |
1ac3479f | 751 | ** e -- the current envelope. |
d6a28dd8 EA |
752 | ** |
753 | ** Returns: | |
d1db7a89 EA |
754 | ** A status code. If EX_TEMPFAIL, higher level code should |
755 | ** attempt recovery. | |
d6a28dd8 EA |
756 | ** |
757 | ** Side Effects: | |
758 | ** pvp is modified. | |
759 | */ | |
760 | ||
fd6cfc53 EA |
761 | # define OP_NONZLEN 00001 |
762 | # define OP_VARLEN 00002 | |
763 | # define OP_CLASS 00004 | |
764 | # define OP_EXACT 00010 | |
765 | ||
d6a28dd8 EA |
766 | struct match |
767 | { | |
54e8e18d EA |
768 | char **first; /* first token matched */ |
769 | char **last; /* last token matched */ | |
9d6aecfd | 770 | char **pattern; /* pointer to pattern */ |
fd6cfc53 EA |
771 | char **source; /* left hand source operand */ |
772 | char flags; /* attributes of this operator */ | |
d6a28dd8 EA |
773 | }; |
774 | ||
54e8e18d | 775 | # define MAXMATCH 9 /* max params per rewrite */ |
fd6cfc53 EA |
776 | # define MAX_CONTROL ' ' |
777 | ||
69bdb647 EA |
778 | # ifndef MAXRULERECURSION |
779 | # define MAXRULERECURSION 50 /* max recursion depth */ | |
780 | # endif | |
fd6cfc53 EA |
781 | static char control_opts[MAX_CONTROL]; |
782 | ||
69bdb647 | 783 | |
d1db7a89 | 784 | int |
fd6cfc53 EA |
785 | static char control_init_data[] = { |
786 | MATCHZANY, OP_VARLEN, | |
787 | MATCHONE, OP_NONZLEN, | |
788 | MATCHANY, OP_VARLEN|OP_NONZLEN, | |
789 | #ifdef MACVALUE | |
790 | MACVALUE, OP_EXACT, | |
791 | #endif /* MACVALUE */ | |
792 | MATCHNCLASS, OP_NONZLEN, | |
793 | MATCHCLASS, OP_NONZLEN|OP_VARLEN|OP_CLASS, | |
fd6cfc53 | 794 | }; |
d6a28dd8 | 795 | |
fd6cfc53 | 796 | static int nrw; |
d6a28dd8 | 797 | |
fd6cfc53 | 798 | void |
b141a9b6 | 799 | rewrite(pvp, ruleset, reclevel, e) |
d6a28dd8 | 800 | char **pvp; |
f65e7ded | 801 | int ruleset; |
b141a9b6 | 802 | int reclevel; |
1ac3479f | 803 | register ENVELOPE *e; |
fd6cfc53 EA |
804 | { |
805 | nrw = 0; | |
806 | _rewrite(pvp, ruleset); | |
807 | } | |
808 | ||
809 | static void | |
810 | _rewrite(pvp, ruleset) | |
811 | char **pvp; | |
812 | int ruleset; | |
d6a28dd8 EA |
813 | { |
814 | register char *ap; /* address pointer */ | |
815 | register char *rp; /* rewrite pointer */ | |
816 | register char **avp; /* address vector pointer */ | |
817 | register char **rvp; /* rewrite vector pointer */ | |
792a6b53 EA |
818 | register struct match *mlp; /* cur ptr into mlist */ |
819 | register struct rewrite *rwr; /* pointer to current rewrite rule */ | |
75df37ee | 820 | int ruleno; /* current rule number */ |
d1db7a89 | 821 | int rstat = EX_OK; /* return status */ |
1d91f401 | 822 | int loopcount; |
41173b8f EA |
823 | int subr; /* subroutine number if >= 0 */ |
824 | bool dolookup; /* do host aliasing */ | |
d6a28dd8 | 825 | char *npvp[MAXATOM+1]; /* temporary space for rebuild */ |
fd6cfc53 EA |
826 | char tokbuf[MAXNAME+1]; /* for concatenated class tokens */ |
827 | int nloops, nmatches = 0; /* for looping rule checks */ | |
828 | struct rewrite *prev_rwr; /* pointer to previous rewrite rule */ | |
829 | struct match mlist[MAXMATCH+1]; /* stores match on LHS */ | |
830 | struct match *old_mlp; /* to save our place */ | |
831 | bool extend_match; /* extend existing match during backup */ | |
832 | ||
25cc8f69 | 833 | if (OpMode == MD_TEST || tTd(21, 1)) |
d6a28dd8 | 834 | { |
b726abe3 | 835 | printf("rewrite: ruleset %2d input:", ruleset); |
fd6cfc53 | 836 | printcav(pvp); |
d6a28dd8 | 837 | } |
f62b79ae EA |
838 | if (ruleset < 0 || ruleset >= MAXRWSETS) |
839 | { | |
b6edea3d | 840 | syserr("554 rewrite: illegal ruleset number %d", ruleset); |
d1db7a89 | 841 | return EX_CONFIG; |
f62b79ae | 842 | } |
69bdb647 | 843 | if (reclevel++ > MAXRULERECURSION) |
b141a9b6 EA |
844 | { |
845 | syserr("rewrite: infinite recursion, ruleset %d", ruleset); | |
846 | return EX_CONFIG; | |
847 | } | |
e93460a9 | 848 | if (pvp == NULL) |
d1db7a89 | 849 | return EX_USAGE; |
d6a28dd8 | 850 | |
fd6cfc53 EA |
851 | if (++nrw > 100) |
852 | { | |
853 | char buf[MAXLINE]; | |
854 | ||
855 | buf[0] = buf[MAXLINE-1] = 0; | |
856 | while (*pvp) | |
857 | (void) strncat(buf, *pvp++, sizeof buf); | |
858 | syserr("address causes rewrite loop: <%s>", buf); | |
859 | return; | |
860 | } | |
861 | ||
862 | /* Be sure to recognize first rule as new */ | |
863 | prev_rwr = NULL; | |
864 | ||
d6a28dd8 | 865 | /* |
fd6cfc53 | 866 | ** Run through the list of rewrite rules, applying any that match. |
d6a28dd8 EA |
867 | */ |
868 | ||
75df37ee | 869 | ruleno = 1; |
1d91f401 | 870 | loopcount = 0; |
f65e7ded | 871 | for (rwr = RewriteRules[ruleset]; rwr != NULL; ) |
d6a28dd8 | 872 | { |
9678c96d | 873 | if (tTd(21, 12)) |
d6a28dd8 | 874 | { |
b00e6882 | 875 | printf("-----trying rule:"); |
fd6cfc53 EA |
876 | printcav(rwr->r_lhs); |
877 | } | |
878 | ||
879 | /* | |
880 | ** Set up the match list. This is done once for each | |
881 | ** rule. If a rule is used repeatedly, the list need not | |
882 | ** be set up the next time. | |
883 | */ | |
884 | ||
885 | if (rwr != prev_rwr) | |
886 | { | |
887 | prev_rwr = rwr; | |
888 | for (rvp = rwr->r_lhs, mlp = mlist; | |
889 | *rvp && (mlp < &mlist[MAXMATCH]); rvp++) | |
890 | { | |
891 | mlp->flags = ((unsigned char) **rvp >= MAX_CONTROL) ? | |
892 | 0 : control_opts[**rvp] ; | |
893 | if (mlp->flags) | |
894 | { | |
895 | mlp->source = rvp; | |
896 | mlp++; | |
897 | } | |
898 | } | |
899 | if (*rvp) | |
900 | { | |
901 | syserr("Too many variables on LHS in ruleset %d", ruleset); | |
902 | return; | |
903 | } | |
904 | mlp->source = rvp; | |
905 | ||
906 | /* Make sure end marker is initialized */ | |
907 | mlp->flags = 0; | |
d6a28dd8 | 908 | } |
ecf90b7d | 909 | |
d6a28dd8 | 910 | /* try to match on this rule */ |
54e8e18d | 911 | mlp = mlist; |
fd6cfc53 | 912 | |
792a6b53 EA |
913 | rvp = rwr->r_lhs; |
914 | avp = pvp; | |
fd6cfc53 EA |
915 | nloops = 0; |
916 | extend_match = FALSE; | |
917 | ||
75df37ee | 918 | if (++loopcount > 100) |
b3cbe40f | 919 | { |
fd6cfc53 EA |
920 | if (nloops++ > 400) |
921 | { | |
922 | syserr("Looping on ruleset %d, rule %d", | |
923 | ruleset, rwr-RewriteRules[ruleset]); | |
924 | mlp = mlist - 1; /* force rule failure */ | |
925 | break; | |
926 | } | |
75df37ee EA |
927 | syserr("554 Infinite loop in ruleset %d, rule %d", |
928 | ruleset, ruleno); | |
929 | if (tTd(21, 1)) | |
72f91c2e | 930 | { |
f62b79ae EA |
931 | printf("workspace: "); |
932 | printav(pvp); | |
72f91c2e | 933 | } |
75df37ee EA |
934 | break; |
935 | } | |
936 | ||
937 | while ((ap = *avp) != NULL || *rvp != NULL) | |
938 | { | |
d6a28dd8 | 939 | rp = *rvp; |
fd6cfc53 | 940 | |
792a6b53 EA |
941 | if (tTd(21, 35)) |
942 | { | |
9d6aecfd | 943 | printf("ADVANCE rp="); |
792a6b53 | 944 | xputs(rp); |
5a1d901b | 945 | printf(", ap="); |
511c3bad | 946 | xputs(ap); |
b00e6882 | 947 | printf("\n"); |
792a6b53 | 948 | } |
fd6cfc53 EA |
949 | |
950 | if (extend_match) | |
951 | extend_match = FALSE; | |
952 | else | |
b3cbe40f | 953 | { |
fd6cfc53 EA |
954 | mlp->first = avp; |
955 | mlp->last = mlp->flags == 0 || (mlp->flags & OP_NONZLEN) ? | |
956 | avp + 1 : avp; | |
957 | } | |
958 | ||
959 | if (rp == NULL) | |
d6a28dd8 | 960 | /* end-of-pattern before end-of-address */ |
792a6b53 | 961 | goto backup; |
fd6cfc53 EA |
962 | |
963 | /* Premature end of address */ | |
964 | if (ap == NULL && avp != mlp->last) | |
965 | goto backup; | |
966 | ||
967 | /* | |
968 | ** Simplest case - exact token comparison between | |
969 | ** pattern and address. Such a match is not saved | |
970 | ** in mlp. | |
971 | */ | |
972 | ||
973 | if (rvp < mlp->source) | |
792a6b53 | 974 | { |
fd6cfc53 EA |
975 | if (ap == NULL || strcasecmp(ap, rp)) |
976 | goto backup; | |
977 | rvp++; | |
978 | avp++; | |
979 | continue; | |
d6a28dd8 EA |
980 | } |
981 | ||
fd6cfc53 EA |
982 | #ifdef MACVALUE |
983 | /* | |
984 | ** This is special case handled. The match is exact, | |
985 | ** but might span zero or more address tokens. The | |
986 | ** result is saved in mlp. | |
987 | */ | |
988 | ||
989 | if (*rp == MACVALUE) | |
d6a28dd8 | 990 | { |
fd6cfc53 EA |
991 | int len; |
992 | rp = macvalue(rp[1], CurEnv); | |
13834bfc | 993 | |
fd6cfc53 EA |
994 | if (rp) |
995 | while (*rp) | |
996 | { | |
997 | if (*avp == NULL || strncasecmp(rp,*avp,len = strlen(*avp))) | |
998 | goto backup; | |
999 | rp += len; | |
1000 | avp++; | |
1001 | } | |
1002 | mlp->last = avp; | |
1003 | rvp++; | |
1004 | mlp++; | |
1005 | continue; | |
1006 | } | |
1007 | #endif /* MACVALUE */ | |
1008 | ||
1009 | /* | |
1010 | ** All other matches are saved in mlp. Initially | |
1011 | ** assume they match at the shortest possible length | |
1012 | ** for this pattern. Variable patterns will be | |
1013 | ** extended later as needed. | |
1014 | */ | |
1015 | ||
1016 | /* Fixed length first */ | |
1017 | if (!(mlp->flags & OP_VARLEN)) | |
1018 | { | |
1019 | switch (*rp) | |
9f39d7cd | 1020 | { |
fd6cfc53 | 1021 | break; |
fd6cfc53 | 1022 | } |
792a6b53 | 1023 | |
fd6cfc53 EA |
1024 | avp = mlp->last; |
1025 | rvp++; | |
54e8e18d | 1026 | mlp++; |
1bca74dd EA |
1027 | break; |
1028 | ||
a42056e7 | 1029 | case MATCHZERO: |
1bca74dd | 1030 | /* match zero tokens */ |
fd6cfc53 EA |
1031 | continue; |
1032 | } | |
1033 | ||
1ac3479f EA |
1034 | case MACRODEXPAND: |
1035 | /* | |
1036 | ** Match against run-time macro. | |
1037 | ** This algorithm is broken for the | |
1038 | ** general case (no recursive macros, | |
1039 | ** improper tokenization) but should | |
1040 | ** work for the usual cases. | |
1041 | */ | |
1042 | ||
1043 | ap = macvalue(rp[1], e); | |
1044 | mlp->first = avp; | |
1045 | if (tTd(21, 2)) | |
1046 | printf("rewrite: LHS $&%c => \"%s\"\n", | |
1047 | rp[1], | |
1048 | ap == NULL ? "(NULL)" : ap); | |
1049 | ||
1050 | if (ap == NULL) | |
1051 | break; | |
54d35e43 | 1052 | while (*ap != '\0') |
1ac3479f EA |
1053 | { |
1054 | if (*avp == NULL || | |
1055 | strncasecmp(ap, *avp, strlen(*avp)) != 0) | |
1056 | { | |
1057 | /* no match */ | |
1058 | avp = mlp->first; | |
1059 | goto backup; | |
1060 | } | |
1061 | ap += strlen(*avp++); | |
1062 | } | |
1063 | ||
1064 | /* match */ | |
1065 | break; | |
1066 | ||
fd6cfc53 EA |
1067 | /* |
1068 | ** We now have a variable length item. It could | |
1069 | ** be $+ or $* in which case no special checking | |
1070 | ** is needed. But a class match such as $=x must | |
1071 | ** be verified. | |
1072 | ** | |
1073 | ** As a speedup, if a variable length item is | |
1074 | ** followed by a plain character token, we initially | |
1075 | ** extend the match to the first such token we find. | |
1076 | ** If the required character token cannot be found, | |
1077 | ** we fail the match at this point. | |
1078 | */ | |
1079 | ||
1080 | avp = mlp->last; | |
1081 | ||
1082 | /* If next token is char token */ | |
1083 | if (&rvp[1] < mlp[1].source) | |
1084 | { | |
1085 | while (*avp && strcasecmp(*avp, rvp[1])) | |
1086 | avp++; | |
1087 | ||
1088 | /* | |
1089 | ** If we can't find the proper ending token, | |
1090 | ** leave avp point to NULL. This indicates | |
1091 | ** we have run out of address tokens. It is | |
1092 | ** pointless to advance the beginning of this | |
1093 | ** match and retry. | |
1094 | */ | |
13834bfc | 1095 | |
fd6cfc53 | 1096 | if (*avp == NULL) |
792a6b53 | 1097 | goto backup; |
fd6cfc53 EA |
1098 | mlp->last = avp; |
1099 | } | |
1100 | else if (rvp[1] == NULL) | |
1101 | /* next token is end of address */ | |
1102 | { | |
1103 | while (*avp) | |
1104 | avp++; | |
1105 | mlp->last = avp; | |
1106 | } | |
1107 | ||
1108 | if (mlp->flags & OP_CLASS) | |
1109 | { | |
1110 | register char *cp = tokbuf; | |
1111 | ||
1112 | avp = mlp->first; | |
1113 | strcpy(cp, *avp); | |
54e8e18d | 1114 | avp++; |
fd6cfc53 EA |
1115 | for (;;) |
1116 | { | |
1117 | while (avp < mlp->last) | |
1118 | { | |
1119 | while (*cp) | |
1120 | cp++; | |
1121 | strcpy(cp, *avp); | |
1122 | avp++; | |
1123 | } | |
1124 | switch (*rp) | |
1125 | { | |
1126 | register STAB *s; | |
1127 | ||
1128 | case MATCHCLASS: | |
1129 | s = stab(tokbuf, ST_CLASS, ST_FIND); | |
1130 | if (s != NULL && bitnset(rp[1], s->s_class)) | |
1131 | goto have_match; | |
1132 | break; | |
fd6cfc53 EA |
1133 | } |
1134 | ||
1135 | /* | |
1136 | ** Class match initially failed. | |
1137 | ** Extend the tentative match. | |
1138 | ** Again, if followed by a character | |
1139 | ** token, extend all the way to that | |
1140 | ** token before checking. | |
1141 | */ | |
1142 | ||
1143 | if (*avp) | |
1144 | { | |
1145 | (mlp->last)++; | |
1146 | if (&rvp[1] < mlp[1].source) | |
1147 | { | |
1148 | while (*(mlp->last) && strcasecmp(*(mlp->last), rvp[1])) | |
1149 | (mlp->last)++; | |
1150 | if (*(mlp->last) == NULL) | |
1151 | avp = mlp->last; | |
1152 | } | |
1153 | } | |
1154 | if (*avp == NULL) | |
1155 | { | |
1156 | /* | |
1157 | ** We could not find the | |
1158 | ** ending token. But we had | |
1159 | ** found ending tokens before. | |
1160 | ** A match is still plausible | |
1161 | ** if the start of the | |
1162 | ** tentative match is advanced. | |
1163 | ** Hence we must not leave avp | |
1164 | ** pointing to NULL. | |
1165 | */ | |
1166 | avp = mlp->first; | |
1167 | goto backup; | |
1168 | } | |
1169 | } | |
d6a28dd8 EA |
1170 | } |
1171 | ||
fd6cfc53 | 1172 | have_match: |
d6a28dd8 | 1173 | rvp++; |
fd6cfc53 | 1174 | mlp++; |
d6a28dd8 EA |
1175 | continue; |
1176 | ||
fd6cfc53 EA |
1177 | backup: |
1178 | /* We failed to match. mlp marks point of failure */ | |
1179 | ||
1180 | /* | |
1181 | ** There is a special case when we have exhausted | |
1182 | ** the address, but have not exhausted the pattern. | |
1183 | ** Under normal circumstances we could consider the | |
1184 | ** failure permanent, since extending the number of | |
1185 | ** address tokens matched by a '$+' or a '$*' will | |
1186 | ** only worsen the situation. | |
1187 | ** | |
1188 | ** There is an exception, however. It is possible | |
1189 | ** that we have matched a class token, say '$=x', | |
1190 | ** with three or more tokens. Extending a '$+' say, | |
1191 | ** which precedes the '$=x' will move the beginning | |
1192 | ** of the '$=x' match to the right, but it might match | |
1193 | ** a smaller number of tokens then, possibly | |
1194 | ** correcting the mismatch. | |
1195 | ** | |
1196 | ** Thus in this case we initially back up to the | |
1197 | ** $=x which matches three or more tokens. | |
1198 | */ | |
1199 | ||
1200 | if (*avp == NULL) | |
d6a28dd8 | 1201 | { |
9d6aecfd | 1202 | rvp = mlp->pattern; |
fd6cfc53 | 1203 | while (--mlp > mlist) |
54e8e18d | 1204 | { |
fd6cfc53 EA |
1205 | if ((mlp->flags & OP_CLASS) && |
1206 | mlp->last > 2 + mlp->first) | |
1207 | break; | |
d6a28dd8 EA |
1208 | } |
1209 | } | |
1210 | ||
fd6cfc53 EA |
1211 | /* |
1212 | ** Now backup till we find a match with a pattern | |
1213 | ** whose length is extendable, and extend that. | |
1214 | */ | |
1215 | ||
1216 | mlp--; | |
1217 | while (mlp >= mlist && !(mlp->flags & OP_VARLEN)) | |
1218 | mlp--; | |
1219 | ||
1220 | /* Total failure to match */ | |
1221 | if (mlp < mlist) | |
d6a28dd8 | 1222 | break; |
fd6cfc53 EA |
1223 | |
1224 | avp = ++(mlp->last); | |
1225 | rvp = mlp->source; | |
1226 | ||
1227 | /* | |
1228 | ** We have found a backup point. Normally we would | |
1229 | ** increase the matched amount by one token, and | |
1230 | ** continue from the next item in the pattern. But | |
1231 | ** there are two special cases. If this is a | |
1232 | ** class-type match (OP_CLASS), we must test the | |
1233 | ** validity of the extended match. If this pattern | |
1234 | ** item is directly followed by a character token, it | |
1235 | ** is worth going back and locating the next such | |
1236 | ** character token before we continue on. | |
1237 | */ | |
1238 | if ((mlp->flags & OP_CLASS) || (&rvp[1] < mlp[1].source)) | |
1239 | { | |
1240 | avp = mlp->first; | |
1241 | extend_match = TRUE; | |
1242 | } | |
1243 | else | |
1244 | { | |
1245 | mlp++; | |
1246 | rvp++; | |
b3cbe40f | 1247 | } |
b3cbe40f | 1248 | } |
d6a28dd8 EA |
1249 | |
1250 | /* | |
fd6cfc53 | 1251 | ** See if we successfully matched. |
d6a28dd8 EA |
1252 | */ |
1253 | ||
fd6cfc53 | 1254 | if (mlp < mlist) |
d6a28dd8 | 1255 | { |
7338e3d4 EA |
1256 | if (tTd(21, 10)) |
1257 | printf("----- rule fails\n"); | |
7338e3d4 | 1258 | rwr = rwr->r_next; |
75df37ee | 1259 | ruleno++; |
1d91f401 | 1260 | loopcount = 0; |
fd6cfc53 EA |
1261 | nmatches = 0; |
1262 | continue; | |
1263 | } | |
1264 | ||
1265 | if (nmatches++ > 200) | |
1266 | { | |
1267 | syserr("Loop in ruleset %d, rule %d (too many matches)", | |
1268 | ruleset, rwr - RewriteRules[ruleset]); | |
1269 | rwr = rwr->r_next; | |
1270 | nmatches = 0; | |
7338e3d4 EA |
1271 | continue; |
1272 | } | |
d6a28dd8 | 1273 | |
7338e3d4 | 1274 | rvp = rwr->r_rhs; |
7338e3d4 EA |
1275 | if (tTd(21, 12)) |
1276 | { | |
1277 | printf("-----rule matches:"); | |
fd6cfc53 | 1278 | printcav(rvp); |
7338e3d4 | 1279 | } |
7338e3d4 EA |
1280 | |
1281 | rp = *rvp; | |
2bee003d | 1282 | if ((*rp & 0377) == CANONUSER) |
7338e3d4 EA |
1283 | { |
1284 | rvp++; | |
1285 | rwr = rwr->r_next; | |
75df37ee | 1286 | ruleno++; |
1d91f401 | 1287 | loopcount = 0; |
fd6cfc53 | 1288 | nmatches = 0; |
7338e3d4 | 1289 | } |
2bee003d | 1290 | else if ((*rp & 0377) == CANONHOST) |
7338e3d4 EA |
1291 | { |
1292 | rvp++; | |
1293 | rwr = NULL; | |
1294 | } | |
2bee003d | 1295 | else if ((*rp & 0377) == CANONNET) |
7338e3d4 EA |
1296 | rwr = NULL; |
1297 | ||
1298 | /* substitute */ | |
41173b8f | 1299 | dolookup = FALSE; |
7338e3d4 EA |
1300 | for (avp = npvp; *rvp != NULL; rvp++) |
1301 | { | |
1302 | register struct match *m; | |
1303 | register char **pp; | |
792a6b53 | 1304 | |
7338e3d4 | 1305 | rp = *rvp; |
41173b8f EA |
1306 | |
1307 | /* check to see if we should do a lookup */ | |
1308 | if (*rp == MATCHLOOKUP) | |
1309 | dolookup = TRUE; | |
1310 | ||
1311 | /* see if there is substitution here */ | |
fd6cfc53 | 1312 | if (*rp == MATCHREPL && rp[1] >= '1' && rp[1] <= '9') |
d6a28dd8 | 1313 | { |
217a0102 EA |
1314 | /* substitute from LHS */ |
1315 | m = &mlist[rp[1] - '1']; | |
f62b79ae | 1316 | if (m < mlist || m >= mlp) |
d6a28dd8 | 1317 | { |
41173b8f | 1318 | toolong: |
fd6cfc53 EA |
1319 | syserr("rewrite: ruleset %d: replacement #%c out of bounds", |
1320 | ruleset, rp[1]); | |
d1db7a89 | 1321 | return EX_CONFIG; |
7338e3d4 | 1322 | } |
217a0102 EA |
1323 | if (tTd(21, 15)) |
1324 | { | |
1325 | printf("$%c:", rp[1]); | |
1326 | pp = m->first; | |
fd6cfc53 | 1327 | while (pp < m->last) |
217a0102 EA |
1328 | { |
1329 | printf(" %x=\"", *pp); | |
1330 | (void) fflush(stdout); | |
1331 | printf("%s\"", *pp++); | |
1332 | } | |
1333 | printf("\n"); | |
1334 | } | |
7338e3d4 | 1335 | pp = m->first; |
fd6cfc53 | 1336 | while (pp < m->last) |
e96bade8 | 1337 | { |
217a0102 | 1338 | if (avp >= &npvp[MAXATOM]) |
fd6cfc53 | 1339 | goto toolong; |
217a0102 | 1340 | *avp++ = *pp++; |
e96bade8 | 1341 | } |
d6a28dd8 | 1342 | } |
217a0102 | 1343 | else |
45ecb1bf | 1344 | { |
217a0102 | 1345 | /* vanilla replacement */ |
7338e3d4 | 1346 | if (avp >= &npvp[MAXATOM]) |
41173b8f | 1347 | goto toolong; |
fd6cfc53 EA |
1348 | #ifdef MACVALUE |
1349 | if (*rp == MACVALUE) | |
1350 | { | |
1351 | char *p = macvalue(rp[1], CurEnv); | |
1352 | ||
1353 | if (tTd(21, 2)) | |
1354 | printf("expanding runtime macro '%c' to \"%s\"\n", | |
1355 | rp[1], p ? p : "(null)"); | |
1356 | if (p) | |
1357 | *avp++ = p; | |
1358 | } | |
1359 | else | |
1360 | #endif /* MACVALUE */ | |
1361 | *avp++ = rp; | |
45ecb1bf | 1362 | } |
7338e3d4 EA |
1363 | } |
1364 | *avp++ = NULL; | |
41173b8f | 1365 | |
217a0102 | 1366 | /* |
42fa5d67 | 1367 | ** Check for any hostname/keyword lookups. |
217a0102 EA |
1368 | */ |
1369 | ||
1370 | for (rvp = npvp; *rvp != NULL; rvp++) | |
1371 | { | |
fd6cfc53 | 1372 | char **hbrvp, **ubrvp; |
217a0102 EA |
1373 | char **xpvp; |
1374 | int trsize; | |
42fa5d67 EA |
1375 | char *replac; |
1376 | int endtoken; | |
1377 | STAB *map; | |
1378 | char *mapname; | |
1379 | char **key_rvp; | |
1380 | char **arg_rvp; | |
1381 | char **default_rvp; | |
fd6cfc53 | 1382 | char hbuf[MAXNAME + 1], ubuf[MAXNAME + 1]; |
217a0102 | 1383 | char *pvpb1[MAXATOM + 1]; |
5a4c03c6 | 1384 | char *argvect[10]; |
7ac75266 | 1385 | char pvpbuf[PSBUFSIZE]; |
f0b4483c | 1386 | char *nullpvp[1]; |
fd6cfc53 EA |
1387 | bool match, defaultpart; |
1388 | char begintype; | |
1389 | char db = '\0'; | |
217a0102 | 1390 | |
2bee003d EA |
1391 | if ((**rvp & 0377) != HOSTBEGIN && |
1392 | (**rvp & 0377) != LOOKUPBEGIN) | |
217a0102 EA |
1393 | continue; |
1394 | ||
1395 | /* | |
42fa5d67 | 1396 | ** Got a hostname/keyword lookup. |
217a0102 EA |
1397 | ** |
1398 | ** This could be optimized fairly easily. | |
1399 | */ | |
1400 | ||
fd6cfc53 | 1401 | begintype = **rvp; |
217a0102 | 1402 | hbrvp = rvp; |
fd6cfc53 | 1403 | ubrvp = NULL; |
2bee003d | 1404 | if ((**rvp & 0377) == HOSTBEGIN) |
42fa5d67 EA |
1405 | { |
1406 | endtoken = HOSTEND; | |
1407 | mapname = "host"; | |
1408 | } | |
1409 | else | |
1410 | { | |
1411 | endtoken = LOOKUPEND; | |
1412 | mapname = *++rvp; | |
1413 | } | |
1414 | map = stab(mapname, ST_MAP, ST_FIND); | |
1415 | if (map == NULL) | |
b6edea3d | 1416 | syserr("554 rewrite: map %s not found", mapname); |
217a0102 EA |
1417 | |
1418 | /* extract the match part */ | |
42fa5d67 | 1419 | key_rvp = ++rvp; |
5a4c03c6 EA |
1420 | default_rvp = NULL; |
1421 | arg_rvp = argvect; | |
1422 | xpvp = NULL; | |
1423 | replac = pvpbuf; | |
2bee003d | 1424 | while (*rvp != NULL && (**rvp & 0377) != endtoken) |
42fa5d67 | 1425 | { |
2bee003d | 1426 | int nodetype = **rvp & 0377; |
5a4c03c6 EA |
1427 | |
1428 | if (nodetype != CANONHOST && nodetype != CANONUSER) | |
1429 | { | |
1430 | rvp++; | |
1431 | continue; | |
1432 | } | |
1433 | ||
1434 | *rvp++ = NULL; | |
1435 | ||
1436 | if (xpvp != NULL) | |
1437 | { | |
4fcb2bfa | 1438 | cataddr(xpvp, NULL, replac, |
1c7897ef EA |
1439 | &pvpbuf[sizeof pvpbuf] - replac, |
1440 | '\0'); | |
5a4c03c6 EA |
1441 | *++arg_rvp = replac; |
1442 | replac += strlen(replac) + 1; | |
1443 | xpvp = NULL; | |
1444 | } | |
1445 | switch (nodetype) | |
42fa5d67 EA |
1446 | { |
1447 | case CANONHOST: | |
5a4c03c6 | 1448 | xpvp = rvp; |
42fa5d67 EA |
1449 | break; |
1450 | ||
1451 | case CANONUSER: | |
42fa5d67 EA |
1452 | default_rvp = rvp; |
1453 | break; | |
42fa5d67 EA |
1454 | } |
1455 | } | |
217a0102 EA |
1456 | if (*rvp != NULL) |
1457 | *rvp++ = NULL; | |
5a4c03c6 EA |
1458 | if (xpvp != NULL) |
1459 | { | |
4fcb2bfa | 1460 | cataddr(xpvp, NULL, replac, |
1c7897ef EA |
1461 | &pvpbuf[sizeof pvpbuf] - replac, |
1462 | '\0'); | |
5a4c03c6 EA |
1463 | *++arg_rvp = replac; |
1464 | } | |
1465 | *++arg_rvp = NULL; | |
217a0102 EA |
1466 | |
1467 | /* save the remainder of the input string */ | |
1468 | trsize = (int) (avp - rvp + 1) * sizeof *rvp; | |
1469 | bcopy((char *) rvp, (char *) pvpb1, trsize); | |
1470 | ||
217a0102 | 1471 | /* append it to the token list */ |
fd6cfc53 EA |
1472 | for (avp = hbrvp; *xpvp != NULL; xpvp++) |
1473 | { | |
7ac75266 | 1474 | *avp++ = newstr(*xpvp); |
c0ef545b | 1475 | if (avp >= &npvp[MAXATOM]) |
217a0102 | 1476 | goto toolong; |
fd6cfc53 | 1477 | } |
7ac75266 | 1478 | } |
fd6cfc53 EA |
1479 | else |
1480 | avp = hbrvp; | |
217a0102 EA |
1481 | |
1482 | /* restore the old trailing information */ | |
fd6cfc53 EA |
1483 | rvp = avp - 1; |
1484 | for (xpvp = pvpb1; *xpvp != NULL; xpvp++) | |
1485 | { | |
c40bef63 | 1486 | if (defaultpart && **xpvp == HOSTEND) |
fd6cfc53 EA |
1487 | { |
1488 | defaultpart = FALSE; | |
1489 | rvp = avp - 1; | |
1490 | } | |
1491 | else if (!defaultpart || !match) | |
1492 | *avp++ = *xpvp; | |
c0ef545b | 1493 | if (avp >= &npvp[MAXATOM]) |
217a0102 | 1494 | goto toolong; |
fd6cfc53 EA |
1495 | } |
1496 | *avp++ = NULL; | |
7ac75266 | 1497 | |
fd6cfc53 | 1498 | /*break;*/ |
217a0102 EA |
1499 | } |
1500 | ||
1501 | /* | |
1502 | ** Check for subroutine calls. | |
fd6cfc53 | 1503 | ** Then copy vector back into original space. |
217a0102 EA |
1504 | */ |
1505 | ||
fd6cfc53 | 1506 | |
41173b8f EA |
1507 | else |
1508 | subr = -1; | |
1509 | ||
1510 | /* | |
1511 | ** Copy result back to original string. | |
1512 | */ | |
1513 | ||
1514 | for (avp = pvp; *rvp != NULL; rvp++) | |
1515 | *avp++ = *rvp; | |
1516 | *avp = NULL; | |
1517 | ||
1518 | /* | |
1519 | ** If this specified a subroutine, call it. | |
1520 | */ | |
1521 | ||
1522 | if (subr >= 0) | |
1523 | { | |
1524 | # ifdef DEBUG | |
1525 | if (tTd(21, 3)) | |
1526 | printf("-----callsubr %s\n", subr); | |
1527 | # endif DEBUG | |
1528 | rewrite(pvp, subr); | |
1529 | } | |
1530 | ||
1531 | /* | |
1532 | ** Done with rewriting this pass. | |
1533 | */ | |
1534 | ||
7338e3d4 EA |
1535 | if (tTd(21, 4)) |
1536 | { | |
1537 | printf("rewritten as:"); | |
fd6cfc53 | 1538 | printcav(pvp); |
d6a28dd8 | 1539 | } |
b3cbe40f | 1540 | } |
b00e6882 | 1541 | |
25cc8f69 | 1542 | if (OpMode == MD_TEST || tTd(21, 1)) |
b00e6882 | 1543 | { |
b726abe3 | 1544 | printf("rewrite: ruleset %2d returns:", ruleset); |
fd6cfc53 | 1545 | printcav(pvp); |
b00e6882 | 1546 | } |
d1db7a89 EA |
1547 | |
1548 | return rstat; | |
d6a28dd8 EA |
1549 | } |
1550 | \f/* | |
fd6cfc53 EA |
1551 | ** CALLSUBR -- call subroutines in rewrite vector |
1552 | ** | |
1553 | ** Parameters: | |
1554 | ** pvp -- pointer to token vector. | |
1555 | ** | |
1556 | ** Returns: | |
1557 | ** none. | |
1558 | ** | |
1559 | ** Side Effects: | |
1560 | ** pvp is modified. | |
1561 | */ | |
1562 | ||
d30b0654 EA |
1563 | static int |
1564 | callsubr(pvp, reclevel, e) | |
1565 | char **pvp; | |
1566 | int reclevel; | |
1567 | ENVELOPE *e; | |
1568 | { | |
1569 | char **rvp; | |
1570 | int subr; | |
1571 | int stat; | |
1572 | STAB *s; | |
1573 | ||
1574 | for (; *pvp != NULL; pvp++) | |
1575 | { | |
1576 | if ((**pvp & 0377) == CALLSUBR && pvp[1] != NULL) | |
1577 | break; | |
1578 | } | |
1579 | if (*pvp == NULL) | |
1580 | return EX_OK; | |
1581 | ||
1582 | if (tTd(21, 3)) | |
1583 | printf("-----callsubr %s\n", pvp[1]); | |
1584 | ||
1585 | s = stab(pvp[1], ST_RULESET, ST_FIND); | |
1586 | if (s == NULL) | |
1587 | subr = atoi(pvp[1]); | |
1588 | else | |
1589 | subr = s->s_ruleset; | |
1590 | ||
1591 | /* | |
1592 | ** Take care of possible inner calls. | |
1593 | */ | |
1594 | ||
1595 | stat = callsubr(&pvp[2], reclevel, e); | |
1596 | if (stat != EX_OK) | |
1597 | return stat; | |
1598 | ||
1599 | /* | |
1600 | ** Move vector up over calling opcode. | |
1601 | */ | |
1602 | ||
1603 | for (rvp = &pvp[2]; *rvp != NULL; rvp++) | |
1604 | rvp[-2] = rvp[0]; | |
1605 | rvp[-2] = NULL; | |
1606 | ||
1607 | /* | |
1608 | ** Call inferior ruleset. | |
1609 | */ | |
1610 | ||
1611 | stat = rewrite(pvp, subr, reclevel, e); | |
1612 | return stat; | |
1613 | } | |
1614 | \f/* | |
1615 | ** CALLSUBR -- call subroutines in rewrite vector | |
1616 | ** | |
1617 | ** Parameters: | |
1618 | ** pvp -- pointer to token vector. | |
1619 | ** | |
1620 | ** Returns: | |
1621 | ** none. | |
1622 | ** | |
1623 | ** Side Effects: | |
1624 | ** pvp is modified. | |
1625 | */ | |
1626 | ||
fd6cfc53 EA |
1627 | static void |
1628 | callsubr(pvp) | |
1629 | char **pvp; | |
1630 | { | |
1631 | char **rvp; | |
1632 | int subr; | |
1633 | ||
1634 | for (; *pvp != NULL; pvp++) | |
1635 | if (**pvp == CALLSUBR && pvp[1] != NULL && isdigit(pvp[1][0])) | |
1636 | { | |
1637 | subr = atoi(pvp[1]); | |
1638 | ||
1639 | if (tTd(21, 3)) | |
1640 | printf("-----callsubr %d\n", subr); | |
1641 | ||
1642 | /* | |
1643 | ** Take care of possible inner calls. | |
1644 | */ | |
1645 | callsubr(pvp+2); | |
1646 | ||
1647 | /* | |
1648 | ** Move vector up over calling opcode. | |
1649 | */ | |
1650 | for (rvp = pvp+2; *rvp != NULL; rvp++) | |
1651 | rvp[-2] = rvp[0]; | |
1652 | rvp[-2] = NULL; | |
1653 | ||
1654 | /* | |
1655 | ** Call inferior ruleset. | |
1656 | */ | |
1657 | _rewrite(pvp, subr); | |
1658 | ||
1659 | break; | |
1660 | } | |
1661 | } | |
1662 | \f/* | |
d6a28dd8 EA |
1663 | ** BUILDADDR -- build address from token vector. |
1664 | ** | |
1665 | ** Parameters: | |
1666 | ** tv -- token vector. | |
1667 | ** a -- pointer to address descriptor to fill. | |
1668 | ** If NULL, one will be allocated. | |
28f94061 EA |
1669 | ** flags -- info regarding whether this is a sender or |
1670 | ** a recipient. | |
35b698c6 | 1671 | ** e -- the current envelope. |
d6a28dd8 EA |
1672 | ** |
1673 | ** Returns: | |
fe43b434 EA |
1674 | ** NULL if there was an error. |
1675 | ** 'a' otherwise. | |
d6a28dd8 EA |
1676 | ** |
1677 | ** Side Effects: | |
1678 | ** fills in 'a' | |
1679 | */ | |
1680 | ||
c796f255 EA |
1681 | struct errcodes |
1682 | { | |
1683 | char *ec_name; /* name of error code */ | |
1684 | int ec_code; /* numeric code */ | |
1685 | } ErrorCodes[] = | |
1686 | { | |
1687 | "usage", EX_USAGE, | |
1688 | "nouser", EX_NOUSER, | |
1689 | "nohost", EX_NOHOST, | |
1690 | "unavailable", EX_UNAVAILABLE, | |
1691 | "software", EX_SOFTWARE, | |
1692 | "tempfail", EX_TEMPFAIL, | |
1693 | "protocol", EX_PROTOCOL, | |
1694 | #ifdef EX_CONFIG | |
1695 | "config", EX_CONFIG, | |
1696 | #endif | |
1697 | NULL, EX_UNAVAILABLE, | |
1698 | }; | |
1699 | ||
fd6cfc53 | 1700 | static ADDRESS * |
28f94061 | 1701 | buildaddr(tv, a, flags, e) |
d6a28dd8 EA |
1702 | register char **tv; |
1703 | register ADDRESS *a; | |
28f94061 | 1704 | int flags; |
35b698c6 | 1705 | register ENVELOPE *e; |
d6a28dd8 | 1706 | { |
d6a28dd8 EA |
1707 | struct mailer **mp; |
1708 | register struct mailer *m; | |
5c5d2382 | 1709 | register char *p; |
5c5d2382 EA |
1710 | char *mname; |
1711 | char **hostp; | |
1712 | char hbuf[MAXNAME + 1]; | |
9577b1df EA |
1713 | static MAILER errormailer; |
1714 | static char *errorargv[] = { "ERROR", NULL }; | |
5c5d2382 | 1715 | static char ubuf[MAXNAME + 1]; |
d6a28dd8 | 1716 | |
b07c457d EA |
1717 | if (tTd(24, 5)) |
1718 | { | |
d6474f90 | 1719 | printf("buildaddr, flags=%x, tv=", flags); |
b07c457d EA |
1720 | printav(tv); |
1721 | } | |
1722 | ||
d6a28dd8 EA |
1723 | if (a == NULL) |
1724 | a = (ADDRESS *) xalloc(sizeof *a); | |
abae7b2d | 1725 | clear((char *) a, sizeof *a); |
d6a28dd8 | 1726 | |
68d9129a | 1727 | /* set up default error return flags */ |
82e3dc75 | 1728 | a->q_flags |= QPINGONFAILURE|QPINGONDELAY; |
68d9129a | 1729 | |
d6a28dd8 | 1730 | /* figure out what net/mailer to use */ |
fd6cfc53 | 1731 | if (*tv == NULL || **tv != CANONNET) |
fe43b434 | 1732 | { |
b6edea3d | 1733 | syserr("554 buildaddr: no net"); |
9577b1df EA |
1734 | badaddr: |
1735 | a->q_flags |= QBADADDR; | |
1736 | a->q_mailer = &errormailer; | |
1737 | if (errormailer.m_name == NULL) | |
1738 | { | |
1739 | /* initialize the bogus mailer */ | |
1740 | errormailer.m_name = "*error*"; | |
1741 | errormailer.m_mailer = "ERROR"; | |
1742 | errormailer.m_argv = errorargv; | |
1743 | } | |
1744 | return a; | |
fe43b434 | 1745 | } |
5c5d2382 EA |
1746 | mname = *++tv; |
1747 | ||
1748 | /* extract host and user portions */ | |
1749 | if ((**++tv & 0377) == CANONHOST) | |
1750 | hostp = ++tv; | |
1751 | else | |
1752 | hostp = NULL; | |
1753 | while (*tv != NULL && (**tv & 0377) != CANONUSER) | |
1754 | tv++; | |
1755 | if (*tv == NULL) | |
fe43b434 | 1756 | { |
5c5d2382 EA |
1757 | syserr("554 buildaddr: no user"); |
1758 | goto badaddr; | |
1759 | } | |
1760 | if (hostp != NULL) | |
1761 | cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); | |
1762 | cataddr(++tv, NULL, ubuf, sizeof ubuf, '\0'); | |
1763 | ||
1764 | /* save away the host name */ | |
1765 | if (strcasecmp(mname, "error") == 0) | |
1766 | { | |
1767 | if (hostp != NULL) | |
4fd73cf9 | 1768 | { |
c796f255 EA |
1769 | register struct errcodes *ep; |
1770 | ||
5c5d2382 EA |
1771 | if (strchr(hbuf, '.') != NULL) |
1772 | { | |
1773 | a->q_status = newstr(hbuf); | |
1774 | setstat(dsntoexitstat(hbuf)); | |
1775 | } | |
1776 | else if (isascii(hbuf[0]) && isdigit(hbuf[0])) | |
c796f255 | 1777 | { |
5c5d2382 | 1778 | setstat(atoi(hbuf)); |
c796f255 EA |
1779 | } |
1780 | else | |
1781 | { | |
1782 | for (ep = ErrorCodes; ep->ec_name != NULL; ep++) | |
5c5d2382 | 1783 | if (strcasecmp(ep->ec_name, hbuf) == 0) |
c796f255 EA |
1784 | break; |
1785 | setstat(ep->ec_code); | |
1786 | } | |
4fd73cf9 | 1787 | } |
b34fac73 EA |
1788 | else |
1789 | setstat(EX_UNAVAILABLE); | |
fd6cfc53 EA |
1790 | buf[0] = '\0'; |
1791 | for (; (*tv != NULL) && (**tv != CANONUSER); tv++) | |
1792 | { | |
1793 | if (buf[0] != '\0') | |
1794 | (void) strcat(buf, " "); | |
1795 | (void) strcat(buf, *tv); | |
1796 | } | |
5c5d2382 EA |
1797 | stripquotes(ubuf); |
1798 | if (isascii(ubuf[0]) && isdigit(ubuf[0]) && | |
1799 | isascii(ubuf[1]) && isdigit(ubuf[1]) && | |
1800 | isascii(ubuf[2]) && isdigit(ubuf[2]) && | |
1801 | ubuf[3] == ' ') | |
a10b59b5 EA |
1802 | { |
1803 | char fmt[10]; | |
1804 | ||
5c5d2382 | 1805 | strncpy(fmt, ubuf, 3); |
a10b59b5 | 1806 | strcpy(&fmt[3], " %s"); |
5c5d2382 | 1807 | usrerr(fmt, ubuf + 4); |
486825cf EA |
1808 | |
1809 | /* | |
1810 | ** If this is a 4xx code and we aren't running | |
1811 | ** SMTP on our input, bounce this message; | |
1812 | ** otherwise it disappears without a trace. | |
1813 | */ | |
1814 | ||
1815 | if (fmt[0] == '4' && OpMode != MD_SMTP && | |
1816 | OpMode != MD_DAEMON) | |
1817 | { | |
1818 | e->e_flags |= EF_FATALERRS; | |
1819 | } | |
a10b59b5 EA |
1820 | } |
1821 | else | |
1822 | { | |
5c5d2382 | 1823 | usrerr("553 %s", ubuf); |
a10b59b5 | 1824 | } |
9577b1df | 1825 | goto badaddr; |
fe43b434 | 1826 | } |
98e5062b | 1827 | |
179c1218 | 1828 | for (mp = Mailer; (m = *mp++) != NULL; ) |
d6a28dd8 | 1829 | { |
5c5d2382 | 1830 | if (strcasecmp(m->m_name, mname) == 0) |
d6a28dd8 EA |
1831 | break; |
1832 | } | |
1833 | if (m == NULL) | |
fe43b434 | 1834 | { |
5c5d2382 | 1835 | syserr("554 buildaddr: unknown mailer %s", mname); |
9577b1df | 1836 | goto badaddr; |
fe43b434 | 1837 | } |
179c1218 | 1838 | a->q_mailer = m; |
d6a28dd8 EA |
1839 | |
1840 | /* figure out what host (if any) */ | |
fd6cfc53 | 1841 | if (**++tv != CANONHOST) |
d6a28dd8 | 1842 | { |
6b3bbc1b EA |
1843 | a->q_host = NULL; |
1844 | } | |
1845 | else | |
1846 | { | |
fd6cfc53 EA |
1847 | else |
1848 | a->q_host = NULL; | |
1849 | } | |
1850 | else | |
1851 | { | |
d6a28dd8 EA |
1852 | |
1853 | /* figure out the user */ | |
5c5d2382 EA |
1854 | p = ubuf; |
1855 | if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') | |
1f116778 | 1856 | { |
5c5d2382 | 1857 | p++; |
1f116778 EA |
1858 | tv++; |
1859 | a->q_flags |= QNOTREMOTE; | |
1860 | } | |
1861 | ||
98e5062b | 1862 | /* do special mapping for local mailer */ |
5c5d2382 EA |
1863 | if (*p == '"') |
1864 | p++; | |
1865 | if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) | |
1866 | a->q_mailer = m = ProgMailer; | |
1867 | else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) | |
1868 | a->q_mailer = m = FileMailer; | |
1869 | else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) | |
98e5062b | 1870 | { |
5c5d2382 EA |
1871 | /* may be :include: */ |
1872 | stripquotes(ubuf); | |
1873 | if (strncasecmp(ubuf, ":include:", 9) == 0) | |
98e5062b | 1874 | { |
5c5d2382 EA |
1875 | /* if :include:, don't need further rewriting */ |
1876 | a->q_mailer = m = InclMailer; | |
1877 | a->q_user = newstr(&ubuf[9]); | |
1878 | return a; | |
98e5062b EA |
1879 | } |
1880 | } | |
d13779b1 | 1881 | |
c40bef63 EA |
1882 | if (m->m_r_rwset > 0) |
1883 | rewrite(tv, m->m_r_rwset); | |
b141a9b6 | 1884 | (void) rewrite(tv, 4, 0, e); |
5108b0cc EA |
1885 | |
1886 | /* save the result for the command line/RCPT argument */ | |
5c5d2382 EA |
1887 | cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); |
1888 | a->q_user = ubuf; | |
d6a28dd8 | 1889 | |
dd3ec3f5 EA |
1890 | /* |
1891 | ** Do mapping to lower case as requested by mailer | |
1892 | */ | |
1893 | ||
1894 | if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) | |
1895 | makelower(a->q_host); | |
1896 | if (!bitnset(M_USR_UPPER, m->m_flags)) | |
1897 | makelower(a->q_user); | |
1898 | ||
5c5d2382 | 1899 | return a; |
d6a28dd8 | 1900 | } |
9e3c0a28 | 1901 | \f/* |
31b33174 EA |
1902 | ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) |
1903 | ** | |
1904 | ** Parameters: | |
1905 | ** pvp -- parameter vector to rebuild. | |
4fcb2bfa EA |
1906 | ** evp -- last parameter to include. Can be NULL to |
1907 | ** use entire pvp. | |
31b33174 EA |
1908 | ** buf -- buffer to build the string into. |
1909 | ** sz -- size of buf. | |
1c7897ef EA |
1910 | ** spacesub -- the space separator character; if null, |
1911 | ** use SpaceSub. | |
31b33174 EA |
1912 | ** |
1913 | ** Returns: | |
1914 | ** none. | |
1915 | ** | |
1916 | ** Side Effects: | |
1917 | ** Destroys buf. | |
1918 | */ | |
1919 | ||
179d940c | 1920 | void |
fd6cfc53 | 1921 | void |
4fcb2bfa | 1922 | cataddr(pvp, evp, buf, sz, spacesub) |
31b33174 | 1923 | char **pvp; |
4fcb2bfa | 1924 | char **evp; |
31b33174 EA |
1925 | char *buf; |
1926 | register int sz; | |
179d940c | 1927 | int spacesub; |
31b33174 EA |
1928 | { |
1929 | bool oatomtok = FALSE; | |
fd6cfc53 | 1930 | bool natomtok; |
31b33174 EA |
1931 | register int i; |
1932 | register char *p; | |
1933 | ||
1c7897ef EA |
1934 | if (spacesub == '\0') |
1935 | spacesub = SpaceSub; | |
1936 | ||
e93460a9 EA |
1937 | if (pvp == NULL) |
1938 | { | |
03388044 | 1939 | (void) strcpy(buf, ""); |
e93460a9 EA |
1940 | return; |
1941 | } | |
31b33174 | 1942 | p = buf; |
89dd4c8f | 1943 | sz -= 2; |
31b33174 EA |
1944 | while (*pvp != NULL && (i = strlen(*pvp)) < sz) |
1945 | { | |
800c836f | 1946 | natomtok = (TokTypeTab[**pvp & 0xff] == ATM); |
31b33174 | 1947 | if (oatomtok && natomtok) |
1c7897ef | 1948 | *p++ = spacesub; |
31b33174 EA |
1949 | (void) strcpy(p, *pvp); |
1950 | oatomtok = natomtok; | |
1951 | p += i; | |
89dd4c8f | 1952 | sz -= i + 1; |
4fcb2bfa EA |
1953 | if (pvp++ == evp) |
1954 | break; | |
31b33174 EA |
1955 | } |
1956 | *p = '\0'; | |
1957 | } | |
1958 | \f/* | |
9e3c0a28 EA |
1959 | ** SAMEADDR -- Determine if two addresses are the same |
1960 | ** | |
1961 | ** This is not just a straight comparison -- if the mailer doesn't | |
1962 | ** care about the host we just ignore it, etc. | |
1963 | ** | |
1964 | ** Parameters: | |
1965 | ** a, b -- pointers to the internal forms to compare. | |
9e3c0a28 EA |
1966 | ** |
1967 | ** Returns: | |
1968 | ** TRUE -- they represent the same mailbox. | |
1969 | ** FALSE -- they don't. | |
1970 | ** | |
1971 | ** Side Effects: | |
1972 | ** none. | |
1973 | */ | |
1974 | ||
1975 | bool | |
7338e3d4 | 1976 | sameaddr(a, b) |
9e3c0a28 EA |
1977 | register ADDRESS *a; |
1978 | register ADDRESS *b; | |
9e3c0a28 | 1979 | { |
60d490ff EA |
1980 | register ADDRESS *ca, *cb; |
1981 | ||
9e3c0a28 EA |
1982 | /* if they don't have the same mailer, forget it */ |
1983 | if (a->q_mailer != b->q_mailer) | |
1984 | return (FALSE); | |
1985 | ||
1986 | /* if the user isn't the same, we can drop out */ | |
fd6cfc53 | 1987 | if (strcasecmp(a->q_user, b->q_user)) |
9e3c0a28 EA |
1988 | return (FALSE); |
1989 | ||
60d490ff | 1990 | /* if we have good uids for both but they differ, these are different */ |
180a908c EA |
1991 | if (a->q_mailer == ProgMailer) |
1992 | { | |
1993 | ca = getctladdr(a); | |
1994 | cb = getctladdr(b); | |
1995 | if (ca != NULL && cb != NULL && | |
1996 | bitset(QGOODUID, ca->q_flags & cb->q_flags) && | |
1997 | ca->q_uid != cb->q_uid) | |
1998 | return (FALSE); | |
1999 | } | |
4e535265 | 2000 | |
9e3c0a28 | 2001 | /* otherwise compare hosts (but be careful for NULL ptrs) */ |
fa085f58 EA |
2002 | if (a->q_host == b->q_host) |
2003 | { | |
2004 | /* probably both null pointers */ | |
2005 | return (TRUE); | |
2006 | } | |
9e3c0a28 | 2007 | if (a->q_host == NULL || b->q_host == NULL) |
fa085f58 EA |
2008 | { |
2009 | /* only one is a null pointer */ | |
9e3c0a28 | 2010 | return (FALSE); |
fa085f58 | 2011 | } |
fd6cfc53 | 2012 | if (strcasecmp(a->q_host, b->q_host)) |
9e3c0a28 EA |
2013 | return (FALSE); |
2014 | ||
2015 | return (TRUE); | |
2016 | } | |
779597d8 EA |
2017 | \f/* |
2018 | ** PRINTADDR -- print address (for debugging) | |
2019 | ** | |
2020 | ** Parameters: | |
2021 | ** a -- the address to print | |
2022 | ** follow -- follow the q_next chain. | |
2023 | ** | |
2024 | ** Returns: | |
2025 | ** none. | |
2026 | ** | |
2027 | ** Side Effects: | |
2028 | ** none. | |
2029 | */ | |
2030 | ||
bdd1eb9a EA |
2031 | struct qflags |
2032 | { | |
2033 | char *qf_name; | |
2034 | u_long qf_bit; | |
2035 | }; | |
2036 | ||
2037 | struct qflags AddressFlags[] = | |
2038 | { | |
2039 | "QDONTSEND", QDONTSEND, | |
2040 | "QBADADDR", QBADADDR, | |
2041 | "QGOODUID", QGOODUID, | |
2042 | "QPRIMARY", QPRIMARY, | |
2043 | "QQUEUEUP", QQUEUEUP, | |
2044 | "QSENT", QSENT, | |
2045 | "QNOTREMOTE", QNOTREMOTE, | |
2046 | "QSELFREF", QSELFREF, | |
2047 | "QVERIFIED", QVERIFIED, | |
bdd1eb9a EA |
2048 | "QBOGUSSHELL", QBOGUSSHELL, |
2049 | "QUNSAFEADDR", QUNSAFEADDR, | |
2050 | "QPINGONSUCCESS", QPINGONSUCCESS, | |
2051 | "QPINGONFAILURE", QPINGONFAILURE, | |
2052 | "QPINGONDELAY", QPINGONDELAY, | |
e1f691b3 | 2053 | "QHASNOTIFY", QHASNOTIFY, |
bdd1eb9a | 2054 | "QRELAYED", QRELAYED, |
126c1099 EA |
2055 | "QEXPANDED", QEXPANDED, |
2056 | "QDELIVERED", QDELIVERED, | |
2057 | "QDELAYED", QDELAYED, | |
66d16835 | 2058 | "QTHISPASS", QTHISPASS, |
bdd1eb9a EA |
2059 | NULL |
2060 | }; | |
2061 | ||
ea07b2d2 | 2062 | void |
fd6cfc53 | 2063 | void |
779597d8 EA |
2064 | printaddr(a, follow) |
2065 | register ADDRESS *a; | |
2066 | bool follow; | |
2067 | { | |
78bbbc48 EA |
2068 | register MAILER *m; |
2069 | MAILER pseudomailer; | |
bdd1eb9a EA |
2070 | register struct qflags *qfp; |
2071 | bool firstone; | |
2072 | ||
2073 | if (a == NULL) | |
2074 | { | |
2075 | printf("[NULL]\n"); | |
2076 | return; | |
2077 | } | |
d4f42161 | 2078 | |
abae7b2d EA |
2079 | static int indent; |
2080 | register int i; | |
2081 | ||
779597d8 EA |
2082 | while (a != NULL) |
2083 | { | |
abae7b2d EA |
2084 | for (i = indent; i > 0; i--) |
2085 | printf("\t"); | |
331b7c9f | 2086 | printf("%x=", a); |
29871fef | 2087 | (void) fflush(stdout); |
78bbbc48 EA |
2088 | |
2089 | /* find the mailer -- carefully */ | |
2090 | m = a->q_mailer; | |
2091 | if (m == NULL) | |
2092 | { | |
2093 | m = &pseudomailer; | |
2094 | m->m_mno = -1; | |
2095 | m->m_name = "NULL"; | |
2096 | } | |
2097 | ||
abae7b2d EA |
2098 | for (i = indent; i > 0; i--) |
2099 | printf("\t"); | |
2100 | printf("\tnext=%x, flags=%o, rmailer %d, alias=%x, sibling=%x, child=%x\n", | |
2101 | a->q_next, a->q_flags, a->q_rmailer, a->q_alias, | |
2102 | a->q_sibling, a->q_child); | |
2103 | ||
2104 | /* follow the chain if appropriate */ | |
779597d8 EA |
2105 | if (!follow) |
2106 | return; | |
abae7b2d EA |
2107 | |
2108 | indent++; | |
2109 | printaddr(a->q_child, TRUE); | |
2110 | indent--; | |
2111 | a = a->q_sibling; | |
779597d8 EA |
2112 | } |
2113 | } | |
f43d47fc EA |
2114 | \f/* |
2115 | ** EMPTYADDR -- return TRUE if this address is empty (``<>'') | |
2116 | ** | |
2117 | ** Parameters: | |
2118 | ** a -- pointer to the address | |
2119 | ** | |
2120 | ** Returns: | |
2121 | ** TRUE -- if this address is "empty" (i.e., no one should | |
2122 | ** ever generate replies to it. | |
2123 | ** FALSE -- if it is a "regular" (read: replyable) address. | |
2124 | */ | |
74c5fe7c | 2125 | |
f43d47fc EA |
2126 | bool |
2127 | emptyaddr(a) | |
2128 | register ADDRESS *a; | |
2129 | { | |
2130 | return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; | |
2131 | } | |
22892d62 EA |
2132 | \f/* |
2133 | ** REMOTENAME -- return the name relative to the current mailer | |
2134 | ** | |
2135 | ** Parameters: | |
2136 | ** name -- the name to translate. | |
b00e6882 EA |
2137 | ** m -- the mailer that we want to do rewriting relative |
2138 | ** to. | |
9e43a19e EA |
2139 | ** flags -- fine tune operations. |
2140 | ** pstat -- pointer to status word. | |
68f7099c | 2141 | ** e -- the current envelope. |
22892d62 EA |
2142 | ** |
2143 | ** Returns: | |
2144 | ** the text string representing this address relative to | |
2145 | ** the receiving mailer. | |
2146 | ** | |
2147 | ** Side Effects: | |
2148 | ** none. | |
2149 | ** | |
2150 | ** Warnings: | |
2151 | ** The text string returned is tucked away locally; | |
2152 | ** copy it if you intend to save it. | |
2153 | */ | |
2154 | ||
2155 | char * | |
9e43a19e | 2156 | remotename(name, m, flags, pstat, e) |
22892d62 | 2157 | char *name; |
fd6cfc53 | 2158 | MAILER *m; |
9e43a19e EA |
2159 | int flags; |
2160 | int *pstat; | |
a4076aed | 2161 | register ENVELOPE *e; |
22892d62 | 2162 | { |
b00e6882 EA |
2163 | register char **pvp; |
2164 | char *fancy; | |
a4076aed | 2165 | char *oldg = macvalue('g', e); |
68f7099c | 2166 | int rwset; |
8446c922 EA |
2167 | static char buf[MAXNAME + 1]; |
2168 | char lbuf[MAXNAME + 1]; | |
217a0102 | 2169 | char pvpbuf[PSBUFSIZE]; |
22892d62 | 2170 | |
e4b94f39 EA |
2171 | if (tTd(12, 1)) |
2172 | printf("remotename(%s)\n", name); | |
e4b94f39 | 2173 | |
4db45bf1 | 2174 | /* don't do anything if we are tagging it as special */ |
c40bef63 | 2175 | if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) |
4db45bf1 EA |
2176 | return (name); |
2177 | ||
22892d62 | 2178 | /* |
857afefe EA |
2179 | ** Do a heuristic crack of this name to extract any comment info. |
2180 | ** This will leave the name as a comment and a $g macro. | |
22892d62 EA |
2181 | */ |
2182 | ||
9e43a19e | 2183 | if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) |
2bee003d | 2184 | fancy = "\201g"; |
532c9874 EA |
2185 | else |
2186 | fancy = crackaddr(name); | |
0908f182 | 2187 | |
857afefe EA |
2188 | /* |
2189 | ** Turn the name into canonical form. | |
2190 | ** Normally this will be RFC 822 style, i.e., "user@domain". | |
2191 | ** If this only resolves to "user", and the "C" flag is | |
2192 | ** specified in the sending mailer, then the sender's | |
2193 | ** domain will be appended. | |
2194 | */ | |
2195 | ||
800c836f | 2196 | pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); |
0908f182 | 2197 | if (pvp == NULL) |
22892d62 | 2198 | return (name); |
b141a9b6 | 2199 | if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) |
9e43a19e EA |
2200 | *pstat = EX_TEMPFAIL; |
2201 | if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) | |
857afefe EA |
2202 | { |
2203 | /* append from domain to this address */ | |
2204 | register char **pxp = pvp; | |
2205 | ||
18c3cee9 | 2206 | /* see if there is an "@domain" in the current name */ |
857afefe EA |
2207 | while (*pxp != NULL && strcmp(*pxp, "@") != 0) |
2208 | pxp++; | |
2209 | if (*pxp == NULL) | |
2210 | { | |
18c3cee9 | 2211 | /* no.... append the "@domain" from the sender */ |
a4076aed | 2212 | register char **qxq = e->e_fromdomain; |
857afefe | 2213 | |
18c3cee9 EA |
2214 | while ((*pxp++ = *qxq++) != NULL) |
2215 | continue; | |
b141a9b6 | 2216 | if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) |
9e43a19e | 2217 | *pstat = EX_TEMPFAIL; |
857afefe EA |
2218 | } |
2219 | } | |
2220 | ||
2221 | /* | |
b726abe3 | 2222 | ** Do more specific rewriting. |
fd6cfc53 EA |
2223 | ** Rewrite using ruleset 1 or 2 for envelope addresses and |
2224 | ** 5 or 6 for header addresses depending on whether this | |
2225 | ** is a sender address or not. | |
857afefe EA |
2226 | ** Then run it through any receiving-mailer-specific rulesets. |
2227 | */ | |
2228 | ||
b00e6882 | 2229 | else |
9e4c75d5 | 2230 | { |
68f7099c | 2231 | if (rwset > 0) |
9e4c75d5 | 2232 | { |
b141a9b6 | 2233 | if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) |
9e43a19e | 2234 | *pstat = EX_TEMPFAIL; |
9e4c75d5 | 2235 | } |
22892d62 | 2236 | |
b726abe3 EA |
2237 | /* |
2238 | ** Do any final sanitation the address may require. | |
2239 | ** This will normally be used to turn internal forms | |
2240 | ** (e.g., user@host.LOCAL) into external form. This | |
2241 | ** may be used as a default to the above rules. | |
2242 | */ | |
2243 | ||
b141a9b6 | 2244 | if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) |
9e43a19e | 2245 | *pstat = EX_TEMPFAIL; |
b726abe3 | 2246 | |
857afefe EA |
2247 | /* |
2248 | ** Now restore the comment information we had at the beginning. | |
2249 | */ | |
2250 | ||
9d6aecfd | 2251 | cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); |
a4076aed | 2252 | define('g', lbuf, e); |
61fabf2e EA |
2253 | |
2254 | /* need to make sure route-addrs have <angle brackets> */ | |
2255 | if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') | |
832e8a27 | 2256 | expand("<\201g>", buf, sizeof buf, e); |
61fabf2e | 2257 | else |
832e8a27 | 2258 | expand(fancy, buf, sizeof buf, e); |
61fabf2e | 2259 | |
a4076aed | 2260 | define('g', oldg, e); |
22892d62 | 2261 | |
22892d62 | 2262 | if (tTd(12, 1)) |
e4b94f39 | 2263 | printf("remotename => `%s'\n", buf); |
22892d62 EA |
2264 | return (buf); |
2265 | } | |
d13779b1 | 2266 | \f/* |
fd6cfc53 EA |
2267 | ** UURELATIVIZE -- Make an address !-relative to recipient/sender nodes |
2268 | ** | |
2269 | ** Parameters: | |
2270 | ** from -- the sending node (usually "$k" or "$w") | |
2271 | ** to -- the receiving node (usually "$h") | |
2272 | ** pvp -- address vector | |
2273 | ** | |
2274 | ** Returns: | |
2275 | ** none. | |
2276 | ** | |
2277 | ** Side Effects: | |
2278 | ** The pvp is rewritten to be relative the "to" node | |
2279 | ** wrt the "from" node. In other words, if the pvp | |
2280 | ** is headed by "to!" that part is stripped; otherwise | |
2281 | ** "from!" is prepended. Exception: "to!user" addresses | |
2282 | ** with no '!'s in the user part are sent as is. | |
2283 | ** | |
2284 | ** Bugs: | |
2285 | ** The pvp may overflow, but we don't catch it. | |
2286 | */ | |
2287 | ||
2288 | static void | |
2289 | uurelativize(from, to, pvp) | |
2290 | const char *from, *to; | |
2291 | char **pvp; | |
2292 | { | |
2293 | register char **pxp = pvp; | |
2294 | char expfrom[MAXNAME], expto[MAXNAME]; | |
2295 | ||
2296 | expand(from, expfrom, &expfrom[sizeof expfrom - 1], CurEnv); | |
2297 | expand(to, expto, &expto[sizeof expto - 1], CurEnv); | |
2298 | ||
2299 | /* | |
2300 | * supposing that we've got something, should | |
2301 | * we add "from!" or remove "to!"? | |
2302 | */ | |
2303 | if (pvp[0] != NULL) | |
2304 | if (pvp[1] == NULL || strcmp(pvp[1], "!") != 0 || | |
2305 | /*strcasecmp?*/ strcmp(pvp[0], expto) != 0) | |
2306 | { | |
2307 | /* either local name, no UUCP address, */ | |
2308 | /* or not to "to!" ==> prepend address with "from!" */ | |
2309 | ||
2310 | /* already there? */ | |
2311 | if (pvp[1] == NULL || strcmp(pvp[1], "!") != 0 || | |
2312 | /*strcasecmp?*/ strcmp(pvp[0], expfrom) != 0) | |
2313 | { | |
2314 | ||
2315 | /* no, put it there */ | |
2316 | while (*pxp != NULL) | |
2317 | pxp++; | |
2318 | do | |
2319 | pxp[2] = *pxp; | |
2320 | while (pxp-- != pvp); | |
2321 | pvp[0] = newstr(expfrom); | |
2322 | pvp[1] = "!"; | |
2323 | } | |
2324 | } | |
2325 | else | |
2326 | { | |
2327 | /* address is to "to!" -- remove if not "to!user" */ | |
2328 | for (pxp = &pvp[2]; | |
2329 | *pxp != NULL && strcmp(*pxp, "!") != 0; pxp++) | |
2330 | ; | |
2331 | if (*pxp != NULL) | |
2332 | for (pxp = pvp; *pxp != NULL; pxp++) | |
2333 | *pxp = pxp[2]; | |
2334 | } | |
2335 | } | |
2336 | \f/* | |
d13779b1 EA |
2337 | ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection |
2338 | ** | |
2339 | ** Parameters: | |
2340 | ** a -- the address to map (but just the user name part). | |
2341 | ** sendq -- the sendq in which to install any replacement | |
2342 | ** addresses. | |
f8c2f9fd EA |
2343 | ** aliaslevel -- the alias nesting depth. |
2344 | ** e -- the envelope. | |
d13779b1 EA |
2345 | ** |
2346 | ** Returns: | |
2347 | ** none. | |
2348 | */ | |
2349 | ||
179d940c | 2350 | void |
f8c2f9fd | 2351 | maplocaluser(a, sendq, aliaslevel, e) |
d13779b1 EA |
2352 | register ADDRESS *a; |
2353 | ADDRESS **sendq; | |
f8c2f9fd | 2354 | int aliaslevel; |
a4076aed | 2355 | ENVELOPE *e; |
d13779b1 EA |
2356 | { |
2357 | register char **pvp; | |
2358 | register ADDRESS *a1 = NULL; | |
9e2cf26f | 2359 | auto char *delimptr; |
d13779b1 EA |
2360 | char pvpbuf[PSBUFSIZE]; |
2361 | ||
2362 | if (tTd(29, 1)) | |
2363 | { | |
2364 | printf("maplocaluser: "); | |
2365 | printaddr(a, FALSE); | |
2366 | } | |
800c836f | 2367 | pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); |
d13779b1 EA |
2368 | if (pvp == NULL) |
2369 | return; | |
2370 | ||
b141a9b6 | 2371 | (void) rewrite(pvp, 5, 0, e); |
2bee003d | 2372 | if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) |
d13779b1 EA |
2373 | return; |
2374 | ||
2375 | /* if non-null, mailer destination specified -- has it changed? */ | |
28f94061 | 2376 | a1 = buildaddr(pvp, NULL, 0, e); |
d13779b1 EA |
2377 | if (a1 == NULL || sameaddr(a, a1)) |
2378 | return; | |
2379 | ||
2380 | /* mark old address as dead; insert new address */ | |
2381 | a->q_flags |= QDONTSEND; | |
78bbbc48 EA |
2382 | if (tTd(29, 5)) |
2383 | { | |
2384 | printf("maplocaluser: QDONTSEND "); | |
2385 | printaddr(a, FALSE); | |
2386 | } | |
d13779b1 | 2387 | a1->q_alias = a; |
dab5fedb | 2388 | allocaddr(a1, RF_COPYALL, NULL); |
f8c2f9fd | 2389 | (void) recipient(a1, sendq, aliaslevel, e); |
d13779b1 | 2390 | } |
28d46d78 EA |
2391 | \f/* |
2392 | ** DEQUOTE_INIT -- initialize dequote map | |
2393 | ** | |
2394 | ** This is a no-op. | |
2395 | ** | |
2396 | ** Parameters: | |
2397 | ** map -- the internal map structure. | |
28d46d78 EA |
2398 | ** args -- arguments. |
2399 | ** | |
2400 | ** Returns: | |
2401 | ** TRUE. | |
2402 | */ | |
2403 | ||
2404 | bool | |
9114f86c | 2405 | dequote_init(map, args) |
28d46d78 | 2406 | MAP *map; |
28d46d78 EA |
2407 | char *args; |
2408 | { | |
5111538e EA |
2409 | register char *p = args; |
2410 | ||
2293b217 | 2411 | map->map_mflags |= MF_KEEPQUOTES; |
5111538e EA |
2412 | for (;;) |
2413 | { | |
2414 | while (isascii(*p) && isspace(*p)) | |
2415 | p++; | |
2416 | if (*p != '-') | |
2417 | break; | |
2418 | switch (*++p) | |
2419 | { | |
2420 | case 'a': | |
2421 | map->map_app = ++p; | |
2422 | break; | |
4cfe7b49 EA |
2423 | |
2424 | case 's': | |
2425 | map->map_coldelim = *++p; | |
2426 | break; | |
5111538e EA |
2427 | } |
2428 | while (*p != '\0' && !(isascii(*p) && isspace(*p))) | |
2429 | p++; | |
2430 | if (*p != '\0') | |
2431 | *p = '\0'; | |
2432 | } | |
2433 | if (map->map_app != NULL) | |
2434 | map->map_app = newstr(map->map_app); | |
2435 | ||
28d46d78 EA |
2436 | return TRUE; |
2437 | } | |
2438 | \f/* | |
2439 | ** DEQUOTE_MAP -- unquote an address | |
2440 | ** | |
2441 | ** Parameters: | |
2442 | ** map -- the internal map structure (ignored). | |
713c523f | 2443 | ** name -- the name to dequote. |
28d46d78 | 2444 | ** av -- arguments (ignored). |
d1db7a89 | 2445 | ** statp -- pointer to status out-parameter. |
28d46d78 EA |
2446 | ** |
2447 | ** Returns: | |
2448 | ** NULL -- if there were no quotes, or if the resulting | |
2449 | ** unquoted buffer would not be acceptable to prescan. | |
2450 | ** else -- The dequoted buffer. | |
2451 | */ | |
2452 | ||
2453 | char * | |
713c523f | 2454 | dequote_map(map, name, av, statp) |
28d46d78 | 2455 | MAP *map; |
713c523f | 2456 | char *name; |
28d46d78 | 2457 | char **av; |
d1db7a89 | 2458 | int *statp; |
28d46d78 EA |
2459 | { |
2460 | register char *p; | |
2461 | register char *q; | |
2462 | register char c; | |
4cfe7b49 EA |
2463 | int anglecnt = 0; |
2464 | int cmntcnt = 0; | |
2465 | int quotecnt = 0; | |
2466 | int spacecnt = 0; | |
2467 | bool quotemode = FALSE; | |
2468 | bool bslashmode = FALSE; | |
2469 | char spacesub = map->map_coldelim; | |
28d46d78 | 2470 | |
713c523f | 2471 | for (p = q = name; (c = *p++) != '\0'; ) |
28d46d78 EA |
2472 | { |
2473 | if (bslashmode) | |
2474 | { | |
2475 | bslashmode = FALSE; | |
2476 | *q++ = c; | |
2477 | continue; | |
2478 | } | |
2479 | ||
4cfe7b49 EA |
2480 | if (c == ' ' && spacesub != '\0') |
2481 | c = spacesub; | |
aff9529d | 2482 | |
28d46d78 EA |
2483 | switch (c) |
2484 | { | |
2485 | case '\\': | |
2486 | bslashmode = TRUE; | |
2487 | break; | |
2488 | ||
2489 | case '(': | |
2490 | cmntcnt++; | |
2491 | break; | |
2492 | ||
2493 | case ')': | |
2494 | if (cmntcnt-- <= 0) | |
2495 | return NULL; | |
2496 | break; | |
493ddf6a EA |
2497 | |
2498 | case ' ': | |
2499 | spacecnt++; | |
2500 | break; | |
28d46d78 EA |
2501 | } |
2502 | ||
2503 | if (cmntcnt > 0) | |
2504 | { | |
2505 | *q++ = c; | |
2506 | continue; | |
2507 | } | |
2508 | ||
2509 | switch (c) | |
2510 | { | |
2511 | case '"': | |
2512 | quotemode = !quotemode; | |
2513 | quotecnt++; | |
2514 | continue; | |
2515 | ||
2516 | case '<': | |
2517 | anglecnt++; | |
2518 | break; | |
2519 | ||
2520 | case '>': | |
2521 | if (anglecnt-- <= 0) | |
2522 | return NULL; | |
2523 | break; | |
2524 | } | |
2525 | *q++ = c; | |
2526 | } | |
2527 | ||
2528 | if (anglecnt != 0 || cmntcnt != 0 || bslashmode || | |
493ddf6a | 2529 | quotemode || quotecnt <= 0 || spacecnt != 0) |
28d46d78 EA |
2530 | return NULL; |
2531 | *q++ = '\0'; | |
713c523f | 2532 | return name; |
28d46d78 | 2533 | } |