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