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>
14 /* High level parsing of addresses:
16 The routines in sbr/mf.c parse the syntactic representations of
17 addresses. The routines in sbr/addrsbr.c associate semantics with those
20 The comments below are left in for historical purposes; DUMB and
21 REALLYDUMB are now the default in the code.
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.
29 If DUMB is not in effect, then this module does some
30 high-level thinking about what the addresses are.
34 string%<uucp>@<local> -> string
36 2. for non-MMDF systems:
38 string@host.<uucp> -> host!string
40 3. for any system, an address interpreted relative to the local host:
42 string@<uucp> -> string
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.
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
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.
57 To summarize, when we're all done, here's what MH knows about the address:
59 DUMB - type: local, uucp, or network
60 host: not locally defaulted, not explicitly expanded
63 other - type: local, uucp, network, unknown
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];
79 extern boolean username_extension_masquerading; /* defined in mts.c */
85 char *getusername (void);
93 pers = mbox = host = route = grp = note = NULL;
96 if ((ap = getadrx (addrs ? addrs : "")) == NULL)
99 strncpy (adr, ap->text, sizeof(adr));
107 if (ap->err && *ap->err)
108 strncpy (err, ap->err, sizeof(err));
115 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
122 strcpy (eresult, err);
124 if (wanthost == AD_HOST)
125 admonish (NULL, "bad address '%s' - %s", str, err);
129 && mbox == NULL && host == NULL && route == NULL
132 strcpy (eresult, "null address");
134 if (wanthost == AD_HOST)
135 admonish (NULL, "null address '%s'", str);
138 if (mbox == NULL && grp == NULL) {
140 strcpy (eresult, "no mailbox in address");
142 if (wanthost == AD_HOST)
143 admonish (NULL, "no mailbox in address '%s'", str);
147 if (dfhost == NULL) {
148 dfhost = LocalName (0);
152 mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp));
155 strcpy (eresult, "insufficient memory to represent address");
157 if (wanthost == AD_HOST)
158 adios (NULL, "insufficient memory to represent address");
163 mp->m_text = getcpy (str);
165 mp->m_pers = getcpy (pers);
168 mp->m_type = BADHOST;
171 mp->m_gname = getcpy (grp);
173 mp->m_note = getcpy (note);
178 mp->m_mbox = getcpy (mbox);
179 mp->m_host = getcpy (host);
182 if ((pp = strchr(mbox, '!'))) {
184 mp->m_mbox = getcpy (pp);
185 mp->m_host = getcpy (mbox);
186 mp->m_type = UUCPHOST;
190 mp->m_mbox = getcpy (mbox);
191 if (route == NULL && dftype == LOCALHOST) {
197 mp->m_host = route ? NULL : getcpy (dfhost);
198 mp->m_type = route ? NETHOST : dftype;
204 if (wanthost == AD_NHST)
205 mp->m_type = !mh_strcasecmp (LocalName (0), mp->m_host)
206 ? LOCALHOST : NETHOST;
208 mp->m_type = mh_strcasecmp (LocalName(0), mp->m_host) ? NETHOST : LOCALHOST;
212 mp->m_path = getcpy (route);
215 mp->m_gname = getcpy (grp);
217 mp->m_note = getcpy (note);
224 mnfree (struct mailname *mp)
248 #define empty(s) ((s) ? (s) : "")
251 auxformat (struct mailname *mp, int extras)
253 static char addr[BUFSIZ];
254 static char buffer[BUFSIZ];
257 strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
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);
264 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
269 if (mp->m_pers || mp->m_path) {
271 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
272 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
275 snprintf (buffer, sizeof(buffer), "%s <%s>",
276 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
281 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
283 strncpy (buffer, addr, sizeof(buffer));
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.
300 char *username, *domain;
301 static char addr[BUFSIZ];
303 username = getusername();
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,
309 char* extension = getenv("USERNAME_EXTENSION");
310 static char username_with_extension[BUFSIZ];
312 if (extension != NULL && *extension != '\0') {
313 snprintf_return = snprintf(username_with_extension,
314 sizeof(username_with_extension),
315 "%s%s", username, extension);
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)"
322 strlen(username), strlen(extension), BUFSIZ);
324 username = username_with_extension;
330 domain = LocalName(0);
332 snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
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);
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"
353 * Check if this is my address
357 ismymbox (struct mailname *np)
365 static char *am = NULL;
366 static struct mailname mq;
369 * If this is the first call, initialize
370 * list of alternate mailboxes.
373 if ((am = context_find ("local-mailbox"))) {
374 struct mailname *mptr;
376 if ((cp = getname(am)) == NULL) {
377 admonish (NULL, "Unable to find address in local-mailbox");
381 if ((mptr = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
382 admonish (NULL, "invalid entry in local-mailbox: %s", cp);
387 * Yes, we're not freeing the whole entry, because all of those
388 * elements contain allocated pointers that we need; maybe
397 * Sigh, it turns out that the address parser gets messed up
398 * if you don't call getname() until it returns NULL.
401 while ((cp = getname(am)) != NULL)
404 mq.m_mbox = getusername ();
409 if ((am = context_find ("alternate-mailboxes")) == NULL)
414 while ((cp = getname (am))) {
415 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
416 admonish (NULL, "illegal address: %s", cp);
421 if (*mp->m_mbox == '*') {
422 mp->m_type |= W_MBEG;
425 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
426 mp->m_type |= W_MEND;
430 if (*mp->m_host == '*') {
431 mp->m_type |= W_HBEG;
434 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
435 mp->m_type |= W_HEND;
439 if ((cp = getenv ("MHWDEBUG")) && *cp)
440 fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
441 mp->m_mbox, mp->m_host,
442 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
446 advise (NULL, "please fix the %s: entry in your %s file",
447 "alternate-mailboxes", mh_profile);
451 if (np == NULL) /* XXX */
454 switch (np->m_type) {
456 len = strlen (cp = LocalName (0));
457 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
462 if (mh_strcasecmp (np->m_host, SystemName()))
466 if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
475 * Now scan through list of alternate
476 * mailboxes, and check for a match.
478 for (mp = &mq; mp->m_next;) {
482 if ((len = strlen (cp = np->m_mbox))
483 < (i = strlen (pp = mp->m_mbox)))
485 switch (mp->m_type & W_MBOX) {
487 if (mh_strcasecmp (cp, pp))
491 if (mh_strcasecmp (cp + len - i, pp))
498 case W_MBEG | W_MEND:
499 if (stringdex (pp, cp) < 0)
506 if (np->m_host == NULL)
508 if ((len = strlen (cp = np->m_host))
509 < (i = strlen (pp = mp->m_host)))
511 switch (mp->m_type & W_HOST) {
513 if (mh_strcasecmp (cp, pp))
517 if (mh_strcasecmp (cp + len - i, pp))
524 case W_HBEG | W_HEND:
525 if (stringdex (pp, cp) < 0)