Commit | Line | Data |
---|---|---|
b3cbe40f EA |
1 | # include <stdio.h> |
2 | # include <ctype.h> | |
406f98bc | 3 | # include "postbox.h" |
b3cbe40f | 4 | |
9e3c0a28 | 5 | static char SccsId[] = "@(#)parseaddr.c 3.8 %G%"; |
916b3375 | 6 | |
b3cbe40f EA |
7 | /* |
8 | ** PARSE -- Parse an address | |
9 | ** | |
10 | ** Parses an address and breaks it up into three parts: a | |
11 | ** net to transmit the message on, the host to transmit it | |
12 | ** to, and a user on that host. These are loaded into an | |
406f98bc | 13 | ** ADDRESS header with the values squirreled away if necessary. |
b3cbe40f EA |
14 | ** The "user" part may not be a real user; the process may |
15 | ** just reoccur on that machine. For example, on a machine | |
16 | ** with an arpanet connection, the address | |
17 | ** csvax.bill@berkeley | |
18 | ** will break up to a "user" of 'csvax.bill' and a host | |
19 | ** of 'berkeley' -- to be transmitted over the arpanet. | |
20 | ** | |
21 | ** Parameters: | |
22 | ** addr -- the address to parse. | |
23 | ** a -- a pointer to the address descriptor buffer. | |
24 | ** If NULL, a header will be created. | |
25 | ** copyf -- determines what shall be copied: | |
26 | ** -1 -- don't copy anything. The printname | |
27 | ** (q_paddr) is just addr, and the | |
28 | ** user & host are allocated internally | |
29 | ** to parse. | |
30 | ** 0 -- copy out the parsed user & host, but | |
31 | ** don't copy the printname. | |
32 | ** +1 -- copy everything. | |
33 | ** | |
34 | ** Returns: | |
35 | ** A pointer to the address descriptor header (`a' if | |
36 | ** `a' is non-NULL). | |
37 | ** NULL on error. | |
38 | ** | |
39 | ** Side Effects: | |
40 | ** none | |
41 | ** | |
b3cbe40f EA |
42 | ** Called By: |
43 | ** main | |
44 | ** sendto | |
45 | ** alias | |
46 | ** savemail | |
b3cbe40f EA |
47 | */ |
48 | ||
d6a28dd8 | 49 | # define DELIMCHARS "$()<>@!.,;:\\\" \t\r\n" /* word delimiters */ |
ecf90b7d EA |
50 | # define SPACESUB ('.'|0200) /* substitution for <lwsp> */ |
51 | ||
406f98bc | 52 | ADDRESS * |
b3cbe40f EA |
53 | parse(addr, a, copyf) |
54 | char *addr; | |
406f98bc | 55 | register ADDRESS *a; |
b3cbe40f EA |
56 | int copyf; |
57 | { | |
d6a28dd8 EA |
58 | register char **pvp; |
59 | register struct mailer *m; | |
60 | extern char **prescan(); | |
406f98bc | 61 | extern char *newstr(); |
7b9c35c8 | 62 | extern char *strcpy(); |
d6a28dd8 | 63 | extern ADDRESS *buildaddr(); |
b3cbe40f EA |
64 | |
65 | /* | |
66 | ** Initialize and prescan address. | |
67 | */ | |
68 | ||
69 | To = addr; | |
9e3c0a28 EA |
70 | # ifdef DEBUG |
71 | if (Debug) | |
72 | printf("\n--parse(%s)\n", addr); | |
73 | # endif DEBUG | |
74 | ||
d6a28dd8 EA |
75 | pvp = prescan(addr, '\0'); |
76 | if (pvp == NULL) | |
b3cbe40f EA |
77 | return (NULL); |
78 | ||
79 | /* | |
d6a28dd8 | 80 | ** Apply rewriting rules. |
b3cbe40f EA |
81 | */ |
82 | ||
d6a28dd8 | 83 | rewrite(pvp); |
b3cbe40f | 84 | |
d6a28dd8 EA |
85 | /* |
86 | ** See if we resolved to a real mailer. | |
87 | */ | |
b3cbe40f | 88 | |
d6a28dd8 EA |
89 | if (pvp[0][0] != CANONNET) |
90 | { | |
91 | setstat(EX_USAGE); | |
92 | usrerr("cannot resolve name"); | |
93 | return (NULL); | |
b3cbe40f EA |
94 | } |
95 | ||
96 | /* | |
d6a28dd8 | 97 | ** Build canonical address from pvp. |
b3cbe40f EA |
98 | */ |
99 | ||
d6a28dd8 EA |
100 | a = buildaddr(pvp, a); |
101 | m = Mailer[a->q_mailer]; | |
b3cbe40f EA |
102 | |
103 | /* | |
d6a28dd8 EA |
104 | ** Make local copies of the host & user and then |
105 | ** transport them out. | |
b3cbe40f EA |
106 | */ |
107 | ||
b3cbe40f | 108 | if (copyf > 0) |
406f98bc | 109 | a->q_paddr = newstr(addr); |
b3cbe40f EA |
110 | else |
111 | a->q_paddr = addr; | |
b3cbe40f | 112 | |
d6a28dd8 | 113 | if (copyf >= 0) |
b3cbe40f | 114 | { |
d6a28dd8 | 115 | if (a->q_host != NULL) |
406f98bc | 116 | a->q_host = newstr(a->q_host); |
d6a28dd8 EA |
117 | else |
118 | a->q_host = ""; | |
119 | if (a->q_user != a->q_paddr) | |
120 | a->q_user = newstr(a->q_user); | |
b3cbe40f EA |
121 | } |
122 | ||
123 | /* | |
124 | ** Do UPPER->lower case mapping unless inhibited. | |
125 | */ | |
126 | ||
d6a28dd8 | 127 | if (!bitset(M_HST_UPPER, m->m_flags)) |
b3cbe40f | 128 | makelower(a->q_host); |
d6a28dd8 | 129 | if (!bitset(M_USR_UPPER, m->m_flags)) |
b3cbe40f EA |
130 | makelower(a->q_user); |
131 | ||
132 | /* | |
133 | ** Compute return value. | |
134 | */ | |
135 | ||
136 | # ifdef DEBUG | |
7160a5cb | 137 | if (Debug) |
b3cbe40f | 138 | printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", |
d6a28dd8 | 139 | addr, a->q_host, a->q_user, a->q_mailer); |
b3cbe40f EA |
140 | # endif DEBUG |
141 | ||
142 | return (a); | |
143 | } | |
144 | \f/* | |
b3cbe40f EA |
145 | ** PRESCAN -- Prescan name and make it canonical |
146 | ** | |
147 | ** Scans a name and turns it into canonical form. This involves | |
148 | ** deleting blanks, comments (in parentheses), and turning the | |
149 | ** word "at" into an at-sign ("@"). The name is copied as this | |
150 | ** is done; it is legal to copy a name onto itself, since this | |
151 | ** process can only make things smaller. | |
152 | ** | |
153 | ** This routine knows about quoted strings and angle brackets. | |
154 | ** | |
155 | ** There are certain subtleties to this routine. The one that | |
156 | ** comes to mind now is that backslashes on the ends of names | |
157 | ** are silently stripped off; this is intentional. The problem | |
158 | ** is that some versions of sndmsg (like at LBL) set the kill | |
159 | ** character to something other than @ when reading addresses; | |
160 | ** so people type "csvax.eric\@berkeley" -- which screws up the | |
161 | ** berknet mailer. | |
162 | ** | |
163 | ** Parameters: | |
164 | ** addr -- the name to chomp. | |
b3cbe40f EA |
165 | ** delim -- the delimiter for the address, normally |
166 | ** '\0' or ','; \0 is accepted in any case. | |
167 | ** are moving in place; set buflim to high core. | |
168 | ** | |
169 | ** Returns: | |
d6a28dd8 | 170 | ** A pointer to a vector of tokens. |
b3cbe40f EA |
171 | ** NULL on error. |
172 | ** | |
173 | ** Side Effects: | |
d6a28dd8 | 174 | ** none. |
b3cbe40f EA |
175 | */ |
176 | ||
d6a28dd8 EA |
177 | # define OPER 1 |
178 | # define ATOM 2 | |
179 | # define EOTOK 3 | |
180 | # define QSTRING 4 | |
181 | # define SPACE 5 | |
182 | # define DOLLAR 6 | |
183 | # define GETONE 7 | |
184 | ||
185 | char ** | |
186 | prescan(addr, delim) | |
b3cbe40f | 187 | char *addr; |
b3cbe40f EA |
188 | char delim; |
189 | { | |
190 | register char *p; | |
d6a28dd8 EA |
191 | static char buf[MAXNAME+MAXATOM]; |
192 | static char *av[MAXATOM+1]; | |
193 | char **avp; | |
b3cbe40f | 194 | bool space; |
b3cbe40f EA |
195 | bool bslashmode; |
196 | int cmntcnt; | |
197 | int brccnt; | |
198 | register char c; | |
d6a28dd8 | 199 | char *tok; |
b3cbe40f | 200 | register char *q; |
406f98bc | 201 | extern char *index(); |
d6a28dd8 EA |
202 | register int state; |
203 | int nstate; | |
b3cbe40f | 204 | |
ecf90b7d | 205 | space = FALSE; |
b3cbe40f | 206 | q = buf; |
d6a28dd8 | 207 | bslashmode = FALSE; |
b3cbe40f | 208 | cmntcnt = brccnt = 0; |
d6a28dd8 EA |
209 | avp = av; |
210 | state = OPER; | |
211 | for (p = addr; *p != '\0' && *p != delim; ) | |
b3cbe40f | 212 | { |
d6a28dd8 EA |
213 | /* read a token */ |
214 | tok = q; | |
215 | while ((c = *p++) != '\0' && c != delim) | |
b3cbe40f | 216 | { |
d6a28dd8 EA |
217 | /* chew up special characters */ |
218 | *q = '\0'; | |
219 | if (bslashmode) | |
220 | { | |
221 | c |= 0200; | |
222 | bslashmode = FALSE; | |
223 | } | |
224 | else if (c == '\\') | |
225 | { | |
226 | bslashmode = TRUE; | |
227 | continue; | |
228 | } | |
229 | ||
230 | nstate = toktype(c); | |
231 | switch (state) | |
232 | { | |
233 | case QSTRING: /* in quoted string */ | |
234 | if (c == '"') | |
235 | state = OPER; | |
236 | break; | |
237 | ||
238 | case ATOM: /* regular atom */ | |
239 | state = nstate; | |
240 | if (state != ATOM) | |
241 | { | |
242 | state = EOTOK; | |
243 | p--; | |
244 | } | |
245 | break; | |
246 | ||
247 | case GETONE: /* grab one character */ | |
248 | state = OPER; | |
249 | break; | |
250 | ||
251 | case EOTOK: /* after atom or q-string */ | |
252 | state = nstate; | |
253 | if (state == SPACE) | |
254 | continue; | |
255 | break; | |
256 | ||
257 | case SPACE: /* linear white space */ | |
258 | state = nstate; | |
259 | space = TRUE; | |
260 | continue; | |
261 | ||
262 | case OPER: /* operator */ | |
263 | if (nstate == SPACE) | |
264 | continue; | |
265 | state = nstate; | |
266 | break; | |
267 | ||
268 | case DOLLAR: /* $- etc. */ | |
269 | state = OPER; | |
270 | switch (c) | |
271 | { | |
272 | case '$': /* literal $ */ | |
273 | break; | |
274 | ||
275 | case '+': /* match anything */ | |
276 | c = MATCHANY; | |
277 | state = GETONE; | |
278 | break; | |
279 | ||
280 | case '-': /* match one token */ | |
281 | c = MATCHONE; | |
282 | state = GETONE; | |
283 | break; | |
284 | ||
285 | case '#': /* canonical net name */ | |
286 | c = CANONNET; | |
287 | break; | |
288 | ||
289 | case '@': /* canonical host name */ | |
290 | c = CANONHOST; | |
291 | break; | |
292 | ||
293 | case ':': /* canonical user name */ | |
294 | c = CANONUSER; | |
295 | break; | |
296 | ||
297 | default: | |
298 | c = '$'; | |
299 | state = OPER; | |
300 | p--; | |
301 | break; | |
302 | } | |
303 | break; | |
304 | ||
305 | default: | |
306 | syserr("prescan: unknown state %d", state); | |
307 | } | |
308 | ||
309 | if (state == OPER) | |
310 | space = FALSE; | |
311 | else if (state == EOTOK) | |
312 | break; | |
313 | if (c == '$' && delim == '\t') | |
314 | { | |
315 | state = DOLLAR; | |
316 | continue; | |
317 | } | |
318 | ||
319 | /* squirrel it away */ | |
320 | if (q >= &buf[sizeof buf - 5]) | |
321 | { | |
322 | usrerr("Address too long"); | |
323 | return (NULL); | |
324 | } | |
325 | if (space) | |
326 | *q++ = SPACESUB; | |
327 | *q++ = c; | |
328 | ||
329 | /* decide whether this represents end of token */ | |
330 | if (state == OPER) | |
331 | break; | |
b3cbe40f | 332 | } |
d6a28dd8 EA |
333 | if (c == '\0' || c == delim) |
334 | p--; | |
335 | ||
336 | /* new token */ | |
337 | if (tok == q) | |
b3cbe40f | 338 | continue; |
d6a28dd8 EA |
339 | *q++ = '\0'; |
340 | ||
341 | c = tok[0]; | |
342 | if (c == '(') | |
2a119b55 | 343 | { |
b3cbe40f | 344 | cmntcnt++; |
2a119b55 EA |
345 | continue; |
346 | } | |
b3cbe40f EA |
347 | else if (c == ')') |
348 | { | |
349 | if (cmntcnt <= 0) | |
350 | { | |
351 | usrerr("Unbalanced ')'"); | |
352 | return (NULL); | |
353 | } | |
354 | else | |
355 | { | |
356 | cmntcnt--; | |
357 | continue; | |
358 | } | |
359 | } | |
d6a28dd8 | 360 | else if (cmntcnt > 0) |
ecf90b7d | 361 | continue; |
d6a28dd8 EA |
362 | |
363 | *avp++ = tok; | |
364 | ||
365 | /* we prefer <> specs */ | |
366 | if (c == '<') | |
b3cbe40f | 367 | { |
7a8fc396 EA |
368 | if (brccnt < 0) |
369 | { | |
370 | usrerr("multiple < spec"); | |
371 | return (NULL); | |
372 | } | |
b3cbe40f | 373 | brccnt++; |
ecf90b7d | 374 | space = FALSE; |
b3cbe40f EA |
375 | if (brccnt == 1) |
376 | { | |
377 | /* we prefer using machine readable name */ | |
378 | q = buf; | |
379 | *q = '\0'; | |
d6a28dd8 | 380 | avp = av; |
b3cbe40f EA |
381 | continue; |
382 | } | |
383 | } | |
384 | else if (c == '>') | |
385 | { | |
386 | if (brccnt <= 0) | |
387 | { | |
388 | usrerr("Unbalanced `>'"); | |
389 | return (NULL); | |
390 | } | |
391 | else | |
392 | brccnt--; | |
393 | if (brccnt <= 0) | |
7a8fc396 EA |
394 | { |
395 | brccnt = -1; | |
b3cbe40f | 396 | continue; |
7a8fc396 | 397 | } |
b3cbe40f EA |
398 | } |
399 | ||
400 | /* | |
401 | ** Turn "at" into "@", | |
2a119b55 | 402 | ** but only if "at" is a word. |
b3cbe40f EA |
403 | */ |
404 | ||
d6a28dd8 | 405 | if (lower(tok[0]) == 'a' && lower(tok[1]) == 't' && tok[2] == '\0') |
b3cbe40f | 406 | { |
d6a28dd8 EA |
407 | tok[0] = '@'; |
408 | tok[1] = '\0'; | |
b3cbe40f | 409 | } |
d6a28dd8 EA |
410 | } |
411 | *avp = NULL; | |
412 | if (cmntcnt > 0) | |
413 | usrerr("Unbalanced '('"); | |
414 | else if (brccnt > 0) | |
415 | usrerr("Unbalanced '<'"); | |
416 | else if (state == QSTRING) | |
417 | usrerr("Unbalanced '\"'"); | |
418 | else if (av[0] != NULL) | |
419 | return (av); | |
420 | return (NULL); | |
421 | } | |
422 | \f/* | |
423 | ** TOKTYPE -- return token type | |
424 | ** | |
425 | ** Parameters: | |
426 | ** c -- the character in question. | |
427 | ** | |
428 | ** Returns: | |
429 | ** Its type. | |
430 | ** | |
431 | ** Side Effects: | |
432 | ** none. | |
433 | */ | |
b3cbe40f | 434 | |
d6a28dd8 EA |
435 | toktype(c) |
436 | register char c; | |
437 | { | |
438 | if (isspace(c)) | |
439 | return (SPACE); | |
440 | if (index(DELIMCHARS, c) != NULL || iscntrl(c)) | |
441 | return (OPER); | |
442 | return (ATOM); | |
443 | } | |
444 | \f/* | |
445 | ** REWRITE -- apply rewrite rules to token vector. | |
446 | ** | |
447 | ** Parameters: | |
448 | ** pvp -- pointer to token vector. | |
449 | ** | |
450 | ** Returns: | |
451 | ** none. | |
452 | ** | |
453 | ** Side Effects: | |
454 | ** pvp is modified. | |
455 | */ | |
456 | ||
457 | struct match | |
458 | { | |
459 | char **firsttok; /* first token matched */ | |
460 | char **lasttok; /* last token matched */ | |
461 | char name; /* name of parameter */ | |
462 | }; | |
463 | ||
464 | # define MAXMATCH 8 /* max params per rewrite */ | |
465 | ||
466 | ||
467 | rewrite(pvp) | |
468 | char **pvp; | |
469 | { | |
470 | register char *ap; /* address pointer */ | |
471 | register char *rp; /* rewrite pointer */ | |
472 | register char **avp; /* address vector pointer */ | |
473 | register char **rvp; /* rewrite vector pointer */ | |
474 | struct rewrite *rwr; | |
475 | struct match mlist[MAXMATCH]; | |
476 | char *npvp[MAXATOM+1]; /* temporary space for rebuild */ | |
477 | ||
9e3c0a28 | 478 | # ifdef DEBUGX |
d6a28dd8 EA |
479 | if (Debug) |
480 | { | |
481 | printf("rewrite: original pvp:\n"); | |
482 | printav(pvp); | |
483 | } | |
9e3c0a28 | 484 | # endif DEBUGX |
d6a28dd8 EA |
485 | |
486 | /* | |
487 | ** Run through the list of rewrite rules, applying | |
488 | ** any that match. | |
489 | */ | |
490 | ||
491 | for (rwr = RewriteRules; rwr != NULL; ) | |
492 | { | |
9e3c0a28 | 493 | # ifdef DEBUGX |
d6a28dd8 EA |
494 | if (Debug) |
495 | { | |
496 | printf("-----trying rule:\n"); | |
497 | printav(rwr->r_lhs); | |
498 | } | |
9e3c0a28 | 499 | # endif DEBUGX |
ecf90b7d | 500 | |
d6a28dd8 EA |
501 | /* try to match on this rule */ |
502 | clrmatch(mlist); | |
503 | for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) | |
b3cbe40f | 504 | { |
d6a28dd8 EA |
505 | ap = *avp; |
506 | rp = *rvp; | |
507 | ||
508 | if (rp == NULL) | |
b3cbe40f | 509 | { |
d6a28dd8 EA |
510 | /* end-of-pattern before end-of-address */ |
511 | goto fail; | |
512 | } | |
513 | ||
514 | switch (*rp) | |
515 | { | |
516 | case MATCHONE: | |
517 | /* match exactly one token */ | |
518 | setmatch(mlist, rp[1], avp, avp); | |
519 | break; | |
520 | ||
521 | case MATCHANY: | |
522 | /* match any number of tokens */ | |
523 | setmatch(mlist, rp[1], NULL, avp); | |
524 | break; | |
525 | ||
526 | default: | |
527 | /* must have exact match */ | |
528 | /* can scribble rp & ap here safely */ | |
5e81958e | 529 | while (*rp != '\0' || *ap != '\0') |
d6a28dd8 EA |
530 | { |
531 | if (*rp++ != lower(*ap++)) | |
532 | goto fail; | |
533 | } | |
534 | break; | |
535 | } | |
536 | ||
537 | /* successful match on this token */ | |
538 | avp++; | |
539 | rvp++; | |
540 | continue; | |
541 | ||
542 | fail: | |
543 | /* match failed -- back up */ | |
544 | while (--rvp >= rwr->r_lhs) | |
545 | { | |
546 | rp = *rvp; | |
547 | if (*rp == MATCHANY) | |
548 | break; | |
549 | ||
550 | /* can't extend match: back up everything */ | |
551 | avp--; | |
552 | ||
553 | if (*rp == MATCHONE) | |
554 | { | |
555 | /* undo binding */ | |
556 | setmatch(mlist, rp[1], NULL, NULL); | |
557 | } | |
558 | } | |
559 | ||
560 | if (rvp < rwr->r_lhs) | |
561 | { | |
562 | /* total failure to match */ | |
563 | break; | |
b3cbe40f | 564 | } |
b3cbe40f | 565 | } |
d6a28dd8 EA |
566 | |
567 | /* | |
568 | ** See if we successfully matched | |
569 | */ | |
570 | ||
571 | if (rvp >= rwr->r_lhs && *rvp == NULL) | |
572 | { | |
9e3c0a28 | 573 | # ifdef DEBUGX |
d6a28dd8 EA |
574 | if (Debug) |
575 | { | |
576 | printf("-----rule matches:\n"); | |
577 | printav(rwr->r_rhs); | |
578 | } | |
9e3c0a28 | 579 | # endif DEBUGX |
d6a28dd8 EA |
580 | |
581 | /* substitute */ | |
582 | for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) | |
583 | { | |
584 | rp = *rvp; | |
585 | if (*rp == MATCHANY) | |
586 | { | |
587 | register struct match *m; | |
588 | register char **pp; | |
589 | extern struct match *findmatch(); | |
590 | ||
591 | m = findmatch(mlist, rp[1]); | |
592 | if (m != NULL) | |
593 | { | |
594 | pp = m->firsttok; | |
595 | do | |
596 | { | |
597 | *avp++ = *pp; | |
598 | } while (pp++ != m->lasttok); | |
599 | } | |
600 | } | |
601 | else | |
602 | *avp++ = rp; | |
603 | } | |
604 | *avp++ = NULL; | |
605 | bmove(npvp, pvp, (avp - npvp) * sizeof *avp); | |
606 | # ifdef DEBUG | |
607 | if (Debug) | |
608 | { | |
9e3c0a28 EA |
609 | char **vp; |
610 | ||
611 | printf("rewritten as `"); | |
612 | for (vp = pvp; *vp != NULL; vp++) | |
613 | xputs(*vp); | |
614 | printf("'\n"); | |
d6a28dd8 EA |
615 | } |
616 | # endif DEBUG | |
617 | if (pvp[0][0] == CANONNET) | |
618 | break; | |
619 | } | |
620 | else | |
621 | { | |
9e3c0a28 | 622 | # ifdef DEBUGX |
d6a28dd8 EA |
623 | if (Debug) |
624 | printf("----- rule fails\n"); | |
9e3c0a28 | 625 | # endif DEBUGX |
d6a28dd8 EA |
626 | rwr = rwr->r_next; |
627 | } | |
b3cbe40f | 628 | } |
d6a28dd8 EA |
629 | } |
630 | \f/* | |
631 | ** SETMATCH -- set parameter value in match vector | |
632 | ** | |
633 | ** Parameters: | |
634 | ** mlist -- list of match values. | |
635 | ** name -- the character name of this parameter. | |
636 | ** first -- the first location of the replacement. | |
637 | ** last -- the last location of the replacement. | |
638 | ** | |
639 | ** If last == NULL, delete this entry. | |
640 | ** If first == NULL, extend this entry (or add it if | |
641 | ** it does not exist). | |
642 | ** | |
643 | ** Returns: | |
644 | ** nothing. | |
645 | ** | |
646 | ** Side Effects: | |
647 | ** munges with mlist. | |
648 | */ | |
649 | ||
650 | setmatch(mlist, name, first, last) | |
651 | struct match *mlist; | |
652 | char name; | |
653 | char **first; | |
654 | char **last; | |
655 | { | |
656 | register struct match *m; | |
657 | struct match *nullm = NULL; | |
658 | ||
659 | for (m = mlist; m < &mlist[MAXMATCH]; m++) | |
660 | { | |
661 | if (m->name == name) | |
662 | break; | |
663 | if (m->name == '\0') | |
664 | nullm = m; | |
665 | } | |
666 | ||
667 | if (m >= &mlist[MAXMATCH]) | |
668 | m = nullm; | |
669 | ||
670 | if (last == NULL) | |
671 | { | |
672 | m->name = '\0'; | |
673 | return; | |
674 | } | |
675 | ||
676 | if (m->name == '\0') | |
677 | { | |
678 | if (first == NULL) | |
679 | m->firsttok = last; | |
680 | else | |
681 | m->firsttok = first; | |
682 | } | |
683 | m->name = name; | |
684 | m->lasttok = last; | |
685 | } | |
686 | \f/* | |
687 | ** FINDMATCH -- find match in mlist | |
688 | ** | |
689 | ** Parameters: | |
690 | ** mlist -- list to search. | |
691 | ** name -- name to find. | |
692 | ** | |
693 | ** Returns: | |
694 | ** pointer to match structure. | |
695 | ** NULL if no match. | |
696 | ** | |
697 | ** Side Effects: | |
698 | ** none. | |
699 | */ | |
700 | ||
701 | struct match * | |
702 | findmatch(mlist, name) | |
703 | struct match *mlist; | |
704 | char name; | |
705 | { | |
706 | register struct match *m; | |
707 | ||
708 | for (m = mlist; m < &mlist[MAXMATCH]; m++) | |
709 | { | |
710 | if (m->name == name) | |
711 | return (m); | |
712 | } | |
713 | ||
b3cbe40f EA |
714 | return (NULL); |
715 | } | |
d6a28dd8 EA |
716 | \f/* |
717 | ** CLRMATCH -- clear match list | |
718 | ** | |
719 | ** Parameters: | |
720 | ** mlist -- list to clear. | |
721 | ** | |
722 | ** Returns: | |
723 | ** none. | |
724 | ** | |
725 | ** Side Effects: | |
726 | ** mlist is cleared. | |
727 | */ | |
728 | ||
729 | clrmatch(mlist) | |
730 | struct match *mlist; | |
731 | { | |
732 | register struct match *m; | |
733 | ||
734 | for (m = mlist; m < &mlist[MAXMATCH]; m++) | |
735 | m->name = '\0'; | |
736 | } | |
737 | \f/* | |
738 | ** BUILDADDR -- build address from token vector. | |
739 | ** | |
740 | ** Parameters: | |
741 | ** tv -- token vector. | |
742 | ** a -- pointer to address descriptor to fill. | |
743 | ** If NULL, one will be allocated. | |
744 | ** | |
745 | ** Returns: | |
746 | ** 'a' | |
747 | ** | |
748 | ** Side Effects: | |
749 | ** fills in 'a' | |
750 | */ | |
751 | ||
752 | ADDRESS * | |
753 | buildaddr(tv, a) | |
754 | register char **tv; | |
755 | register ADDRESS *a; | |
756 | { | |
757 | register int i; | |
758 | static char buf[MAXNAME]; | |
759 | struct mailer **mp; | |
760 | register struct mailer *m; | |
761 | extern char *xalloc(); | |
762 | ||
763 | if (a == NULL) | |
764 | a = (ADDRESS *) xalloc(sizeof *a); | |
9e3c0a28 | 765 | a->q_flags = 0; |
d6a28dd8 EA |
766 | |
767 | /* figure out what net/mailer to use */ | |
768 | if (**tv != CANONNET) | |
769 | syserr("buildaddr: no net"); | |
770 | tv++; | |
5e81958e | 771 | for (mp = Mailer, i = 0; (m = *mp++) != NULL; i++) |
d6a28dd8 EA |
772 | { |
773 | if (strcmp(m->m_name, *tv) == 0) | |
774 | break; | |
775 | } | |
776 | if (m == NULL) | |
777 | syserr("buildaddr: unknown net %s", *tv); | |
778 | a->q_mailer = i; | |
779 | ||
780 | /* figure out what host (if any) */ | |
781 | tv++; | |
782 | if (!bitset(M_NOHOST, m->m_flags)) | |
783 | { | |
784 | if (**tv != CANONHOST) | |
785 | syserr("buildaddr: no host"); | |
786 | tv++; | |
787 | a->q_host = *tv; | |
788 | tv++; | |
789 | } | |
790 | else | |
791 | a->q_host = NULL; | |
792 | ||
793 | /* figure out the user */ | |
794 | if (**tv != CANONUSER) | |
795 | syserr("buildaddr: no user"); | |
796 | buf[0] = '\0'; | |
797 | while (**++tv != NULL) | |
798 | strcat(buf, *tv); | |
799 | a->q_user = buf; | |
800 | ||
801 | return (a); | |
802 | } | |
9e3c0a28 EA |
803 | \f/* |
804 | ** SAMEADDR -- Determine if two addresses are the same | |
805 | ** | |
806 | ** This is not just a straight comparison -- if the mailer doesn't | |
807 | ** care about the host we just ignore it, etc. | |
808 | ** | |
809 | ** Parameters: | |
810 | ** a, b -- pointers to the internal forms to compare. | |
811 | ** wildflg -- if TRUE, 'a' may have no user specified, | |
812 | ** in which case it is to match anything. | |
813 | ** | |
814 | ** Returns: | |
815 | ** TRUE -- they represent the same mailbox. | |
816 | ** FALSE -- they don't. | |
817 | ** | |
818 | ** Side Effects: | |
819 | ** none. | |
820 | */ | |
821 | ||
822 | bool | |
823 | sameaddr(a, b, wildflg) | |
824 | register ADDRESS *a; | |
825 | register ADDRESS *b; | |
826 | bool wildflg; | |
827 | { | |
828 | /* if they don't have the same mailer, forget it */ | |
829 | if (a->q_mailer != b->q_mailer) | |
830 | return (FALSE); | |
831 | ||
832 | /* if the user isn't the same, we can drop out */ | |
833 | if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) | |
834 | return (FALSE); | |
835 | ||
836 | /* if the mailer ignores hosts, we have succeeded! */ | |
837 | if (bitset(M_NOHOST, Mailer[a->q_mailer]->m_flags)) | |
838 | return (TRUE); | |
839 | ||
840 | /* otherwise compare hosts (but be careful for NULL ptrs) */ | |
841 | if (a->q_host == NULL || b->q_host == NULL) | |
842 | return (FALSE); | |
843 | if (strcmp(a->q_host, b->q_host) != 0) | |
844 | return (FALSE); | |
845 | ||
846 | return (TRUE); | |
847 | } |