Made DUMB the default and removed the the #ifdefs.
[mmh] / sbr / addrsbr.c
1 /*
2 ** addrsbr.c -- parse addresses 822-style
3 **
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.
7 */
8
9 #include <h/mh.h>
10 #include <h/addrsbr.h>
11 #include <h/mf.h>
12
13 /*
14 ** High level parsing of addresses:
15 **
16 ** The routines in sbr/mf.c parse the syntactic representations of
17 ** addresses.  The routines in sbr/addrsbr.c associate semantics with those
18 ** addresses.
19 **
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.
25 **
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
29 **       everything else
30 */
31
32
33 static int  ingrp = 0;
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];
42
43 /* static prototype */
44 char *OfficialName(char *);
45
46
47 char *
48 getname(char *addrs)
49 {
50         struct adrx *ap;
51
52         pers = mbox = host = route = grp = note = NULL;
53         err[0] = '\0';
54
55         if ((ap = getadrx(addrs ? addrs : "")) == NULL)
56                 return NULL;
57
58         strncpy(adr, ap->text, sizeof(adr));
59         pers = ap->pers;
60         mbox = ap->mbox;
61         host = ap->host;
62         route = ap->path;
63         grp = ap->grp;
64         ingrp = ap->ingrp;
65         note = ap->note;
66         if (ap->err && *ap->err)
67                 strncpy(err, ap->err, sizeof(err));
68
69         return adr;
70 }
71
72
73 struct mailname *
74 getm(char *str, char *dfhost, int dftype, int wanthost, char *eresult)
75 {
76         char *pp;
77         struct mailname *mp;
78
79         if (err[0]) {
80                 if (eresult)
81                         strcpy(eresult, err);
82                 else
83                         if (wanthost == AD_HOST)
84                                 admonish(NULL, "bad address '%s' - %s", str, err);
85                 return NULL;
86         }
87         if (pers == NULL && mbox == NULL && host == NULL && route == NULL
88                 && grp == NULL) {
89                 if (eresult)
90                         strcpy(eresult, "null address");
91                 else
92                         if (wanthost == AD_HOST)
93                                 admonish(NULL, "null address '%s'", str);
94                 return NULL;
95         }
96         if (mbox == NULL && grp == NULL) {
97                 if (eresult)
98                         strcpy(eresult, "no mailbox in address");
99                 else if (wanthost == AD_HOST)
100                         admonish(NULL, "no mailbox in address '%s'", str);
101                 return NULL;
102         }
103
104         if (dfhost == NULL) {
105                 dfhost = LocalName();
106                 dftype = LOCALHOST;
107         }
108
109         mp = (struct mailname *) calloc((size_t) 1, sizeof(*mp));
110         if (mp == NULL) {
111                 if (eresult)
112                         strcpy(eresult, "insufficient memory to represent address");
113                 else if (wanthost == AD_HOST)
114                         adios(NULL, "insufficient memory to represent address");
115                 return NULL;
116         }
117
118         mp->m_next = NULL;
119         mp->m_text = getcpy(str);
120         if (pers)
121                 mp->m_pers = getcpy(pers);
122
123         if (mbox == NULL) {
124                 mp->m_type = BADHOST;
125                 mp->m_nohost = 1;
126                 mp->m_ingrp = ingrp;
127                 mp->m_gname = getcpy(grp);
128                 if (note)
129                         mp->m_note = getcpy(note);
130                 return mp;
131         }
132
133         if (host) {
134                 mp->m_mbox = getcpy(mbox);
135                 mp->m_host = getcpy(host);
136         } else {
137                 if ((pp = strchr(mbox, '!'))) {
138                         *pp++ = '\0';
139                         mp->m_mbox = getcpy(pp);
140                         mp->m_host = getcpy(mbox);
141                         mp->m_type = UUCPHOST;
142                 } else {
143                         mp->m_nohost = 1;
144                         mp->m_mbox = getcpy(mbox);
145                         if (route == NULL && dftype == LOCALHOST) {
146                                 mp->m_host = NULL;
147                                 mp->m_type = dftype;
148                         } else {
149                                 mp->m_host = route ? NULL : getcpy(dfhost);
150                                 mp->m_type = route ? NETHOST : dftype;
151                         }
152                 }
153                 goto got_host;
154         }
155
156         if (wanthost == AD_NHST)
157                 mp->m_type = !mh_strcasecmp(LocalName(), mp->m_host)
158                         ? LOCALHOST : NETHOST;
159         else
160                 mp->m_type = mh_strcasecmp(LocalName(), mp->m_host) ?  NETHOST : LOCALHOST;
161
162 got_host: ;
163         if (route)
164                 mp->m_path = getcpy(route);
165         mp->m_ingrp = ingrp;
166         if (grp)
167                 mp->m_gname = getcpy(grp);
168         if (note)
169                 mp->m_note = getcpy(note);
170
171         return mp;
172 }
173
174
175 void
176 mnfree(struct mailname *mp)
177 {
178         if (!mp)
179                 return;
180
181         if (mp->m_text)
182                 free(mp->m_text);
183         if (mp->m_pers)
184                 free(mp->m_pers);
185         if (mp->m_mbox)
186                 free(mp->m_mbox);
187         if (mp->m_host)
188                 free(mp->m_host);
189         if (mp->m_path)
190                 free(mp->m_path);
191         if (mp->m_gname)
192                 free(mp->m_gname);
193         if (mp->m_note)
194                 free(mp->m_note);
195
196         free((char *) mp);
197 }
198
199
200 #define empty(s) ((s) ? (s) : "")
201
202 char *
203 adrformat(struct mailname *mp)
204 {
205         static char addr[BUFSIZ];
206         static char buffer[BUFSIZ];
207
208         if (mp->m_nohost)
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);
213         else
214                 snprintf(addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
215
216         if (mp->m_pers || mp->m_path) {
217                 if (mp->m_note)
218                         snprintf(buffer, sizeof(buffer), "%s %s <%s>",
219                                 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
220                                 mp->m_note, addr);
221                 else
222                         snprintf(buffer, sizeof(buffer), "%s <%s>",
223                                 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
224                                 addr);
225         } else if (mp->m_note)
226                 snprintf(buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
227         else
228                 strncpy(buffer, addr, sizeof(buffer));
229
230         return buffer;
231 }
232
233
234 #define W_NIL   0x0000
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"
242
243 /*
244 ** Check if this is my address
245 */
246
247 int
248 ismymbox(struct mailname *np)
249 {
250         int oops;
251         register int len, i;
252         register char *cp;
253         register char *pp;
254         char buffer[BUFSIZ];
255         struct mailname *mp;
256         static char *am = NULL;
257         static struct mailname mq={NULL};
258
259         /*
260         ** If this is the first call, initialize
261         ** list of alternate mailboxes.
262         */
263         if (am == NULL) {
264                 mq.m_next = NULL;
265                 mq.m_mbox = getusername();
266                 if ((am = context_find("alternate-mailboxes")) == NULL)
267                         am = getusername();
268                 else {
269                         mp = &mq;
270                         oops = 0;
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);
274                                         oops++;
275                                 } else {
276                                         mp = mp->m_next;
277                                         mp->m_type = W_NIL;
278                                         if (*mp->m_mbox == '*') {
279                                                 mp->m_type |= W_MBEG;
280                                                 mp->m_mbox++;
281                                         }
282                                         if (*(cp = mp->m_mbox + strlen(mp->m_mbox) - 1) == '*') {
283                                                 mp->m_type |= W_MEND;
284                                                 *cp = '\0';
285                                         }
286                                         if (mp->m_host) {
287                                                 if (*mp->m_host == '*') {
288                                                         mp->m_type |= W_HBEG;
289                                                         mp->m_host++;
290                                                 }
291                                                 if (*(cp = mp->m_host + strlen(mp->m_host) - 1) == '*') {
292                                                         mp->m_type |= W_HEND;
293                                                         *cp = '\0';
294                                                 }
295                                         }
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));
300                                 }
301                         }
302                         if (oops)
303                                 advise(NULL, "please fix the profile entry %s",
304                                                 "alternate-mailboxes");
305                 }
306         }
307
308         if (np == NULL) /* XXX */
309                 return 0;
310
311         switch (np->m_type) {
312         case NETHOST:
313                 len = strlen(cp = LocalName());
314                 if (!uprf(np->m_host, cp) || np->m_host[len] != '.')
315                         break;
316                 goto local_test;
317
318         case UUCPHOST:
319                 if (mh_strcasecmp(np->m_host, SystemName()))
320                         break;  /* fall */
321         case LOCALHOST:
322 local_test: ;
323                 if (!mh_strcasecmp(np->m_mbox, mq.m_mbox))
324                         return 1;
325                 break;
326
327         default:
328                 break;
329         }
330
331         /*
332         ** Now scan through list of alternate
333         ** mailboxes, and check for a match.
334         */
335         for (mp = &mq; mp->m_next;) {
336                 mp = mp->m_next;
337                 if (!np->m_mbox)
338                         continue;
339                 if ((len = strlen(cp = np->m_mbox))
340                         < (i = strlen(pp = mp->m_mbox)))
341                         continue;
342                 switch (mp->m_type & W_MBOX) {
343                 case W_NIL:
344                         if (mh_strcasecmp(cp, pp))
345                                 continue;
346                         break;
347                 case W_MBEG:
348                         if (mh_strcasecmp(cp + len - i, pp))
349                                 continue;
350                         break;
351                 case W_MEND:
352                         if (!uprf(cp, pp))
353                                 continue;
354                         break;
355                 case W_MBEG | W_MEND:
356                         if (stringdex(pp, cp) < 0)
357                                 continue;
358                         break;
359                 }
360
361                 if (mp->m_nohost)
362                         return 1;
363                 if (np->m_host == NULL)
364                         continue;
365                 if ((len = strlen(cp = np->m_host))
366                         < (i = strlen(pp = mp->m_host)))
367                         continue;
368                 switch (mp->m_type & W_HOST) {
369                 case W_NIL:
370                         if (mh_strcasecmp(cp, pp))
371                                 continue;
372                         break;
373                 case W_HBEG:
374                         if (mh_strcasecmp (cp + len - i, pp))
375                                 continue;
376                         break;
377                 case W_HEND:
378                         if (!uprf(cp, pp))
379                                 continue;
380                         break;
381                 case W_HBEG | W_HEND:
382                         if (stringdex(pp, cp) < 0)
383                                 continue;
384                         break;
385                 }
386                 return 1;
387         }
388
389         return 0;
390 }
391
392
393 /*
394 ** Moved from hosts.c -- find out the official name of a host
395 */
396
397 /*
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.
402 */
403
404 #include <netdb.h>
405
406
407 char *
408 OfficialName(char *name)
409 {
410         unsigned char *p;
411         char *q, site[BUFSIZ];
412         struct addrinfo hints, *res;
413
414         static char buffer[BUFSIZ];
415
416         for (p = name, q = site; *p && (q - site < sizeof(site) - 1); p++, q++)
417                 *q = isupper(*p) ? tolower(*p) : *p;
418         *q = '\0';
419         q = site;
420
421         if (!mh_strcasecmp(LocalName(), site))
422                 return LocalName();
423
424         memset(&hints, 0, sizeof(hints));
425         hints.ai_flags = AI_CANONNAME;
426         hints.ai_family = PF_UNSPEC;
427
428         if (getaddrinfo(q, NULL, &hints, &res) == 0) {
429                 strncpy(buffer, res->ai_canonname, sizeof(buffer));
430                 buffer[sizeof(buffer) - 1] = '\0';
431                 freeaddrinfo(res);
432                 return buffer;
433         }
434
435         strncpy(buffer, site, sizeof(buffer));
436         return buffer;
437 }