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