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