3 * addrsbr.c -- parse addresses 822-style
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
13 #include <h/addrsbr.h>
16 /* High level parsing of addresses:
18 The routines in sbr/mf.c parse the syntactic representations of
19 addresses. The routines in sbr/addrsbr.c associate semantics with those
22 If #ifdef DUMB is in effect, a full 822-style parser is called
23 for syntax recongition. This breaks each address into its components.
24 Note however that no semantics are assumed about the parts or their
25 totality. This means that implicit hostnames aren't made explicit,
26 and explicit hostnames aren't expanded to their "official" represenations.
28 If DUMB is not in effect, then this module does some
29 high-level thinking about what the addresses are.
33 string%<uucp>@<local> -> string
35 2. for non-MMDF systems:
37 string@host.<uucp> -> host!string
39 3. for any system, an address interpreted relative to the local host:
41 string@<uucp> -> string
43 For cases (1) and (3) above, the leftmost host is extracted. If it's not
44 present, the local host is used. If the tests above fail, the address is
45 considered to be a real 822-style address.
47 If an explicit host is not present, then MH checks for a bang to indicate
48 an explicit UUCP-style address. If so, this is noted. If not, the host is
49 defaulted, typically to the local host. The lack of an explict host is
52 If an explicit 822-style host is present, then MH checks to see if it
53 can expand this to the official name for the host. If the hostname is
54 unknown, the address is so typed.
56 To summarize, when we're all done, here's what MH knows about the address:
58 DUMB - type: local, uucp, or network
59 host: not locally defaulted, not explicitly expanded
62 other - type: local, uucp, network, unknown
68 static char *pers = NULL;
69 static char *mbox = NULL;
70 static char *host = NULL;
71 static char *route = NULL;
72 static char *grp = NULL;
73 static char *note = NULL;
74 static char err[BUFSIZ];
75 static char adr[BUFSIZ];
78 extern boolean username_extension_masquerading; /* defined in mts.c */
84 char *getusername (void);
92 pers = mbox = host = route = grp = note = NULL;
95 if ((ap = getadrx (addrs ? addrs : "")) == NULL)
98 strncpy (adr, ap->text, sizeof(adr));
106 if (ap->err && *ap->err)
107 strncpy (err, ap->err, sizeof(err));
114 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
120 #endif /* not DUMB */
124 strcpy (eresult, err);
126 if (wanthost == AD_HOST)
127 admonish (NULL, "bad address '%s' - %s", str, err);
131 && mbox == NULL && host == NULL && route == NULL
134 strcpy (eresult, "null address");
136 if (wanthost == AD_HOST)
137 admonish (NULL, "null address '%s'", str);
140 if (mbox == NULL && grp == NULL) {
142 strcpy (eresult, "no mailbox in address");
144 if (wanthost == AD_HOST)
145 admonish (NULL, "no mailbox in address '%s'", str);
149 if (dfhost == NULL) {
150 dfhost = LocalName ();
154 mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp));
157 strcpy (eresult, "insufficient memory to represent address");
159 if (wanthost == AD_HOST)
160 adios (NULL, "insufficient memory to represent address");
165 mp->m_text = getcpy (str);
167 mp->m_pers = getcpy (pers);
170 mp->m_type = BADHOST;
173 mp->m_gname = getcpy (grp);
175 mp->m_note = getcpy (note);
180 mp->m_mbox = getcpy (mbox);
181 mp->m_host = getcpy (host);
184 if ((pp = strchr(mbox, '!'))) {
186 mp->m_mbox = getcpy (pp);
187 mp->m_host = getcpy (mbox);
188 mp->m_type = UUCPHOST;
192 mp->m_mbox = getcpy (mbox);
194 if (route == NULL && dftype == LOCALHOST) {
201 mp->m_host = route ? NULL : getcpy (dfhost);
202 mp->m_type = route ? NETHOST : dftype;
208 if (wanthost == AD_NHST)
209 mp->m_type = !mh_strcasecmp (LocalName (), mp->m_host)
210 ? LOCALHOST : NETHOST;
213 mp->m_type = mh_strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
216 if (pp = OfficialName (mp->m_host)) {
219 mp->m_host = getcpy (pp);
220 mp->m_type = mh_strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
223 if (dp = strchr(mp->m_host, '.')) {
225 if (pp = OfficialName (mp->m_host))
229 mp->m_type = BADHOST;
231 #endif /* not DUMB */
235 mp->m_path = getcpy (route);
238 mp->m_gname = getcpy (grp);
240 mp->m_note = getcpy (note);
247 mnfree (struct mailname *mp)
271 #define empty(s) ((s) ? (s) : "")
274 auxformat (struct mailname *mp, int extras)
276 static char addr[BUFSIZ];
277 static char buffer[BUFSIZ];
281 strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
286 if (mp->m_type != UUCPHOST)
287 snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
288 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
290 #endif /* not BANG */
291 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
296 if (mp->m_pers || mp->m_path) {
298 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
299 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
302 snprintf (buffer, sizeof(buffer), "%s <%s>",
303 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
308 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
310 strncpy (buffer, addr, sizeof(buffer));
317 * address specific "sprintf"
321 adrsprintf (char *username, char *domain)
324 static char addr[BUFSIZ];
326 if (username == NULL)
327 username = getusername();
329 if (username_extension_masquerading) {
330 /* mts.conf contains "masquerade:[...]username_extension[...]", so tack
331 on the value of the $USERNAME_EXTENSION environment variable, if set,
333 char* extension = getenv("USERNAME_EXTENSION");
334 static char username_with_extension[BUFSIZ];
336 if (extension != NULL && *extension != '\0') {
337 snprintf_return = snprintf(username_with_extension,
338 sizeof(username_with_extension),
339 "%s%s", username, extension);
341 if (snprintf_return < 0 ||
342 snprintf_return >= sizeof(username_with_extension))
343 adios(NULL, "snprintf() error writing username (%d chars) and"
344 " $USERNAME_EXTENSION (%d chars) to array of BUFSIZ (%d)"
346 strlen(username), strlen(extension), BUFSIZ);
348 username = username_with_extension;
357 domain = LocalName();
360 snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
362 snprintf_return = snprintf (addr, sizeof(addr), "%s!%s", domain, username);
365 if (snprintf_return < 0 || snprintf_return >= sizeof(addr))
366 adios(NULL, "snprintf() error writing username (%d chars), domain (%d"
367 " chars), and 1 separator char to array of BUFSIZ (%d) chars",
368 strlen(username), strlen(domain), BUFSIZ);
375 #define W_MBEG 0x0001
376 #define W_MEND 0x0002
377 #define W_MBOX (W_MBEG | W_MEND)
378 #define W_HBEG 0x0004
379 #define W_HEND 0x0008
380 #define W_HOST (W_HBEG | W_HEND)
381 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
384 * Check if this is my address
388 ismymbox (struct mailname *np)
396 static char *am = NULL;
397 static struct mailname mq={NULL};
400 * If this is the first call, initialize
401 * list of alternate mailboxes.
405 mq.m_mbox = getusername ();
406 if ((am = context_find ("alternate-mailboxes")) == NULL)
411 while ((cp = getname (am))) {
412 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
413 admonish (NULL, "illegal address: %s", cp);
418 if (*mp->m_mbox == '*') {
419 mp->m_type |= W_MBEG;
422 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
423 mp->m_type |= W_MEND;
427 if (*mp->m_host == '*') {
428 mp->m_type |= W_HBEG;
431 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
432 mp->m_type |= W_HEND;
436 if ((cp = getenv ("MHWDEBUG")) && *cp)
437 fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
438 mp->m_mbox, mp->m_host,
439 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
443 advise (NULL, "please fix the %s: entry in your %s file",
444 "alternate-mailboxes", mh_profile);
448 if (np == NULL) /* XXX */
451 switch (np->m_type) {
453 len = strlen (cp = LocalName ());
454 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
459 if (mh_strcasecmp (np->m_host, SystemName()))
463 if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
472 * Now scan through list of alternate
473 * mailboxes, and check for a match.
475 for (mp = &mq; mp->m_next;) {
479 if ((len = strlen (cp = np->m_mbox))
480 < (i = strlen (pp = mp->m_mbox)))
482 switch (mp->m_type & W_MBOX) {
484 if (mh_strcasecmp (cp, pp))
488 if (mh_strcasecmp (cp + len - i, pp))
495 case W_MBEG | W_MEND:
496 if (stringdex (pp, cp) < 0)
503 if (np->m_host == NULL)
505 if ((len = strlen (cp = np->m_host))
506 < (i = strlen (pp = mp->m_host)))
508 switch (mp->m_type & W_HOST) {
510 if (mh_strcasecmp (cp, pp))
514 if (mh_strcasecmp (cp + len - i, pp))
521 case W_HBEG | W_HEND:
522 if (stringdex (pp, cp) < 0)