Removed support for UUCP bang path addresses.
[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 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         struct mailname *mp;
77
78         if (err[0]) {
79                 if (eresult)
80                         strcpy(eresult, err);
81                 else
82                         if (wanthost == AD_HOST)
83                                 admonish(NULL, "bad address '%s' - %s", str, err);
84                 return NULL;
85         }
86         if (pers == NULL && mbox == NULL && host == NULL && route == NULL
87                 && grp == NULL) {
88                 if (eresult)
89                         strcpy(eresult, "null address");
90                 else
91                         if (wanthost == AD_HOST)
92                                 admonish(NULL, "null address '%s'", str);
93                 return NULL;
94         }
95         if (mbox == NULL && grp == NULL) {
96                 if (eresult)
97                         strcpy(eresult, "no mailbox in address");
98                 else if (wanthost == AD_HOST)
99                         admonish(NULL, "no mailbox in address '%s'", str);
100                 return NULL;
101         }
102
103         if (dfhost == NULL) {
104                 dfhost = LocalName();
105                 dftype = LOCALHOST;
106         }
107
108         mp = (struct mailname *) calloc((size_t) 1, sizeof(*mp));
109         if (mp == NULL) {
110                 if (eresult)
111                         strcpy(eresult, "insufficient memory to represent address");
112                 else if (wanthost == AD_HOST)
113                         adios(NULL, "insufficient memory to represent address");
114                 return NULL;
115         }
116
117         mp->m_next = NULL;
118         mp->m_text = getcpy(str);
119         if (pers)
120                 mp->m_pers = getcpy(pers);
121
122         if (mbox == NULL) {
123                 mp->m_type = BADHOST;
124                 mp->m_nohost = 1;
125                 mp->m_ingrp = ingrp;
126                 mp->m_gname = getcpy(grp);
127                 if (note)
128                         mp->m_note = getcpy(note);
129                 return mp;
130         }
131
132         if (host) {
133                 mp->m_mbox = getcpy(mbox);
134                 mp->m_host = getcpy(host);
135         } else {
136                 mp->m_nohost = 1;
137                 mp->m_mbox = getcpy(mbox);
138                 if (route == NULL && dftype == LOCALHOST) {
139                         mp->m_host = NULL;
140                         mp->m_type = dftype;
141                 } else {
142                         mp->m_host = route ? NULL : getcpy(dfhost);
143                         mp->m_type = route ? NETHOST : dftype;
144                 }
145                 goto got_host;
146         }
147
148         if (wanthost == AD_NHST)
149                 mp->m_type = !mh_strcasecmp(LocalName(), mp->m_host)
150                         ? LOCALHOST : NETHOST;
151         else
152                 mp->m_type = mh_strcasecmp(LocalName(), mp->m_host) ?  NETHOST : LOCALHOST;
153
154 got_host: ;
155         if (route)
156                 mp->m_path = getcpy(route);
157         mp->m_ingrp = ingrp;
158         if (grp)
159                 mp->m_gname = getcpy(grp);
160         if (note)
161                 mp->m_note = getcpy(note);
162
163         return mp;
164 }
165
166
167 void
168 mnfree(struct mailname *mp)
169 {
170         if (!mp)
171                 return;
172
173         if (mp->m_text)
174                 free(mp->m_text);
175         if (mp->m_pers)
176                 free(mp->m_pers);
177         if (mp->m_mbox)
178                 free(mp->m_mbox);
179         if (mp->m_host)
180                 free(mp->m_host);
181         if (mp->m_path)
182                 free(mp->m_path);
183         if (mp->m_gname)
184                 free(mp->m_gname);
185         if (mp->m_note)
186                 free(mp->m_note);
187
188         free((char *) mp);
189 }
190
191
192 #define empty(s) ((s) ? (s) : "")
193
194 char *
195 adrformat(struct mailname *mp)
196 {
197         static char addr[BUFSIZ];
198         static char buffer[BUFSIZ];
199
200         if (mp->m_nohost)
201                 strncpy(addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
202         else
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);
205
206         if (mp->m_pers || mp->m_path) {
207                 if (mp->m_note)
208                         snprintf(buffer, sizeof(buffer), "%s %s <%s>",
209                                 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
210                                 mp->m_note, addr);
211                 else
212                         snprintf(buffer, sizeof(buffer), "%s <%s>",
213                                 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
214                                 addr);
215         } else if (mp->m_note)
216                 snprintf(buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
217         else
218                 strncpy(buffer, addr, sizeof(buffer));
219
220         return buffer;
221 }
222
223
224 #define W_NIL   0x0000
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"
232
233 /*
234 ** Check if this is my address
235 */
236
237 int
238 ismymbox(struct mailname *np)
239 {
240         int oops;
241         register int len, i;
242         register char *cp;
243         register char *pp;
244         char buffer[BUFSIZ];
245         struct mailname *mp;
246         static char *am = NULL;
247         static struct mailname mq={NULL};
248
249         /*
250         ** If this is the first call, initialize
251         ** list of alternate mailboxes.
252         */
253         if (am == NULL) {
254                 mq.m_next = NULL;
255                 mq.m_mbox = getusername();
256                 if ((am = context_find("alternate-mailboxes")) == NULL)
257                         am = getusername();
258                 else {
259                         mp = &mq;
260                         oops = 0;
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);
264                                         oops++;
265                                 } else {
266                                         mp = mp->m_next;
267                                         mp->m_type = W_NIL;
268                                         if (*mp->m_mbox == '*') {
269                                                 mp->m_type |= W_MBEG;
270                                                 mp->m_mbox++;
271                                         }
272                                         if (*(cp = mp->m_mbox + strlen(mp->m_mbox) - 1) == '*') {
273                                                 mp->m_type |= W_MEND;
274                                                 *cp = '\0';
275                                         }
276                                         if (mp->m_host) {
277                                                 if (*mp->m_host == '*') {
278                                                         mp->m_type |= W_HBEG;
279                                                         mp->m_host++;
280                                                 }
281                                                 if (*(cp = mp->m_host + strlen(mp->m_host) - 1) == '*') {
282                                                         mp->m_type |= W_HEND;
283                                                         *cp = '\0';
284                                                 }
285                                         }
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));
290                                 }
291                         }
292                         if (oops)
293                                 advise(NULL, "please fix the profile entry %s",
294                                                 "alternate-mailboxes");
295                 }
296         }
297
298         if (np == NULL) /* XXX */
299                 return 0;
300
301         switch (np->m_type) {
302         case NETHOST:
303                 len = strlen(cp = LocalName());
304                 if (!uprf(np->m_host, cp) || np->m_host[len] != '.')
305                         break;
306                 goto local_test;
307
308         case LOCALHOST:
309 local_test: ;
310                 if (!mh_strcasecmp(np->m_mbox, mq.m_mbox))
311                         return 1;
312                 break;
313
314         default:
315                 break;
316         }
317
318         /*
319         ** Now scan through list of alternate
320         ** mailboxes, and check for a match.
321         */
322         for (mp = &mq; mp->m_next;) {
323                 mp = mp->m_next;
324                 if (!np->m_mbox)
325                         continue;
326                 if ((len = strlen(cp = np->m_mbox))
327                         < (i = strlen(pp = mp->m_mbox)))
328                         continue;
329                 switch (mp->m_type & W_MBOX) {
330                 case W_NIL:
331                         if (mh_strcasecmp(cp, pp))
332                                 continue;
333                         break;
334                 case W_MBEG:
335                         if (mh_strcasecmp(cp + len - i, pp))
336                                 continue;
337                         break;
338                 case W_MEND:
339                         if (!uprf(cp, pp))
340                                 continue;
341                         break;
342                 case W_MBEG | W_MEND:
343                         if (stringdex(pp, cp) < 0)
344                                 continue;
345                         break;
346                 }
347
348                 if (mp->m_nohost)
349                         return 1;
350                 if (np->m_host == NULL)
351                         continue;
352                 if ((len = strlen(cp = np->m_host))
353                         < (i = strlen(pp = mp->m_host)))
354                         continue;
355                 switch (mp->m_type & W_HOST) {
356                 case W_NIL:
357                         if (mh_strcasecmp(cp, pp))
358                                 continue;
359                         break;
360                 case W_HBEG:
361                         if (mh_strcasecmp (cp + len - i, pp))
362                                 continue;
363                         break;
364                 case W_HEND:
365                         if (!uprf(cp, pp))
366                                 continue;
367                         break;
368                 case W_HBEG | W_HEND:
369                         if (stringdex(pp, cp) < 0)
370                                 continue;
371                         break;
372                 }
373                 return 1;
374         }
375
376         return 0;
377 }
378
379
380 /*
381 ** Moved from hosts.c -- find out the official name of a host
382 */
383
384 /*
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.
389 */
390
391 #include <netdb.h>
392
393
394 char *
395 OfficialName(char *name)
396 {
397         unsigned char *p;
398         char *q, site[BUFSIZ];
399         struct addrinfo hints, *res;
400
401         static char buffer[BUFSIZ];
402
403         for (p = name, q = site; *p && (q - site < sizeof(site) - 1); p++, q++)
404                 *q = isupper(*p) ? tolower(*p) : *p;
405         *q = '\0';
406         q = site;
407
408         if (!mh_strcasecmp(LocalName(), site))
409                 return LocalName();
410
411         memset(&hints, 0, sizeof(hints));
412         hints.ai_flags = AI_CANONNAME;
413         hints.ai_family = PF_UNSPEC;
414
415         if (getaddrinfo(q, NULL, &hints, &res) == 0) {
416                 strncpy(buffer, res->ai_canonname, sizeof(buffer));
417                 buffer[sizeof(buffer) - 1] = '\0';
418                 freeaddrinfo(res);
419                 return buffer;
420         }
421
422         strncpy(buffer, site, sizeof(buffer));
423         return buffer;
424 }