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