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 If #ifdef DUMB is in effect, a full 822-style parser is called
21 for syntax recongition. This breaks each address into its components.
22 Note however that no semantics are assumed about the parts or their
23 totality. This means that implicit hostnames aren't made explicit,
24 and explicit hostnames aren't expanded to their "official" represenations.
26 If DUMB is not in effect, then this module does some
27 high-level thinking about what the addresses are.
31 string%<uucp>@<local> -> string
33 2. for non-MMDF systems:
35 string@host.<uucp> -> host!string
37 3. for any system, an address interpreted relative to the local host:
39 string@<uucp> -> string
41 For cases (1) and (3) above, the leftmost host is extracted. If it's not
42 present, the local host is used. If the tests above fail, the address is
43 considered to be a real 822-style address.
45 If an explicit host is not present, then MH checks for a bang to indicate
46 an explicit UUCP-style address. If so, this is noted. If not, the host is
47 defaulted, typically to the local host. The lack of an explict host is
50 If an explicit 822-style host is present, then MH checks to see if it
51 can expand this to the official name for the host. If the hostname is
52 unknown, the address is so typed.
54 To summarize, when we're all done, here's what MH knows about the address:
56 DUMB - type: local, uucp, or network
57 host: not locally defaulted, not explicitly expanded
60 other - type: local, uucp, network, unknown
66 static char *pers = NULL;
67 static char *mbox = NULL;
68 static char *host = NULL;
69 static char *route = NULL;
70 static char *grp = NULL;
71 static char *note = NULL;
72 static char err[BUFSIZ];
73 static char adr[BUFSIZ];
76 extern boolean username_extension_masquerading; /* defined in mts.c */
82 char *getusername (void);
90 pers = mbox = host = route = grp = note = NULL;
93 if ((ap = getadrx (addrs ? addrs : "")) == NULL)
96 strncpy (adr, ap->text, sizeof(adr));
104 if (ap->err && *ap->err)
105 strncpy (err, ap->err, sizeof(err));
112 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
118 #endif /* not DUMB */
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 ();
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);
192 if (route == NULL && dftype == LOCALHOST) {
199 mp->m_host = route ? NULL : getcpy (dfhost);
200 mp->m_type = route ? NETHOST : dftype;
206 if (wanthost == AD_NHST)
207 mp->m_type = !mh_strcasecmp (LocalName (), mp->m_host)
208 ? LOCALHOST : NETHOST;
211 mp->m_type = mh_strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
214 if (pp = OfficialName (mp->m_host)) {
217 mp->m_host = getcpy (pp);
218 mp->m_type = mh_strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
221 if (dp = strchr(mp->m_host, '.')) {
223 if (pp = OfficialName (mp->m_host))
227 mp->m_type = BADHOST;
229 #endif /* not DUMB */
233 mp->m_path = getcpy (route);
236 mp->m_gname = getcpy (grp);
238 mp->m_note = getcpy (note);
245 mnfree (struct mailname *mp)
269 #define empty(s) ((s) ? (s) : "")
272 auxformat (struct mailname *mp, int extras)
274 static char addr[BUFSIZ];
275 static char buffer[BUFSIZ];
279 strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
284 if (mp->m_type != UUCPHOST)
285 snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
286 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
288 #endif /* not BANG */
289 snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
294 if (mp->m_pers || mp->m_path) {
296 snprintf (buffer, sizeof(buffer), "%s %s <%s>",
297 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
300 snprintf (buffer, sizeof(buffer), "%s <%s>",
301 legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
306 snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
308 strncpy (buffer, addr, sizeof(buffer));
315 * address specific "sprintf"
319 adrsprintf (char *username, char *domain)
322 static char addr[BUFSIZ];
324 if (username == NULL)
325 username = getusername();
327 if (username_extension_masquerading) {
328 /* mts.conf contains "masquerade:[...]username_extension[...]", so tack
329 on the value of the $USERNAME_EXTENSION environment variable, if set,
331 char* extension = getenv("USERNAME_EXTENSION");
332 static char username_with_extension[BUFSIZ];
334 if (extension != NULL && *extension != '\0') {
335 snprintf_return = snprintf(username_with_extension,
336 sizeof(username_with_extension),
337 "%s%s", username, extension);
339 if (snprintf_return < 0 ||
340 snprintf_return >= sizeof(username_with_extension))
341 adios(NULL, "snprintf() error writing username (%d chars) and"
342 " $USERNAME_EXTENSION (%d chars) to array of BUFSIZ (%d)"
344 strlen(username), strlen(extension), BUFSIZ);
346 username = username_with_extension;
355 domain = LocalName();
358 snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
360 snprintf_return = snprintf (addr, sizeof(addr), "%s!%s", domain, username);
363 if (snprintf_return < 0 || snprintf_return >= sizeof(addr))
364 adios(NULL, "snprintf() error writing username (%d chars), domain (%d"
365 " chars), and 1 separator char to array of BUFSIZ (%d) chars",
366 strlen(username), strlen(domain), BUFSIZ);
373 #define W_MBEG 0x0001
374 #define W_MEND 0x0002
375 #define W_MBOX (W_MBEG | W_MEND)
376 #define W_HBEG 0x0004
377 #define W_HEND 0x0008
378 #define W_HOST (W_HBEG | W_HEND)
379 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
382 * Check if this is my address
386 ismymbox (struct mailname *np)
394 static char *am = NULL;
395 static struct mailname mq={NULL};
398 * If this is the first call, initialize
399 * list of alternate mailboxes.
403 mq.m_mbox = getusername ();
404 if ((am = context_find ("alternate-mailboxes")) == NULL)
409 while ((cp = getname (am))) {
410 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
411 admonish (NULL, "illegal address: %s", cp);
416 if (*mp->m_mbox == '*') {
417 mp->m_type |= W_MBEG;
420 if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
421 mp->m_type |= W_MEND;
425 if (*mp->m_host == '*') {
426 mp->m_type |= W_HBEG;
429 if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
430 mp->m_type |= W_HEND;
434 if ((cp = getenv ("MHWDEBUG")) && *cp)
435 fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
436 mp->m_mbox, mp->m_host,
437 snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
441 advise (NULL, "please fix the %s: entry in your %s file",
442 "alternate-mailboxes", mh_profile);
446 if (np == NULL) /* XXX */
449 switch (np->m_type) {
451 len = strlen (cp = LocalName ());
452 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
457 if (mh_strcasecmp (np->m_host, SystemName()))
461 if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
470 * Now scan through list of alternate
471 * mailboxes, and check for a match.
473 for (mp = &mq; mp->m_next;) {
477 if ((len = strlen (cp = np->m_mbox))
478 < (i = strlen (pp = mp->m_mbox)))
480 switch (mp->m_type & W_MBOX) {
482 if (mh_strcasecmp (cp, pp))
486 if (mh_strcasecmp (cp + len - i, pp))
493 case W_MBEG | W_MEND:
494 if (stringdex (pp, cp) < 0)
501 if (np->m_host == NULL)
503 if ((len = strlen (cp = np->m_host))
504 < (i = strlen (pp = mp->m_host)))
506 switch (mp->m_type & W_HOST) {
508 if (mh_strcasecmp (cp, pp))
512 if (mh_strcasecmp (cp + len - i, pp))
519 case W_HBEG | W_HEND:
520 if (stringdex (pp, cp) < 0)