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