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, uucp, 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)
83 if (wanthost == AD_HOST)
84 admonish(NULL, "bad address '%s' - %s", str, err);
87 if (pers == NULL && mbox == NULL && host == NULL && route == NULL
90 strcpy(eresult, "null address");
92 if (wanthost == AD_HOST)
93 admonish(NULL, "null address '%s'", str);
96 if (mbox == NULL && grp == NULL) {
98 strcpy(eresult, "no mailbox in address");
99 else if (wanthost == AD_HOST)
100 admonish(NULL, "no mailbox in address '%s'", str);
104 if (dfhost == NULL) {
105 dfhost = LocalName();
109 mp = (struct mailname *) calloc((size_t) 1, sizeof(*mp));
112 strcpy(eresult, "insufficient memory to represent address");
113 else if (wanthost == AD_HOST)
114 adios(NULL, "insufficient memory to represent address");
119 mp->m_text = getcpy(str);
121 mp->m_pers = getcpy(pers);
124 mp->m_type = BADHOST;
127 mp->m_gname = getcpy(grp);
129 mp->m_note = getcpy(note);
134 mp->m_mbox = getcpy(mbox);
135 mp->m_host = getcpy(host);
137 if ((pp = strchr(mbox, '!'))) {
139 mp->m_mbox = getcpy(pp);
140 mp->m_host = getcpy(mbox);
141 mp->m_type = UUCPHOST;
144 mp->m_mbox = getcpy(mbox);
145 if (route == NULL && dftype == LOCALHOST) {
149 mp->m_host = route ? NULL : getcpy(dfhost);
150 mp->m_type = route ? NETHOST : dftype;
156 if (wanthost == AD_NHST)
157 mp->m_type = !mh_strcasecmp(LocalName(), mp->m_host)
158 ? LOCALHOST : NETHOST;
160 mp->m_type = mh_strcasecmp(LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
164 mp->m_path = getcpy(route);
167 mp->m_gname = getcpy(grp);
169 mp->m_note = getcpy(note);
176 mnfree(struct mailname *mp)
200 #define empty(s) ((s) ? (s) : "")
203 adrformat(struct mailname *mp)
205 static char addr[BUFSIZ];
206 static char buffer[BUFSIZ];
209 strncpy(addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
210 else if (mp->m_type != UUCPHOST)
211 snprintf(addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
212 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
214 snprintf(addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
216 if (mp->m_pers || mp->m_path) {
218 snprintf(buffer, sizeof(buffer), "%s %s <%s>",
219 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
222 snprintf(buffer, sizeof(buffer), "%s <%s>",
223 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
225 } else if (mp->m_note)
226 snprintf(buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
228 strncpy(buffer, addr, sizeof(buffer));
235 #define W_MBEG 0x0001
236 #define W_MEND 0x0002
237 #define W_MBOX (W_MBEG | W_MEND)
238 #define W_HBEG 0x0004
239 #define W_HEND 0x0008
240 #define W_HOST (W_HBEG | W_HEND)
241 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
244 ** Check if this is my address
248 ismymbox(struct mailname *np)
256 static char *am = NULL;
257 static struct mailname mq={NULL};
260 ** If this is the first call, initialize
261 ** list of alternate mailboxes.
265 mq.m_mbox = getusername();
266 if ((am = context_find("alternate-mailboxes")) == NULL)
271 while ((cp = getname(am))) {
272 if ((mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL)) == NULL) {
273 admonish(NULL, "illegal address: %s", cp);
278 if (*mp->m_mbox == '*') {
279 mp->m_type |= W_MBEG;
282 if (*(cp = mp->m_mbox + strlen(mp->m_mbox) - 1) == '*') {
283 mp->m_type |= W_MEND;
287 if (*mp->m_host == '*') {
288 mp->m_type |= W_HBEG;
291 if (*(cp = mp->m_host + strlen(mp->m_host) - 1) == '*') {
292 mp->m_type |= W_HEND;
296 if ((cp = getenv("MHWDEBUG")) && *cp)
297 fprintf(stderr, "mbox=\"%s\" host=\"%s\" %s\n",
298 mp->m_mbox, mp->m_host,
299 snprintb(buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
303 advise(NULL, "please fix the profile entry %s",
304 "alternate-mailboxes");
308 if (np == NULL) /* XXX */
311 switch (np->m_type) {
313 len = strlen(cp = LocalName());
314 if (!uprf(np->m_host, cp) || np->m_host[len] != '.')
319 if (mh_strcasecmp(np->m_host, SystemName()))
323 if (!mh_strcasecmp(np->m_mbox, mq.m_mbox))
332 ** Now scan through list of alternate
333 ** mailboxes, and check for a match.
335 for (mp = &mq; mp->m_next;) {
339 if ((len = strlen(cp = np->m_mbox))
340 < (i = strlen(pp = mp->m_mbox)))
342 switch (mp->m_type & W_MBOX) {
344 if (mh_strcasecmp(cp, pp))
348 if (mh_strcasecmp(cp + len - i, pp))
355 case W_MBEG | W_MEND:
356 if (stringdex(pp, cp) < 0)
363 if (np->m_host == NULL)
365 if ((len = strlen(cp = np->m_host))
366 < (i = strlen(pp = mp->m_host)))
368 switch (mp->m_type & W_HOST) {
370 if (mh_strcasecmp(cp, pp))
374 if (mh_strcasecmp (cp + len - i, pp))
381 case W_HBEG | W_HEND:
382 if (stringdex(pp, cp) < 0)
394 ** Moved from hosts.c -- find out the official name of a host
398 ** In the SendMail world, we really don't know what the valid
399 ** hosts are. We could poke around in the sendmail.cf file, but
400 ** that still isn't a guarantee. As a result, we'll say that
401 ** everything is a valid host, and let SendMail worry about it.
408 OfficialName(char *name)
411 char *q, site[BUFSIZ];
412 struct addrinfo hints, *res;
414 static char buffer[BUFSIZ];
416 for (p = name, q = site; *p && (q - site < sizeof(site) - 1); p++, q++)
417 *q = isupper(*p) ? tolower(*p) : *p;
421 if (!mh_strcasecmp(LocalName(), site))
424 memset(&hints, 0, sizeof(hints));
425 hints.ai_flags = AI_CANONNAME;
426 hints.ai_family = PF_UNSPEC;
428 if (getaddrinfo(q, NULL, &hints, &res) == 0) {
429 strncpy(buffer, res->ai_canonname, sizeof(buffer));
430 buffer[sizeof(buffer) - 1] = '\0';
435 strncpy(buffer, site, sizeof(buffer));