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