]> diplodocus.org Git - nmh/blob - sbr/addrsbr.c
d3c423e42e88298bab04c1d04d86d6f1b6dd3244
[nmh] / sbr / addrsbr.c
1 /*
2 * addrsbr.c -- parse addresses 822-style
3 *
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/addrsbr.h>
11 #include <h/mf.h>
12 #include <h/mts.h>
13 #include <h/utils.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 explicit 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 static int eai = 0;
79
80 void
81 enable_eai() {
82 eai = 1;
83 }
84
85
86 char *
87 getname (const char *addrs)
88 {
89 struct adrx *ap;
90 pers = mbox = host = route = grp = note = NULL;
91 err[0] = '\0';
92
93 if ((ap = getadrx (addrs ? addrs : "", eai)) == NULL) {
94 return NULL;
95 }
96
97 strncpy (adr, ap->text, sizeof(adr));
98 pers = ap->pers;
99 mbox = ap->mbox;
100 host = ap->host;
101 route = ap->path;
102 grp = ap->grp;
103 ingrp = ap->ingrp;
104 note = ap->note;
105 if (ap->err && *ap->err)
106 strncpy (err, ap->err, sizeof(err));
107
108 return adr;
109 }
110
111
112 struct mailname *
113 getm (char *str, char *dfhost, int dftype, char *eresult, size_t eresultsize)
114 {
115 char *pp;
116 struct mailname *mp;
117
118 if (err[0]) {
119 if (eresult) {
120 strncpy (eresult, err, eresultsize);
121 eresult[eresultsize - 1] = '\0';
122 }
123 return NULL;
124 }
125 if (pers == NULL
126 && mbox == NULL && host == NULL && route == NULL
127 && grp == NULL) {
128 if (eresult) {
129 strncpy (eresult, "null address", eresultsize);
130 eresult[eresultsize - 1] = '\0';
131 }
132 return NULL;
133 }
134 if (mbox == NULL && grp == NULL) {
135 if (eresult) {
136 strncpy (eresult, "no mailbox in address", eresultsize);
137 eresult[eresultsize - 1] = '\0';
138 }
139 return NULL;
140 }
141
142 if (dfhost == NULL) {
143 dfhost = LocalName (0);
144 dftype = LOCALHOST;
145 }
146
147 NEW0(mp);
148 mp->m_next = NULL;
149 mp->m_text = getcpy (str);
150 if (pers)
151 mp->m_pers = mh_xstrdup(pers);
152
153 if (mbox == NULL) {
154 mp->m_type = BADHOST;
155 mp->m_nohost = 1;
156 mp->m_ingrp = ingrp;
157 mp->m_gname = getcpy (grp);
158 if (note)
159 mp->m_note = mh_xstrdup(note);
160 return mp;
161 }
162
163 if (host) {
164 mp->m_mbox = getcpy (mbox);
165 mp->m_host = mh_xstrdup(host);
166 mp->m_type =
167 strcasecmp (LocalName(0), mp->m_host) ? NETHOST : LOCALHOST;
168 } else {
169 if ((pp = strchr(mbox, '!'))) {
170 *pp++ = '\0';
171 mp->m_mbox = mh_xstrdup(pp);
172 mp->m_host = getcpy (mbox);
173 mp->m_type = UUCPHOST;
174 } else {
175 mp->m_nohost = 1;
176 mp->m_mbox = getcpy (mbox);
177 if (route == NULL && dftype == LOCALHOST) {
178 mp->m_host = NULL;
179 mp->m_type = dftype;
180 } else {
181 mp->m_host = route ? NULL : getcpy (dfhost);
182 mp->m_type = route ? NETHOST : dftype;
183 }
184 }
185 }
186
187 /* For alternate mailboxes, m_type gets overwritten in ismymbox ()
188 to support wild-card matching. */
189
190 if (route)
191 mp->m_path = mh_xstrdup(route);
192 mp->m_ingrp = ingrp;
193 if (grp)
194 mp->m_gname = mh_xstrdup(grp);
195 if (note)
196 mp->m_note = mh_xstrdup(note);
197
198 return mp;
199 }
200
201
202 void
203 mnfree (struct mailname *mp)
204 {
205 if (!mp)
206 return;
207
208 mh_xfree(mp->m_text);
209 mh_xfree(mp->m_pers);
210 mh_xfree(mp->m_mbox);
211 mh_xfree(mp->m_host);
212 mh_xfree(mp->m_path);
213 mh_xfree(mp->m_gname);
214 mh_xfree(mp->m_note);
215
216 free(mp);
217 }
218
219
220 #define empty(s) ((s) ? (s) : "")
221
222 char *
223 auxformat (struct mailname *mp, int extras)
224 {
225 static char addr[BUFSIZ];
226 static char buffer[BUFSIZ];
227
228 if (mp->m_nohost)
229 strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
230 else
231
232 if (mp->m_type != UUCPHOST) {
233 if (mp->m_host)
234 snprintf (addr, sizeof(addr), "%s%s@%s", empty(mp->m_path),
235 empty(mp->m_mbox), mp->m_host);
236 else snprintf (addr, sizeof(addr), "%s%s", empty(mp->m_path),
237 empty(mp->m_mbox));
238 } else
239 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
240
241 if (!extras)
242 return addr;
243
244 if (mp->m_pers || mp->m_path) {
245 if (mp->m_note)
246 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
247 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
248 mp->m_note, addr);
249 else
250 snprintf (buffer, sizeof(buffer), "%s <%s>",
251 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
252 addr);
253 }
254 else
255 if (mp->m_note)
256 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
257 else
258 strncpy (buffer, addr, sizeof(buffer));
259
260 return buffer;
261 }
262
263
264 #define W_NIL 0x0000
265 #define W_MBEG 0x0001
266 #define W_MEND 0x0002
267 #define W_MBOX (W_MBEG | W_MEND)
268 #define W_HBEG 0x0004
269 #define W_HEND 0x0008
270 #define W_HOST (W_HBEG | W_HEND)
271 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
272
273 /*
274 * Check if this is my address
275 */
276
277 int
278 ismymbox (struct mailname *np)
279 {
280 int oops;
281 int len, i;
282 char *cp;
283 char *pp;
284 char buffer[BUFSIZ];
285 struct mailname *mp;
286 static char *am = NULL;
287 static struct mailname mq;
288 static int localmailbox = 0;
289
290 /*
291 * If this is the first call, initialize
292 * list of alternate mailboxes.
293 */
294 if (am == NULL) {
295 mq.m_next = NULL;
296 mq.m_mbox = getusername ();
297
298 if ((am = context_find ("local-mailbox"))) {
299
300 localmailbox++;
301
302 if ((cp = getname(am)) == NULL) {
303 inform("Unable to find address in local-mailbox, continuing...");
304 return 0;
305 }
306
307 if ((mq.m_next = getm (cp, NULL, 0, NULL, 0)) == NULL) {
308 inform("invalid entry in local-mailbox: %s, continuing...", cp);
309 return 0;
310 }
311
312 /* Sigh, it turns out that the address parser gets messed up
313 * if you don't call getname() until it returns NULL. */
314 while (getname(am) != NULL)
315 ;
316 }
317
318 if ((am = context_find ("alternate-mailboxes")) == NULL)
319 am = getusername();
320 else {
321 mp = mq.m_next ? mq.m_next : &mq;
322 oops = 0;
323 while ((cp = getname (am))) {
324 if ((mp->m_next = getm (cp, NULL, 0, NULL, 0)) == NULL) {
325 inform("illegal address: %s, continuing...", cp);
326 oops++;
327 } else {
328 mp = mp->m_next;
329 mp->m_type = W_NIL;
330 if (*mp->m_mbox == '*') {
331 mp->m_type |= W_MBEG;
332 mp->m_mbox++;
333 }
334 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
335 mp->m_type |= W_MEND;
336 *cp = '\0';
337 }
338 if (mp->m_host) {
339 if (*mp->m_host == '*') {
340 mp->m_type |= W_HBEG;
341 mp->m_host++;
342 }
343 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
344 mp->m_type |= W_HEND;
345 *cp = '\0';
346 }
347 }
348 }
349 }
350 if (oops)
351 inform("please fix the %s: entry in your %s file",
352 "alternate-mailboxes", mh_profile);
353 }
354
355 if ((cp = getenv ("MHWDEBUG")) && *cp) {
356 for (mp = &mq; mp; mp = mp->m_next) {
357 fprintf (stderr, "Local- or Alternate-Mailbox: text=\"%s\" "
358 "mbox=\"%s\" host=\"%s\" %s\n",
359 mp->m_text ? mp->m_text : "", mp->m_mbox,
360 mp->m_host ? mp->m_host : "",
361 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type,
362 WBITS));
363 }
364 }
365 }
366
367 if (np == NULL) /* XXX */
368 return 0;
369
370 /*
371 * Don't perform this "local" test if we have a Local-Mailbox set
372 */
373
374 if (! localmailbox)
375 switch (np->m_type) {
376 case NETHOST:
377 len = strlen (cp = LocalName (0));
378 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
379 break;
380 goto local_test;
381
382 case UUCPHOST:
383 if (strcasecmp (np->m_host, SystemName()))
384 break;
385 /* FALLTHRU */
386 case LOCALHOST:
387 local_test: ;
388 if (!strcasecmp (np->m_mbox, mq.m_mbox))
389 return 1;
390 break;
391
392 default:
393 break;
394 }
395
396 /*
397 * Now scan through list of alternate
398 * mailboxes, and check for a match.
399 */
400 for (mp = &mq; mp->m_next;) {
401 mp = mp->m_next;
402 if (!np->m_mbox)
403 continue;
404 if ((len = strlen (cp = np->m_mbox))
405 < (i = strlen (pp = mp->m_mbox)))
406 continue;
407 switch (mp->m_type & W_MBOX) {
408 case W_NIL:
409 if (strcasecmp (cp, pp))
410 continue;
411 break;
412 case W_MBEG:
413 if (strcasecmp (cp + len - i, pp))
414 continue;
415 break;
416 case W_MEND:
417 if (!uprf (cp, pp))
418 continue;
419 break;
420 case W_MBEG | W_MEND:
421 if (stringdex (pp, cp) < 0)
422 continue;
423 break;
424 }
425
426 if (mp->m_nohost)
427 return 1;
428 if (np->m_host == NULL || mp->m_host == NULL)
429 continue;
430 if ((len = strlen (cp = np->m_host))
431 < (i = strlen (pp = mp->m_host)))
432 continue;
433 switch (mp->m_type & W_HOST) {
434 case W_NIL:
435 if (strcasecmp (cp, pp))
436 continue;
437 break;
438 case W_HBEG:
439 if (strcasecmp (cp + len - i, pp))
440 continue;
441 break;
442 case W_HEND:
443 if (!uprf (cp, pp))
444 continue;
445 break;
446 case W_HBEG | W_HEND:
447 if (stringdex (pp, cp) < 0)
448 continue;
449 break;
450 }
451 return 1;
452 }
453
454 return 0;
455 }