3 * addrsbr.c -- parse addresses 822-style
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.
11 #include <h/addrsbr.h>
15 /* High level parsing of addresses:
17 The routines in sbr/mf.c parse the syntactic representations of
18 addresses. The routines in sbr/addrsbr.c associate semantics with those
21 The comments below are left in for historical purposes; DUMB and
22 REALLYDUMB are now the default in the code.
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.
30 If DUMB is not in effect, then this module does some
31 high-level thinking about what the addresses are.
35 string%<uucp>@<local> -> string
37 2. for non-MMDF systems:
39 string@host.<uucp> -> host!string
41 3. for any system, an address interpreted relative to the local host:
43 string@<uucp> -> string
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.
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
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.
58 To summarize, when we're all done, here's what MH knows about the address:
60 DUMB - type: local, uucp, or network
61 host: not locally defaulted, not explicitly expanded
64 other - type: local, uucp, network, unknown
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];
80 extern boolean username_extension_masquerading; /* defined in mts.c */
88 pers = mbox = host = route = grp = note = NULL;
91 if ((ap = getadrx (addrs ? addrs : "")) == NULL)
94 strncpy (adr, ap->text, sizeof(adr));
102 if (ap->err && *ap->err)
103 strncpy (err, ap->err, sizeof(err));
110 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
117 strcpy (eresult, err);
119 if (wanthost == AD_HOST)
120 admonish (NULL, "bad address '%s' - %s", str, err);
124 && mbox == NULL && host == NULL && route == NULL
127 strcpy (eresult, "null address");
129 if (wanthost == AD_HOST)
130 admonish (NULL, "null address '%s'", str);
133 if (mbox == NULL && grp == NULL) {
135 strcpy (eresult, "no mailbox in address");
137 if (wanthost == AD_HOST)
138 admonish (NULL, "no mailbox in address '%s'", str);
142 if (dfhost == NULL) {
143 dfhost = LocalName (0);
147 mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp));
150 strcpy (eresult, "insufficient memory to represent address");
152 if (wanthost == AD_HOST)
153 adios (NULL, "insufficient memory to represent address");
158 mp->m_text = getcpy (str);
160 mp->m_pers = getcpy (pers);
163 mp->m_type = BADHOST;
166 mp->m_gname = getcpy (grp);
168 mp->m_note = getcpy (note);
173 mp->m_mbox = getcpy (mbox);
174 mp->m_host = getcpy (host);
177 if ((pp = strchr(mbox, '!'))) {
179 mp->m_mbox = getcpy (pp);
180 mp->m_host = getcpy (mbox);
181 mp->m_type = UUCPHOST;
185 mp->m_mbox = getcpy (mbox);
186 if (route == NULL && dftype == LOCALHOST) {
192 mp->m_host = route ? NULL : getcpy (dfhost);
193 mp->m_type = route ? NETHOST : dftype;
199 if (wanthost == AD_NHST)
200 mp->m_type = !mh_strcasecmp (LocalName (0), mp->m_host)
201 ? LOCALHOST : NETHOST;
203 mp->m_type = mh_strcasecmp (LocalName(0), mp->m_host) ? NETHOST : LOCALHOST;
207 mp->m_path = getcpy (route);
210 mp->m_gname = getcpy (grp);
212 mp->m_note = getcpy (note);
219 mnfree (struct mailname *mp)
243 #define empty(s) ((s) ? (s) : "")
246 auxformat (struct mailname *mp, int extras)
248 static char addr[BUFSIZ];
249 static char buffer[BUFSIZ];
252 strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
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);
259 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
264 if (mp->m_pers || mp->m_path) {
266 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
267 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
270 snprintf (buffer, sizeof(buffer), "%s <%s>",
271 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
276 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
278 strncpy (buffer, addr, sizeof(buffer));
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.
295 char *username, *domain;
296 static char addr[BUFSIZ];
298 username = getusername();
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,
304 char* extension = getenv("USERNAME_EXTENSION");
305 static char username_with_extension[BUFSIZ];
307 if (extension != NULL && *extension != '\0') {
308 snprintf_return = snprintf(username_with_extension,
309 sizeof(username_with_extension),
310 "%s%s", username, extension);
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)"
317 strlen(username), strlen(extension), BUFSIZ);
319 username = username_with_extension;
325 domain = LocalName(0);
327 snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
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);
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"
348 * Check if this is my address
352 ismymbox (struct mailname *np)
360 static char *am = NULL;
361 static struct mailname mq;
362 static int localmailbox = 0;
365 * If this is the first call, initialize
366 * list of alternate mailboxes.
370 mq.m_mbox = getusername ();
372 if ((am = context_find ("local-mailbox"))) {
376 if ((cp = getname(am)) == NULL) {
377 admonish (NULL, "Unable to find address in local-mailbox");
381 if ((mq.m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
382 admonish (NULL, "invalid entry in local-mailbox: %s", cp);
387 * Sigh, it turns out that the address parser gets messed up
388 * if you don't call getname() until it returns NULL.
391 while ((cp = getname(am)) != NULL)
395 if ((am = context_find ("alternate-mailboxes")) == NULL)
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);
407 if (*mp->m_mbox == '*') {
408 mp->m_type |= W_MBEG;
411 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
412 mp->m_type |= W_MEND;
416 if (*mp->m_host == '*') {
417 mp->m_type |= W_HBEG;
420 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
421 mp->m_type |= W_HEND;
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));
432 advise (NULL, "please fix the %s: entry in your %s file",
433 "alternate-mailboxes", mh_profile);
437 if (np == NULL) /* XXX */
441 * Don't perform this "local" test if we have a Local-Mailbox set
445 switch (np->m_type) {
447 len = strlen (cp = LocalName (0));
448 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
453 if (mh_strcasecmp (np->m_host, SystemName()))
457 if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
466 * Now scan through list of alternate
467 * mailboxes, and check for a match.
469 for (mp = &mq; mp->m_next;) {
472 continue; if ((len = strlen (cp = np->m_mbox))
473 < (i = strlen (pp = mp->m_mbox)))
475 switch (mp->m_type & W_MBOX) {
477 if (mh_strcasecmp (cp, pp))
481 if (mh_strcasecmp (cp + len - i, pp))
488 case W_MBEG | W_MEND:
489 if (stringdex (pp, cp) < 0)
496 if (np->m_host == NULL)
498 if ((len = strlen (cp = np->m_host))
499 < (i = strlen (pp = mp->m_host)))
501 switch (mp->m_type & W_HOST) {
503 if (mh_strcasecmp (cp, pp))
507 if (mh_strcasecmp (cp + len - i, pp))
514 case W_HBEG | W_HEND:
515 if (stringdex (pp, cp) < 0)