2 ** addrsbr.c -- parse addresses 822-style
4 ** This code is Copyright (c) 2002, by the authors of nmh. See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
10 #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 ** A full 822-style parser is called for syntax recongition. This breaks
21 ** each address into its components. Note however that no semantics are
22 ** assumed about the parts or their totality. This means that implicit
23 ** hostnames aren't made explicit, and explicit hostnames aren't expanded
24 ** to their "official" represenations.
26 ** To summarize, when we're all done, here's what MH knows about the address:
27 ** type: local or network
28 ** host: not locally defaulted, not explicitly expanded
34 static char *pers = NULL;
35 static char *mbox = NULL;
36 static char *host = NULL;
37 static char *route = NULL;
38 static char *grp = NULL;
39 static char *note = NULL;
40 static char err[BUFSIZ];
41 static char adr[BUFSIZ];
43 /* static prototype */
44 char *OfficialName(char *);
52 pers = mbox = host = route = grp = note = NULL;
55 if ((ap = getadrx(addrs ? addrs : "")) == NULL)
58 strncpy(adr, ap->text, sizeof(adr));
66 if (ap->err && *ap->err)
67 strncpy(err, ap->err, sizeof(err));
74 getm(char *str, char *dfhost, int dftype, int wanthost, char *eresult)
82 if (wanthost == AD_HOST)
83 admonish(NULL, "bad address '%s' - %s", str, err);
86 if (pers == NULL && mbox == NULL && host == NULL && route == NULL
89 strcpy(eresult, "null address");
91 if (wanthost == AD_HOST)
92 admonish(NULL, "null address '%s'", str);
95 if (mbox == NULL && grp == NULL) {
97 strcpy(eresult, "no mailbox in address");
98 else if (wanthost == AD_HOST)
99 admonish(NULL, "no mailbox in address '%s'", str);
103 if (dfhost == NULL) {
104 dfhost = LocalName();
108 mp = (struct mailname *) calloc((size_t) 1, sizeof(*mp));
111 strcpy(eresult, "insufficient memory to represent address");
112 else if (wanthost == AD_HOST)
113 adios(NULL, "insufficient memory to represent address");
118 mp->m_text = getcpy(str);
120 mp->m_pers = getcpy(pers);
123 mp->m_type = BADHOST;
126 mp->m_gname = getcpy(grp);
128 mp->m_note = getcpy(note);
133 mp->m_mbox = getcpy(mbox);
134 mp->m_host = getcpy(host);
137 mp->m_mbox = getcpy(mbox);
138 if (route == NULL && dftype == LOCALHOST) {
142 mp->m_host = route ? NULL : getcpy(dfhost);
143 mp->m_type = route ? NETHOST : dftype;
148 if (wanthost == AD_NHST)
149 mp->m_type = !mh_strcasecmp(LocalName(), mp->m_host)
150 ? LOCALHOST : NETHOST;
152 mp->m_type = mh_strcasecmp(LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
156 mp->m_path = getcpy(route);
159 mp->m_gname = getcpy(grp);
161 mp->m_note = getcpy(note);
168 mnfree(struct mailname *mp)
192 #define empty(s) ((s) ? (s) : "")
195 adrformat(struct mailname *mp)
197 static char addr[BUFSIZ];
198 static char buffer[BUFSIZ];
201 strncpy(addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
203 snprintf(addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
204 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
206 if (mp->m_pers || mp->m_path) {
208 snprintf(buffer, sizeof(buffer), "%s %s <%s>",
209 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
212 snprintf(buffer, sizeof(buffer), "%s <%s>",
213 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
215 } else if (mp->m_note)
216 snprintf(buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
218 strncpy(buffer, addr, sizeof(buffer));
225 #define W_MBEG 0x0001
226 #define W_MEND 0x0002
227 #define W_MBOX (W_MBEG | W_MEND)
228 #define W_HBEG 0x0004
229 #define W_HEND 0x0008
230 #define W_HOST (W_HBEG | W_HEND)
231 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
234 ** Check if this is my address
238 ismymbox(struct mailname *np)
246 static char *am = NULL;
247 static struct mailname mq={NULL};
250 ** If this is the first call, initialize
251 ** list of alternate mailboxes.
255 mq.m_mbox = getusername();
256 if ((am = context_find("alternate-mailboxes")) == NULL)
261 while ((cp = getname(am))) {
262 if ((mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL)) == NULL) {
263 admonish(NULL, "illegal address: %s", cp);
268 if (*mp->m_mbox == '*') {
269 mp->m_type |= W_MBEG;
272 if (*(cp = mp->m_mbox + strlen(mp->m_mbox) - 1) == '*') {
273 mp->m_type |= W_MEND;
277 if (*mp->m_host == '*') {
278 mp->m_type |= W_HBEG;
281 if (*(cp = mp->m_host + strlen(mp->m_host) - 1) == '*') {
282 mp->m_type |= W_HEND;
286 if ((cp = getenv("MHWDEBUG")) && *cp)
287 fprintf(stderr, "mbox=\"%s\" host=\"%s\" %s\n",
288 mp->m_mbox, mp->m_host,
289 snprintb(buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
293 advise(NULL, "please fix the profile entry %s",
294 "alternate-mailboxes");
298 if (np == NULL) /* XXX */
301 switch (np->m_type) {
303 len = strlen(cp = LocalName());
304 if (!uprf(np->m_host, cp) || np->m_host[len] != '.')
310 if (!mh_strcasecmp(np->m_mbox, mq.m_mbox))
319 ** Now scan through list of alternate
320 ** mailboxes, and check for a match.
322 for (mp = &mq; mp->m_next;) {
326 if ((len = strlen(cp = np->m_mbox))
327 < (i = strlen(pp = mp->m_mbox)))
329 switch (mp->m_type & W_MBOX) {
331 if (mh_strcasecmp(cp, pp))
335 if (mh_strcasecmp(cp + len - i, pp))
342 case W_MBEG | W_MEND:
343 if (stringdex(pp, cp) < 0)
350 if (np->m_host == NULL)
352 if ((len = strlen(cp = np->m_host))
353 < (i = strlen(pp = mp->m_host)))
355 switch (mp->m_type & W_HOST) {
357 if (mh_strcasecmp(cp, pp))
361 if (mh_strcasecmp (cp + len - i, pp))
368 case W_HBEG | W_HEND:
369 if (stringdex(pp, cp) < 0)
381 ** Moved from hosts.c -- find out the official name of a host
385 ** In the SendMail world, we really don't know what the valid
386 ** hosts are. We could poke around in the sendmail.cf file, but
387 ** that still isn't a guarantee. As a result, we'll say that
388 ** everything is a valid host, and let SendMail worry about it.
395 OfficialName(char *name)
398 char *q, site[BUFSIZ];
399 struct addrinfo hints, *res;
401 static char buffer[BUFSIZ];
403 for (p = name, q = site; *p && (q - site < sizeof(site) - 1); p++, q++)
404 *q = isupper(*p) ? tolower(*p) : *p;
408 if (!mh_strcasecmp(LocalName(), site))
411 memset(&hints, 0, sizeof(hints));
412 hints.ai_flags = AI_CANONNAME;
413 hints.ai_family = PF_UNSPEC;
415 if (getaddrinfo(q, NULL, &hints, &res) == 0) {
416 strncpy(buffer, res->ai_canonname, sizeof(buffer));
417 buffer[sizeof(buffer) - 1] = '\0';
422 strncpy(buffer, site, sizeof(buffer));