]> diplodocus.org Git - nmh/blob - sbr/addrsbr.c
Make the test suite work on systems other than Linux. Still needs work.
[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 (0);
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 (0), mp->m_host)
206 ? LOCALHOST : NETHOST;
207 else
208 mp->m_type = mh_strcasecmp (LocalName(0), 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 * This used to be adrsprintf() (where it would format an address for you
291 * given a username and a domain). But somewhere we got to the point where
292 * the only caller was post, and it only called it with both arguments NULL.
293 * So the function was renamed with a more sensible name.
294 */
295
296 char *
297 getlocaladdr(void)
298 {
299 int snprintf_return;
300 char *username, *domain;
301 static char addr[BUFSIZ];
302
303 username = getusername();
304
305 if (username_extension_masquerading) {
306 /* mts.conf contains "masquerade:[...]username_extension[...]", so tack
307 on the value of the $USERNAME_EXTENSION environment variable, if set,
308 to username. */
309 char* extension = getenv("USERNAME_EXTENSION");
310 static char username_with_extension[BUFSIZ];
311
312 if (extension != NULL && *extension != '\0') {
313 snprintf_return = snprintf(username_with_extension,
314 sizeof(username_with_extension),
315 "%s%s", username, extension);
316
317 if (snprintf_return < 0 ||
318 snprintf_return >= (int) sizeof(username_with_extension))
319 adios(NULL, "snprintf() error writing username (%d chars) and"
320 " $USERNAME_EXTENSION (%d chars) to array of BUFSIZ (%d)"
321 " chars",
322 strlen(username), strlen(extension), BUFSIZ);
323
324 username = username_with_extension;
325 }
326 }
327
328 return username;
329
330 domain = LocalName(0);
331
332 snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
333
334 if (snprintf_return < 0 || snprintf_return >= (int) sizeof(addr))
335 adios(NULL, "snprintf() error writing username (%d chars), domain (%d"
336 " chars), and 1 separator char to array of BUFSIZ (%d) chars",
337 strlen(username), strlen(domain), BUFSIZ);
338
339 return addr;
340 }
341
342
343 #define W_NIL 0x0000
344 #define W_MBEG 0x0001
345 #define W_MEND 0x0002
346 #define W_MBOX (W_MBEG | W_MEND)
347 #define W_HBEG 0x0004
348 #define W_HEND 0x0008
349 #define W_HOST (W_HBEG | W_HEND)
350 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
351
352 /*
353 * Check if this is my address
354 */
355
356 int
357 ismymbox (struct mailname *np)
358 {
359 int oops;
360 register int len, i;
361 register char *cp;
362 register char *pp;
363 char buffer[BUFSIZ];
364 struct mailname *mp;
365 static char *am = NULL;
366 static struct mailname mq;
367
368 /*
369 * If this is the first call, initialize
370 * list of alternate mailboxes.
371 */
372 if (am == NULL) {
373 mq.m_next = NULL;
374 mq.m_mbox = getusername ();
375 if ((am = context_find ("alternate-mailboxes")) == NULL)
376 am = getusername();
377 else {
378 mp = &mq;
379 oops = 0;
380 while ((cp = getname (am))) {
381 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
382 admonish (NULL, "illegal address: %s", cp);
383 oops++;
384 } else {
385 mp = mp->m_next;
386 mp->m_type = W_NIL;
387 if (*mp->m_mbox == '*') {
388 mp->m_type |= W_MBEG;
389 mp->m_mbox++;
390 }
391 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
392 mp->m_type |= W_MEND;
393 *cp = '\0';
394 }
395 if (mp->m_host) {
396 if (*mp->m_host == '*') {
397 mp->m_type |= W_HBEG;
398 mp->m_host++;
399 }
400 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
401 mp->m_type |= W_HEND;
402 *cp = '\0';
403 }
404 }
405 if ((cp = getenv ("MHWDEBUG")) && *cp)
406 fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
407 mp->m_mbox, mp->m_host,
408 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
409 }
410 }
411 if (oops)
412 advise (NULL, "please fix the %s: entry in your %s file",
413 "alternate-mailboxes", mh_profile);
414 }
415 }
416
417 if (np == NULL) /* XXX */
418 return 0;
419
420 switch (np->m_type) {
421 case NETHOST:
422 len = strlen (cp = LocalName (0));
423 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
424 break;
425 goto local_test;
426
427 case UUCPHOST:
428 if (mh_strcasecmp (np->m_host, SystemName()))
429 break; /* fall */
430 case LOCALHOST:
431 local_test: ;
432 if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
433 return 1;
434 break;
435
436 default:
437 break;
438 }
439
440 /*
441 * Now scan through list of alternate
442 * mailboxes, and check for a match.
443 */
444 for (mp = &mq; mp->m_next;) {
445 mp = mp->m_next;
446 if (!np->m_mbox)
447 continue;
448 if ((len = strlen (cp = np->m_mbox))
449 < (i = strlen (pp = mp->m_mbox)))
450 continue;
451 switch (mp->m_type & W_MBOX) {
452 case W_NIL:
453 if (mh_strcasecmp (cp, pp))
454 continue;
455 break;
456 case W_MBEG:
457 if (mh_strcasecmp (cp + len - i, pp))
458 continue;
459 break;
460 case W_MEND:
461 if (!uprf (cp, pp))
462 continue;
463 break;
464 case W_MBEG | W_MEND:
465 if (stringdex (pp, cp) < 0)
466 continue;
467 break;
468 }
469
470 if (mp->m_nohost)
471 return 1;
472 if (np->m_host == NULL)
473 continue;
474 if ((len = strlen (cp = np->m_host))
475 < (i = strlen (pp = mp->m_host)))
476 continue;
477 switch (mp->m_type & W_HOST) {
478 case W_NIL:
479 if (mh_strcasecmp (cp, pp))
480 continue;
481 break;
482 case W_HBEG:
483 if (mh_strcasecmp (cp + len - i, pp))
484 continue;
485 break;
486 case W_HEND:
487 if (!uprf (cp, pp))
488 continue;
489 break;
490 case W_HBEG | W_HEND:
491 if (stringdex (pp, cp) < 0)
492 continue;
493 break;
494 }
495 return 1;
496 }
497
498 return 0;
499 }