]> diplodocus.org Git - nmh/blob - sbr/addrsbr.c
Note changes to mhbuild.
[nmh] / sbr / addrsbr.c
1
2 /*
3 * addrsbr.c -- parse addresses 822-style
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h>
11 #include <h/addrsbr.h>
12 #include <h/mf.h>
13 #include <h/mts.h>
14
15 /* High level parsing of addresses:
16
17 The routines in sbr/mf.c parse the syntactic representations of
18 addresses. The routines in sbr/addrsbr.c associate semantics with those
19 addresses.
20
21 The comments below are left in for historical purposes; DUMB and
22 REALLYDUMB are now the default in the code.
23
24 If #ifdef DUMB is in effect, a full 822-style parser is called
25 for syntax recongition. This breaks each address into its components.
26 Note however that no semantics are assumed about the parts or their
27 totality. This means that implicit hostnames aren't made explicit,
28 and explicit hostnames aren't expanded to their "official" represenations.
29
30 If DUMB is not in effect, then this module does some
31 high-level thinking about what the addresses are.
32
33 1. for MMDF systems:
34
35 string%<uucp>@<local> -> string
36
37 2. for non-MMDF systems:
38
39 string@host.<uucp> -> host!string
40
41 3. for any system, an address interpreted relative to the local host:
42
43 string@<uucp> -> string
44
45 For cases (1) and (3) above, the leftmost host is extracted. If it's not
46 present, the local host is used. If the tests above fail, the address is
47 considered to be a real 822-style address.
48
49 If an explicit host is not present, then MH checks for a bang to indicate
50 an explicit UUCP-style address. If so, this is noted. If not, the host is
51 defaulted, typically to the local host. The lack of an explict host is
52 also noted.
53
54 If an explicit 822-style host is present, then MH checks to see if it
55 can expand this to the official name for the host. If the hostname is
56 unknown, the address is so typed.
57
58 To summarize, when we're all done, here's what MH knows about the address:
59
60 DUMB - type: local, uucp, or network
61 host: not locally defaulted, not explicitly expanded
62 everything else
63
64 other - type: local, uucp, network, unknown
65 everything else
66 */
67
68
69 static int ingrp = 0;
70 static char *pers = NULL;
71 static char *mbox = NULL;
72 static char *host = NULL;
73 static char *route = NULL;
74 static char *grp = NULL;
75 static char *note = NULL;
76 static char err[BUFSIZ];
77 static char adr[BUFSIZ];
78
79
80 char *
81 getname (const char *addrs)
82 {
83 struct adrx *ap;
84
85 pers = mbox = host = route = grp = note = NULL;
86 err[0] = '\0';
87
88 if ((ap = getadrx (addrs ? addrs : "")) == NULL)
89 return NULL;
90
91 strncpy (adr, ap->text, sizeof(adr));
92 pers = ap->pers;
93 mbox = ap->mbox;
94 host = ap->host;
95 route = ap->path;
96 grp = ap->grp;
97 ingrp = ap->ingrp;
98 note = ap->note;
99 if (ap->err && *ap->err)
100 strncpy (err, ap->err, sizeof(err));
101
102 return adr;
103 }
104
105
106 struct mailname *
107 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
108 {
109 char *pp;
110 struct mailname *mp;
111
112 if (err[0]) {
113 if (eresult)
114 strcpy (eresult, err);
115 else
116 if (wanthost == AD_HOST)
117 admonish (NULL, "bad address '%s' - %s", str, err);
118 return NULL;
119 }
120 if (pers == NULL
121 && mbox == NULL && host == NULL && route == NULL
122 && grp == NULL) {
123 if (eresult)
124 strcpy (eresult, "null address");
125 else
126 if (wanthost == AD_HOST)
127 admonish (NULL, "null address '%s'", str);
128 return NULL;
129 }
130 if (mbox == NULL && grp == NULL) {
131 if (eresult)
132 strcpy (eresult, "no mailbox in address");
133 else
134 if (wanthost == AD_HOST)
135 admonish (NULL, "no mailbox in address '%s'", str);
136 return NULL;
137 }
138
139 if (dfhost == NULL) {
140 dfhost = LocalName (0);
141 dftype = LOCALHOST;
142 }
143
144 mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp));
145 if (mp == NULL) {
146 if (eresult)
147 strcpy (eresult, "insufficient memory to represent address");
148 else
149 if (wanthost == AD_HOST)
150 adios (NULL, "insufficient memory to represent address");
151 return NULL;
152 }
153
154 mp->m_next = NULL;
155 mp->m_text = getcpy (str);
156 if (pers)
157 mp->m_pers = getcpy (pers);
158
159 if (mbox == NULL) {
160 mp->m_type = BADHOST;
161 mp->m_nohost = 1;
162 mp->m_ingrp = ingrp;
163 mp->m_gname = getcpy (grp);
164 if (note)
165 mp->m_note = getcpy (note);
166 return mp;
167 }
168
169 if (host) {
170 mp->m_mbox = getcpy (mbox);
171 mp->m_host = getcpy (host);
172 mp->m_type =
173 strcasecmp (LocalName(0), mp->m_host) ? NETHOST : LOCALHOST;
174 } else {
175 if ((pp = strchr(mbox, '!'))) {
176 *pp++ = '\0';
177 mp->m_mbox = getcpy (pp);
178 mp->m_host = getcpy (mbox);
179 mp->m_type = UUCPHOST;
180 } else {
181 mp->m_nohost = 1;
182 mp->m_mbox = getcpy (mbox);
183 if (route == NULL && dftype == LOCALHOST) {
184 mp->m_host = NULL;
185 mp->m_type = dftype;
186 } else {
187 mp->m_host = route ? NULL : getcpy (dfhost);
188 mp->m_type = route ? NETHOST : dftype;
189 }
190 }
191 }
192
193 /* For alternate mailboxes, m_type gets overwritten in ismymbox ()
194 to support wild-card matching. */
195
196 if (route)
197 mp->m_path = getcpy (route);
198 mp->m_ingrp = ingrp;
199 if (grp)
200 mp->m_gname = getcpy (grp);
201 if (note)
202 mp->m_note = getcpy (note);
203
204 return mp;
205 }
206
207
208 void
209 mnfree (struct mailname *mp)
210 {
211 if (!mp)
212 return;
213
214 if (mp->m_text)
215 free (mp->m_text);
216 if (mp->m_pers)
217 free (mp->m_pers);
218 if (mp->m_mbox)
219 free (mp->m_mbox);
220 if (mp->m_host)
221 free (mp->m_host);
222 if (mp->m_path)
223 free (mp->m_path);
224 if (mp->m_gname)
225 free (mp->m_gname);
226 if (mp->m_note)
227 free (mp->m_note);
228
229 free ((char *) mp);
230 }
231
232
233 #define empty(s) ((s) ? (s) : "")
234
235 char *
236 auxformat (struct mailname *mp, int extras)
237 {
238 static char addr[BUFSIZ];
239 static char buffer[BUFSIZ];
240
241 if (mp->m_nohost)
242 strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
243 else
244
245 if (mp->m_type != UUCPHOST) {
246 if (mp->m_host)
247 snprintf (addr, sizeof(addr), "%s%s@%s", empty(mp->m_path),
248 empty(mp->m_mbox), mp->m_host);
249 else snprintf (addr, sizeof(addr), "%s%s", empty(mp->m_path),
250 empty(mp->m_mbox));
251 } else
252 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
253
254 if (!extras)
255 return addr;
256
257 if (mp->m_pers || mp->m_path) {
258 if (mp->m_note)
259 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
260 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
261 mp->m_note, addr);
262 else
263 snprintf (buffer, sizeof(buffer), "%s <%s>",
264 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
265 addr);
266 }
267 else
268 if (mp->m_note)
269 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
270 else
271 strncpy (buffer, addr, sizeof(buffer));
272
273 return buffer;
274 }
275
276
277 #define W_NIL 0x0000
278 #define W_MBEG 0x0001
279 #define W_MEND 0x0002
280 #define W_MBOX (W_MBEG | W_MEND)
281 #define W_HBEG 0x0004
282 #define W_HEND 0x0008
283 #define W_HOST (W_HBEG | W_HEND)
284 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
285
286 /*
287 * Check if this is my address
288 */
289
290 int
291 ismymbox (struct mailname *np)
292 {
293 int oops;
294 register int len, i;
295 register char *cp;
296 register char *pp;
297 char buffer[BUFSIZ];
298 struct mailname *mp;
299 static char *am = NULL;
300 static struct mailname mq;
301 static int localmailbox = 0;
302
303 /*
304 * If this is the first call, initialize
305 * list of alternate mailboxes.
306 */
307 if (am == NULL) {
308 mq.m_next = NULL;
309 mq.m_mbox = getusername ();
310
311 if ((am = context_find ("local-mailbox"))) {
312
313 localmailbox++;
314
315 if ((cp = getname(am)) == NULL) {
316 admonish (NULL, "Unable to find address in local-mailbox");
317 return 0;
318 }
319
320 if ((mq.m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
321 admonish (NULL, "invalid entry in local-mailbox: %s", cp);
322 return 0;
323 }
324
325 /*
326 * Sigh, it turns out that the address parser gets messed up
327 * if you don't call getname() until it returns NULL.
328 */
329
330 while ((cp = getname(am)) != NULL)
331 ;
332 }
333
334 if ((am = context_find ("alternate-mailboxes")) == NULL)
335 am = getusername();
336 else {
337 mp = mq.m_next ? mq.m_next : &mq;
338 oops = 0;
339 while ((cp = getname (am))) {
340 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
341 admonish (NULL, "illegal address: %s", cp);
342 oops++;
343 } else {
344 mp = mp->m_next;
345 mp->m_type = W_NIL;
346 if (*mp->m_mbox == '*') {
347 mp->m_type |= W_MBEG;
348 mp->m_mbox++;
349 }
350 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
351 mp->m_type |= W_MEND;
352 *cp = '\0';
353 }
354 if (mp->m_host) {
355 if (*mp->m_host == '*') {
356 mp->m_type |= W_HBEG;
357 mp->m_host++;
358 }
359 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
360 mp->m_type |= W_HEND;
361 *cp = '\0';
362 }
363 }
364 }
365 }
366 if (oops)
367 advise (NULL, "please fix the %s: entry in your %s file",
368 "alternate-mailboxes", mh_profile);
369 }
370
371 if ((cp = getenv ("MHWDEBUG")) && *cp) {
372 for (mp = &mq; mp; mp = mp->m_next) {
373 fprintf (stderr, "Local- or Alternate-Mailbox: text=\"%s\" "
374 "mbox=\"%s\" host=\"%s\" %s\n",
375 mp->m_text ? mp->m_text : "", mp->m_mbox,
376 mp->m_host ? mp->m_host : "",
377 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type,
378 WBITS));
379 }
380 }
381 }
382
383 if (np == NULL) /* XXX */
384 return 0;
385
386 /*
387 * Don't perform this "local" test if we have a Local-Mailbox set
388 */
389
390 if (! localmailbox)
391 switch (np->m_type) {
392 case NETHOST:
393 len = strlen (cp = LocalName (0));
394 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
395 break;
396 goto local_test;
397
398 case UUCPHOST:
399 if (strcasecmp (np->m_host, SystemName()))
400 break; /* fall */
401 case LOCALHOST:
402 local_test: ;
403 if (!strcasecmp (np->m_mbox, mq.m_mbox))
404 return 1;
405 break;
406
407 default:
408 break;
409 }
410
411 /*
412 * Now scan through list of alternate
413 * mailboxes, and check for a match.
414 */
415 for (mp = &mq; mp->m_next;) {
416 mp = mp->m_next;
417 if (!np->m_mbox)
418 continue; if ((len = strlen (cp = np->m_mbox))
419 < (i = strlen (pp = mp->m_mbox)))
420 continue;
421 switch (mp->m_type & W_MBOX) {
422 case W_NIL:
423 if (strcasecmp (cp, pp))
424 continue;
425 break;
426 case W_MBEG:
427 if (strcasecmp (cp + len - i, pp))
428 continue;
429 break;
430 case W_MEND:
431 if (!uprf (cp, pp))
432 continue;
433 break;
434 case W_MBEG | W_MEND:
435 if (stringdex (pp, cp) < 0)
436 continue;
437 break;
438 }
439
440 if (mp->m_nohost)
441 return 1;
442 if (np->m_host == NULL)
443 continue;
444 if ((len = strlen (cp = np->m_host))
445 < (i = strlen (pp = mp->m_host)))
446 continue;
447 switch (mp->m_type & W_HOST) {
448 case W_NIL:
449 if (strcasecmp (cp, pp))
450 continue;
451 break;
452 case W_HBEG:
453 if (strcasecmp (cp + len - i, pp))
454 continue;
455 break;
456 case W_HEND:
457 if (!uprf (cp, pp))
458 continue;
459 break;
460 case W_HBEG | W_HEND:
461 if (stringdex (pp, cp) < 0)
462 continue;
463 break;
464 }
465 return 1;
466 }
467
468 return 0;
469 }