]> diplodocus.org Git - nmh/blob - sbr/addrsbr.c
9b2973a369fc8c77d4a9671213495096d91eb025
[nmh] / sbr / addrsbr.c
1 /* addrsbr.c -- parse addresses 822-style
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include "h/mh.h"
9 #include "snprintb.h"
10 #include "strindex.h"
11 #include "uprf.h"
12 #include "getcpy.h"
13 #include "context_find.h"
14 #include "error.h"
15 #include "h/addrsbr.h"
16 #include "h/mf.h"
17 #include "h/mts.h"
18 #include "h/utils.h"
19
20 /* High level parsing of addresses:
21
22 The routines in sbr/mf.c parse the syntactic representations of
23 addresses. The routines in sbr/addrsbr.c associate semantics with those
24 addresses.
25
26 The comments below are left in for historical purposes; DUMB and
27 REALLYDUMB are now the default in the code.
28
29 If #ifdef DUMB is in effect, a full 822-style parser is called
30 for syntax recognition. This breaks each address into its components.
31 Note however that no semantics are assumed about the parts or their
32 totality. This means that implicit hostnames aren't made explicit,
33 and explicit hostnames aren't expanded to their "official" representations.
34
35 If DUMB is not in effect, then this module does some
36 high-level thinking about what the addresses are.
37
38 1. for MMDF systems:
39
40 string%<uucp>@<local> -> string
41
42 2. for non-MMDF systems:
43
44 string@host.<uucp> -> host!string
45
46 3. for any system, an address interpreted relative to the local host:
47
48 string@<uucp> -> string
49
50 For cases (1) and (3) above, the leftmost host is extracted. If it's not
51 present, the local host is used. If the tests above fail, the address is
52 considered to be a real 822-style address.
53
54 If an explicit host is not present, then MH checks for a bang to indicate
55 an explicit UUCP-style address. If so, this is noted. If not, the host is
56 defaulted, typically to the local host. The lack of an explicit host is
57 also noted.
58
59 If an explicit 822-style host is present, then MH checks to see if it
60 can expand this to the official name for the host. If the hostname is
61 unknown, the address is so typed.
62
63 To summarize, when we're all done, here's what MH knows about the address:
64
65 DUMB - type: local, uucp, or network
66 host: not locally defaulted, not explicitly expanded
67 everything else
68
69 other - type: local, uucp, network, unknown
70 everything else
71 */
72
73
74 static int ingrp = 0;
75 static char *pers = NULL;
76 static char *mbox = NULL;
77 static char *host = NULL;
78 static char *route = NULL;
79 static char *grp = NULL;
80 static char *note = NULL;
81 static char err[BUFSIZ];
82 static char adr[BUFSIZ];
83 static int eai = 0;
84
85 void
86 enable_eai(void)
87 {
88 eai = 1;
89 }
90
91
92 char *
93 getname (const char *addrs)
94 {
95 struct adrx *ap;
96 pers = mbox = host = route = grp = note = NULL;
97 err[0] = '\0';
98
99 if ((ap = getadrx (FENDNULL(addrs), eai)) == NULL) {
100 return NULL;
101 }
102
103 strncpy (adr, ap->text, sizeof(adr));
104 pers = ap->pers;
105 mbox = ap->mbox;
106 host = ap->host;
107 route = ap->path;
108 grp = ap->grp;
109 ingrp = ap->ingrp;
110 note = ap->note;
111 if (ap->err && *ap->err)
112 strncpy (err, ap->err, sizeof(err));
113
114 return adr;
115 }
116
117
118 struct mailname *
119 getm (char *str, char *dfhost, int dftype, char *eresult, size_t eresultsize)
120 {
121 char *pp;
122 struct mailname *mp;
123
124 if (err[0]) {
125 if (eresult) {
126 strncpy (eresult, err, eresultsize);
127 eresult[eresultsize - 1] = '\0';
128 }
129 return NULL;
130 }
131 if (pers == NULL
132 && mbox == NULL && host == NULL && route == NULL
133 && grp == NULL) {
134 if (eresult) {
135 strncpy (eresult, "null address", eresultsize);
136 eresult[eresultsize - 1] = '\0';
137 }
138 return NULL;
139 }
140 if (mbox == NULL && grp == NULL) {
141 if (eresult) {
142 strncpy (eresult, "no mailbox in address", eresultsize);
143 eresult[eresultsize - 1] = '\0';
144 }
145 return NULL;
146 }
147
148 if (dfhost == NULL) {
149 dfhost = LocalName (0);
150 dftype = LOCALHOST;
151 }
152
153 NEW0(mp);
154 mp->m_next = NULL;
155 mp->m_text = getcpy (str);
156 if (pers)
157 mp->m_pers = mh_xstrdup(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 = mh_xstrdup(note);
166 return mp;
167 }
168
169 if (host) {
170 mp->m_mbox = getcpy (mbox);
171 mp->m_host = mh_xstrdup(host);
172 mp->m_type =
173 strcasecmp (LocalName(0), mp->m_host) ? NETHOST : LOCALHOST;
174 } else {
175 if ((pp = strchr(mbox, '!'))) {
176 *pp++ = '\0';
177 mp->m_mbox = mh_xstrdup(pp);
178 mp->m_host = getcpy (mbox);
179 mp->m_type = UUCPHOST;
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 } else {
187 mp->m_host = route ? NULL : getcpy (dfhost);
188 mp->m_type = route ? NETHOST : dftype;
189 }
190 }
191 }
192
193 /* For alternate mailboxes, m_type gets overwritten in ismymbox ()
194 to support wild-card matching. */
195
196 if (route)
197 mp->m_path = mh_xstrdup(route);
198 mp->m_ingrp = ingrp;
199 if (grp)
200 mp->m_gname = mh_xstrdup(grp);
201 if (note)
202 mp->m_note = mh_xstrdup(note);
203
204 return mp;
205 }
206
207
208 void
209 mnfree (struct mailname *mp)
210 {
211 if (!mp)
212 return;
213
214 free(mp->m_text);
215 free(mp->m_pers);
216 free(mp->m_mbox);
217 free(mp->m_host);
218 free(mp->m_path);
219 free(mp->m_gname);
220 free(mp->m_note);
221
222 free(mp);
223 }
224
225
226 char *
227 auxformat (struct mailname *mp, int extras)
228 {
229 static char addr[BUFSIZ];
230 static char buffer[BUFSIZ];
231
232 if (mp->m_nohost)
233 strncpy (addr, FENDNULL(mp->m_mbox), sizeof(addr));
234 else if (mp->m_type != UUCPHOST) {
235 if (mp->m_host)
236 snprintf (addr, sizeof(addr), "%s%s@%s", FENDNULL(mp->m_path),
237 FENDNULL(mp->m_mbox), mp->m_host);
238 else snprintf (addr, sizeof(addr), "%s%s", FENDNULL(mp->m_path),
239 FENDNULL(mp->m_mbox));
240 } else
241 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
242
243 if (!extras)
244 return addr;
245
246 if (mp->m_pers || mp->m_path) {
247 if (mp->m_note)
248 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
249 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
250 mp->m_note, addr);
251 else
252 snprintf (buffer, sizeof(buffer), "%s <%s>",
253 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
254 addr);
255 } else 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 bool
278 ismymbox (struct mailname *np)
279 {
280 bool 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 bool localmailbox;
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 = true;
301
302 if ((cp = getname(am)) == NULL) {
303 inform("Unable to find address in local-mailbox, continuing...");
304 return false;
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 false;
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 = false;
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 = true;
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 FENDNULL(mp->m_text), mp->m_mbox,
360 FENDNULL(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 false;
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 true;
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 true;
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 true;
452 }
453
454 return false;
455 }