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