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