]> diplodocus.org Git - nmh/blob - sbr/addrsbr.c
Makefile.am: Add test/inc/test-eom-align to XFAIL_TESTS.
[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 recognition. 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" representations.
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(void) {
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 (FENDNULL(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 char *
220 auxformat (struct mailname *mp, int extras)
221 {
222 static char addr[BUFSIZ];
223 static char buffer[BUFSIZ];
224
225 if (mp->m_nohost)
226 strncpy (addr, FENDNULL(mp->m_mbox), sizeof(addr));
227 else
228
229 if (mp->m_type != UUCPHOST) {
230 if (mp->m_host)
231 snprintf (addr, sizeof(addr), "%s%s@%s", FENDNULL(mp->m_path),
232 FENDNULL(mp->m_mbox), mp->m_host);
233 else snprintf (addr, sizeof(addr), "%s%s", FENDNULL(mp->m_path),
234 FENDNULL(mp->m_mbox));
235 } else
236 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
237
238 if (!extras)
239 return addr;
240
241 if (mp->m_pers || mp->m_path) {
242 if (mp->m_note)
243 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
244 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
245 mp->m_note, addr);
246 else
247 snprintf (buffer, sizeof(buffer), "%s <%s>",
248 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
249 addr);
250 }
251 else
252 if (mp->m_note)
253 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
254 else
255 strncpy (buffer, addr, sizeof(buffer));
256
257 return buffer;
258 }
259
260
261 #define W_NIL 0x0000
262 #define W_MBEG 0x0001
263 #define W_MEND 0x0002
264 #define W_MBOX (W_MBEG | W_MEND)
265 #define W_HBEG 0x0004
266 #define W_HEND 0x0008
267 #define W_HOST (W_HBEG | W_HEND)
268 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
269
270 /*
271 * Check if this is my address
272 */
273
274 int
275 ismymbox (struct mailname *np)
276 {
277 int oops;
278 int len, i;
279 char *cp;
280 char *pp;
281 char buffer[BUFSIZ];
282 struct mailname *mp;
283 static char *am = NULL;
284 static struct mailname mq;
285 static int localmailbox = 0;
286
287 /*
288 * If this is the first call, initialize
289 * list of alternate mailboxes.
290 */
291 if (am == NULL) {
292 mq.m_next = NULL;
293 mq.m_mbox = getusername ();
294
295 if ((am = context_find ("local-mailbox"))) {
296
297 localmailbox++;
298
299 if ((cp = getname(am)) == NULL) {
300 inform("Unable to find address in local-mailbox, continuing...");
301 return 0;
302 }
303
304 if ((mq.m_next = getm (cp, NULL, 0, NULL, 0)) == NULL) {
305 inform("invalid entry in local-mailbox: %s, continuing...", cp);
306 return 0;
307 }
308
309 /* Sigh, it turns out that the address parser gets messed up
310 * if you don't call getname() until it returns NULL. */
311 while (getname(am) != NULL)
312 ;
313 }
314
315 if ((am = context_find ("alternate-mailboxes")) == NULL)
316 am = getusername();
317 else {
318 mp = mq.m_next ? mq.m_next : &mq;
319 oops = 0;
320 while ((cp = getname (am))) {
321 if ((mp->m_next = getm (cp, NULL, 0, NULL, 0)) == NULL) {
322 inform("illegal address: %s, continuing...", cp);
323 oops++;
324 } else {
325 mp = mp->m_next;
326 mp->m_type = W_NIL;
327 if (*mp->m_mbox == '*') {
328 mp->m_type |= W_MBEG;
329 mp->m_mbox++;
330 }
331 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
332 mp->m_type |= W_MEND;
333 *cp = '\0';
334 }
335 if (mp->m_host) {
336 if (*mp->m_host == '*') {
337 mp->m_type |= W_HBEG;
338 mp->m_host++;
339 }
340 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
341 mp->m_type |= W_HEND;
342 *cp = '\0';
343 }
344 }
345 }
346 }
347 if (oops)
348 inform("please fix the %s: entry in your %s file",
349 "alternate-mailboxes", mh_profile);
350 }
351
352 if ((cp = getenv ("MHWDEBUG")) && *cp) {
353 for (mp = &mq; mp; mp = mp->m_next) {
354 fprintf (stderr, "Local- or Alternate-Mailbox: text=\"%s\" "
355 "mbox=\"%s\" host=\"%s\" %s\n",
356 FENDNULL(mp->m_text), mp->m_mbox,
357 FENDNULL(mp->m_host),
358 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type,
359 WBITS));
360 }
361 }
362 }
363
364 if (np == NULL) /* XXX */
365 return 0;
366
367 /*
368 * Don't perform this "local" test if we have a Local-Mailbox set
369 */
370
371 if (! localmailbox)
372 switch (np->m_type) {
373 case NETHOST:
374 len = strlen (cp = LocalName (0));
375 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
376 break;
377 goto local_test;
378
379 case UUCPHOST:
380 if (strcasecmp (np->m_host, SystemName()))
381 break;
382 /* FALLTHRU */
383 case LOCALHOST:
384 local_test: ;
385 if (!strcasecmp (np->m_mbox, mq.m_mbox))
386 return 1;
387 break;
388
389 default:
390 break;
391 }
392
393 /*
394 * Now scan through list of alternate
395 * mailboxes, and check for a match.
396 */
397 for (mp = &mq; mp->m_next;) {
398 mp = mp->m_next;
399 if (!np->m_mbox)
400 continue;
401 if ((len = strlen (cp = np->m_mbox))
402 < (i = strlen (pp = mp->m_mbox)))
403 continue;
404 switch (mp->m_type & W_MBOX) {
405 case W_NIL:
406 if (strcasecmp (cp, pp))
407 continue;
408 break;
409 case W_MBEG:
410 if (strcasecmp (cp + len - i, pp))
411 continue;
412 break;
413 case W_MEND:
414 if (!uprf (cp, pp))
415 continue;
416 break;
417 case W_MBEG | W_MEND:
418 if (stringdex (pp, cp) < 0)
419 continue;
420 break;
421 }
422
423 if (mp->m_nohost)
424 return 1;
425 if (np->m_host == NULL || mp->m_host == NULL)
426 continue;
427 if ((len = strlen (cp = np->m_host))
428 < (i = strlen (pp = mp->m_host)))
429 continue;
430 switch (mp->m_type & W_HOST) {
431 case W_NIL:
432 if (strcasecmp (cp, pp))
433 continue;
434 break;
435 case W_HBEG:
436 if (strcasecmp (cp + len - i, pp))
437 continue;
438 break;
439 case W_HEND:
440 if (!uprf (cp, pp))
441 continue;
442 break;
443 case W_HBEG | W_HEND:
444 if (stringdex (pp, cp) < 0)
445 continue;
446 break;
447 }
448 return 1;
449 }
450
451 return 0;
452 }