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