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