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