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