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