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