]> diplodocus.org Git - nmh/blob - sbr/addrsbr.c
Don't increment bytes_read if returning EOF.
[nmh] / sbr / addrsbr.c
1
2 /*
3 * addrsbr.c -- parse addresses 822-style
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.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 recongition. 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" represenations.
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() {
83 eai = 1;
84 }
85
86
87 char *
88 getname (const char *addrs)
89 {
90 struct adrx *ap;
91 pers = mbox = host = route = grp = note = NULL;
92 err[0] = '\0';
93
94 if ((ap = getadrx (addrs ? addrs : "", eai)) == NULL) {
95 return NULL;
96 }
97
98 strncpy (adr, ap->text, sizeof(adr));
99 pers = ap->pers;
100 mbox = ap->mbox;
101 host = ap->host;
102 route = ap->path;
103 grp = ap->grp;
104 ingrp = ap->ingrp;
105 note = ap->note;
106 if (ap->err && *ap->err)
107 strncpy (err, ap->err, sizeof(err));
108
109 return adr;
110 }
111
112
113 struct mailname *
114 getm (char *str, char *dfhost, int dftype, char *eresult, size_t eresultsize)
115 {
116 char *pp;
117 struct mailname *mp;
118
119 if (err[0]) {
120 if (eresult) {
121 strncpy (eresult, err, eresultsize);
122 eresult[eresultsize - 1] = '\0';
123 }
124 return NULL;
125 }
126 if (pers == NULL
127 && mbox == NULL && host == NULL && route == NULL
128 && grp == NULL) {
129 if (eresult) {
130 strncpy (eresult, "null address", eresultsize);
131 eresult[eresultsize - 1] = '\0';
132 }
133 return NULL;
134 }
135 if (mbox == NULL && grp == NULL) {
136 if (eresult) {
137 strncpy (eresult, "no mailbox in address", eresultsize);
138 eresult[eresultsize - 1] = '\0';
139 }
140 return NULL;
141 }
142
143 if (dfhost == NULL) {
144 dfhost = LocalName (0);
145 dftype = LOCALHOST;
146 }
147
148 mp = (struct mailname *) mh_xcalloc ((size_t) 1, sizeof(*mp));
149 if (mp == NULL) {
150 if (eresult) {
151 strncpy (eresult, "insufficient memory to represent address",
152 eresultsize);
153 eresult[eresultsize - 1] = '\0';
154 }
155 return NULL;
156 }
157
158 mp->m_next = NULL;
159 mp->m_text = getcpy (str);
160 if (pers)
161 mp->m_pers = getcpy (pers);
162
163 if (mbox == NULL) {
164 mp->m_type = BADHOST;
165 mp->m_nohost = 1;
166 mp->m_ingrp = ingrp;
167 mp->m_gname = getcpy (grp);
168 if (note)
169 mp->m_note = getcpy (note);
170 return mp;
171 }
172
173 if (host) {
174 mp->m_mbox = getcpy (mbox);
175 mp->m_host = getcpy (host);
176 mp->m_type =
177 strcasecmp (LocalName(0), mp->m_host) ? NETHOST : LOCALHOST;
178 } else {
179 if ((pp = strchr(mbox, '!'))) {
180 *pp++ = '\0';
181 mp->m_mbox = getcpy (pp);
182 mp->m_host = getcpy (mbox);
183 mp->m_type = UUCPHOST;
184 } else {
185 mp->m_nohost = 1;
186 mp->m_mbox = getcpy (mbox);
187 if (route == NULL && dftype == LOCALHOST) {
188 mp->m_host = NULL;
189 mp->m_type = dftype;
190 } else {
191 mp->m_host = route ? NULL : getcpy (dfhost);
192 mp->m_type = route ? NETHOST : dftype;
193 }
194 }
195 }
196
197 /* For alternate mailboxes, m_type gets overwritten in ismymbox ()
198 to support wild-card matching. */
199
200 if (route)
201 mp->m_path = getcpy (route);
202 mp->m_ingrp = ingrp;
203 if (grp)
204 mp->m_gname = getcpy (grp);
205 if (note)
206 mp->m_note = getcpy (note);
207
208 return mp;
209 }
210
211
212 void
213 mnfree (struct mailname *mp)
214 {
215 if (!mp)
216 return;
217
218 if (mp->m_text)
219 free (mp->m_text);
220 if (mp->m_pers)
221 free (mp->m_pers);
222 if (mp->m_mbox)
223 free (mp->m_mbox);
224 if (mp->m_host)
225 free (mp->m_host);
226 if (mp->m_path)
227 free (mp->m_path);
228 if (mp->m_gname)
229 free (mp->m_gname);
230 if (mp->m_note)
231 free (mp->m_note);
232
233 free ((char *) mp);
234 }
235
236
237 #define empty(s) ((s) ? (s) : "")
238
239 char *
240 auxformat (struct mailname *mp, int extras)
241 {
242 static char addr[BUFSIZ];
243 static char buffer[BUFSIZ];
244
245 if (mp->m_nohost)
246 strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
247 else
248
249 if (mp->m_type != UUCPHOST) {
250 if (mp->m_host)
251 snprintf (addr, sizeof(addr), "%s%s@%s", empty(mp->m_path),
252 empty(mp->m_mbox), mp->m_host);
253 else snprintf (addr, sizeof(addr), "%s%s", empty(mp->m_path),
254 empty(mp->m_mbox));
255 } else
256 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
257
258 if (!extras)
259 return addr;
260
261 if (mp->m_pers || mp->m_path) {
262 if (mp->m_note)
263 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
264 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
265 mp->m_note, addr);
266 else
267 snprintf (buffer, sizeof(buffer), "%s <%s>",
268 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
269 addr);
270 }
271 else
272 if (mp->m_note)
273 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
274 else
275 strncpy (buffer, addr, sizeof(buffer));
276
277 return buffer;
278 }
279
280
281 #define W_NIL 0x0000
282 #define W_MBEG 0x0001
283 #define W_MEND 0x0002
284 #define W_MBOX (W_MBEG | W_MEND)
285 #define W_HBEG 0x0004
286 #define W_HEND 0x0008
287 #define W_HOST (W_HBEG | W_HEND)
288 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
289
290 /*
291 * Check if this is my address
292 */
293
294 int
295 ismymbox (struct mailname *np)
296 {
297 int oops;
298 register int len, i;
299 register char *cp;
300 register char *pp;
301 char buffer[BUFSIZ];
302 struct mailname *mp;
303 static char *am = NULL;
304 static struct mailname mq;
305 static int localmailbox = 0;
306
307 /*
308 * If this is the first call, initialize
309 * list of alternate mailboxes.
310 */
311 if (am == NULL) {
312 mq.m_next = NULL;
313 mq.m_mbox = getusername ();
314
315 if ((am = context_find ("local-mailbox"))) {
316
317 localmailbox++;
318
319 if ((cp = getname(am)) == NULL) {
320 admonish (NULL, "Unable to find address in local-mailbox");
321 return 0;
322 }
323
324 if ((mq.m_next = getm (cp, NULL, 0, NULL, 0)) == NULL) {
325 admonish (NULL, "invalid entry in local-mailbox: %s", cp);
326 return 0;
327 }
328
329 /*
330 * Sigh, it turns out that the address parser gets messed up
331 * if you don't call getname() until it returns NULL.
332 */
333
334 while ((cp = getname(am)) != NULL)
335 ;
336 }
337
338 if ((am = context_find ("alternate-mailboxes")) == NULL)
339 am = getusername();
340 else {
341 mp = mq.m_next ? mq.m_next : &mq;
342 oops = 0;
343 while ((cp = getname (am))) {
344 if ((mp->m_next = getm (cp, NULL, 0, NULL, 0)) == NULL) {
345 admonish (NULL, "illegal address: %s", cp);
346 oops++;
347 } else {
348 mp = mp->m_next;
349 mp->m_type = W_NIL;
350 if (*mp->m_mbox == '*') {
351 mp->m_type |= W_MBEG;
352 mp->m_mbox++;
353 }
354 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
355 mp->m_type |= W_MEND;
356 *cp = '\0';
357 }
358 if (mp->m_host) {
359 if (*mp->m_host == '*') {
360 mp->m_type |= W_HBEG;
361 mp->m_host++;
362 }
363 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
364 mp->m_type |= W_HEND;
365 *cp = '\0';
366 }
367 }
368 }
369 }
370 if (oops)
371 advise (NULL, "please fix the %s: entry in your %s file",
372 "alternate-mailboxes", mh_profile);
373 }
374
375 if ((cp = getenv ("MHWDEBUG")) && *cp) {
376 for (mp = &mq; mp; mp = mp->m_next) {
377 fprintf (stderr, "Local- or Alternate-Mailbox: text=\"%s\" "
378 "mbox=\"%s\" host=\"%s\" %s\n",
379 mp->m_text ? mp->m_text : "", mp->m_mbox,
380 mp->m_host ? mp->m_host : "",
381 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type,
382 WBITS));
383 }
384 }
385 }
386
387 if (np == NULL) /* XXX */
388 return 0;
389
390 /*
391 * Don't perform this "local" test if we have a Local-Mailbox set
392 */
393
394 if (! localmailbox)
395 switch (np->m_type) {
396 case NETHOST:
397 len = strlen (cp = LocalName (0));
398 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
399 break;
400 goto local_test;
401
402 case UUCPHOST:
403 if (strcasecmp (np->m_host, SystemName()))
404 break; /* fall */
405 case LOCALHOST:
406 local_test: ;
407 if (!strcasecmp (np->m_mbox, mq.m_mbox))
408 return 1;
409 break;
410
411 default:
412 break;
413 }
414
415 /*
416 * Now scan through list of alternate
417 * mailboxes, and check for a match.
418 */
419 for (mp = &mq; mp->m_next;) {
420 mp = mp->m_next;
421 if (!np->m_mbox)
422 continue;
423 if ((len = strlen (cp = np->m_mbox))
424 < (i = strlen (pp = mp->m_mbox)))
425 continue;
426 switch (mp->m_type & W_MBOX) {
427 case W_NIL:
428 if (strcasecmp (cp, pp))
429 continue;
430 break;
431 case W_MBEG:
432 if (strcasecmp (cp + len - i, pp))
433 continue;
434 break;
435 case W_MEND:
436 if (!uprf (cp, pp))
437 continue;
438 break;
439 case W_MBEG | W_MEND:
440 if (stringdex (pp, cp) < 0)
441 continue;
442 break;
443 }
444
445 if (mp->m_nohost)
446 return 1;
447 if (np->m_host == NULL || mp->m_host == NULL)
448 continue;
449 if ((len = strlen (cp = np->m_host))
450 < (i = strlen (pp = mp->m_host)))
451 continue;
452 switch (mp->m_type & W_HOST) {
453 case W_NIL:
454 if (strcasecmp (cp, pp))
455 continue;
456 break;
457 case W_HBEG:
458 if (strcasecmp (cp + len - i, pp))
459 continue;
460 break;
461 case W_HEND:
462 if (!uprf (cp, pp))
463 continue;
464 break;
465 case W_HBEG | W_HEND:
466 if (stringdex (pp, cp) < 0)
467 continue;
468 break;
469 }
470 return 1;
471 }
472
473 return 0;
474 }