Removed now unused OfficialName(). (Had been for UUCP, AFAIK.)
[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
44 char *
45 getname(char *addrs)
46 {
47         struct adrx *ap;
48
49         pers = mbox = host = route = grp = note = NULL;
50         err[0] = '\0';
51
52         if ((ap = getadrx(addrs ? addrs : "")) == NULL)
53                 return NULL;
54
55         strncpy(adr, ap->text, sizeof(adr));
56         pers = ap->pers;
57         mbox = ap->mbox;
58         host = ap->host;
59         route = ap->path;
60         grp = ap->grp;
61         ingrp = ap->ingrp;
62         note = ap->note;
63         if (ap->err && *ap->err)
64                 strncpy(err, ap->err, sizeof(err));
65
66         return adr;
67 }
68
69
70 struct mailname *
71 getm(char *str, char *dfhost, int dftype, int wanthost, char *eresult)
72 {
73         struct mailname *mp;
74
75         if (err[0]) {
76                 if (eresult)
77                         strcpy(eresult, err);
78                 else
79                         if (wanthost == AD_HOST)
80                                 admonish(NULL, "bad address '%s' - %s", str, err);
81                 return NULL;
82         }
83         if (pers == NULL && mbox == NULL && host == NULL && route == NULL
84                 && grp == NULL) {
85                 if (eresult)
86                         strcpy(eresult, "null address");
87                 else
88                         if (wanthost == AD_HOST)
89                                 admonish(NULL, "null address '%s'", str);
90                 return NULL;
91         }
92         if (mbox == NULL && grp == NULL) {
93                 if (eresult)
94                         strcpy(eresult, "no mailbox in address");
95                 else if (wanthost == AD_HOST)
96                         admonish(NULL, "no mailbox in address '%s'", str);
97                 return NULL;
98         }
99
100         if (dfhost == NULL) {
101                 dfhost = LocalName();
102                 dftype = LOCALHOST;
103         }
104
105         mp = (struct mailname *) calloc((size_t) 1, sizeof(*mp));
106         if (mp == NULL) {
107                 if (eresult)
108                         strcpy(eresult, "insufficient memory to represent address");
109                 else if (wanthost == AD_HOST)
110                         adios(NULL, "insufficient memory to represent address");
111                 return NULL;
112         }
113
114         mp->m_next = NULL;
115         mp->m_text = getcpy(str);
116         if (pers)
117                 mp->m_pers = getcpy(pers);
118
119         if (mbox == NULL) {
120                 mp->m_type = BADHOST;
121                 mp->m_nohost = 1;
122                 mp->m_ingrp = ingrp;
123                 mp->m_gname = getcpy(grp);
124                 if (note)
125                         mp->m_note = getcpy(note);
126                 return mp;
127         }
128
129         if (host) {
130                 mp->m_mbox = getcpy(mbox);
131                 mp->m_host = getcpy(host);
132         } else {
133                 mp->m_nohost = 1;
134                 mp->m_mbox = getcpy(mbox);
135                 if (route == NULL && dftype == LOCALHOST) {
136                         mp->m_host = NULL;
137                         mp->m_type = dftype;
138                 } else {
139                         mp->m_host = route ? NULL : getcpy(dfhost);
140                         mp->m_type = route ? NETHOST : dftype;
141                 }
142                 goto got_host;
143         }
144
145         if (wanthost == AD_NHST)
146                 mp->m_type = !mh_strcasecmp(LocalName(), mp->m_host)
147                         ? LOCALHOST : NETHOST;
148         else
149                 mp->m_type = mh_strcasecmp(LocalName(), mp->m_host) ?  NETHOST : LOCALHOST;
150
151 got_host: ;
152         if (route)
153                 mp->m_path = getcpy(route);
154         mp->m_ingrp = ingrp;
155         if (grp)
156                 mp->m_gname = getcpy(grp);
157         if (note)
158                 mp->m_note = getcpy(note);
159
160         return mp;
161 }
162
163
164 void
165 mnfree(struct mailname *mp)
166 {
167         if (!mp)
168                 return;
169
170         if (mp->m_text)
171                 free(mp->m_text);
172         if (mp->m_pers)
173                 free(mp->m_pers);
174         if (mp->m_mbox)
175                 free(mp->m_mbox);
176         if (mp->m_host)
177                 free(mp->m_host);
178         if (mp->m_path)
179                 free(mp->m_path);
180         if (mp->m_gname)
181                 free(mp->m_gname);
182         if (mp->m_note)
183                 free(mp->m_note);
184
185         free((char *) mp);
186 }
187
188
189 #define empty(s) ((s) ? (s) : "")
190
191 char *
192 adrformat(struct mailname *mp)
193 {
194         static char addr[BUFSIZ];
195         static char buffer[BUFSIZ];
196
197         if (mp->m_nohost)
198                 strncpy(addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
199         else
200                 snprintf(addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
201                         empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
202
203         if (mp->m_pers || mp->m_path) {
204                 if (mp->m_note)
205                         snprintf(buffer, sizeof(buffer), "%s %s <%s>",
206                                 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
207                                 mp->m_note, addr);
208                 else
209                         snprintf(buffer, sizeof(buffer), "%s <%s>",
210                                 legal_person(mp->m_pers ? mp->m_pers : mp->m_mbox),
211                                 addr);
212         } else if (mp->m_note)
213                 snprintf(buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
214         else
215                 strncpy(buffer, addr, sizeof(buffer));
216
217         return buffer;
218 }
219
220
221 #define W_NIL   0x0000
222 #define W_MBEG  0x0001
223 #define W_MEND  0x0002
224 #define W_MBOX  (W_MBEG | W_MEND)
225 #define W_HBEG  0x0004
226 #define W_HEND  0x0008
227 #define W_HOST  (W_HBEG | W_HEND)
228 #define WBITS   "\020\01MBEG\02MEND\03HBEG\04HEND"
229
230 /*
231 ** Check if this is my address
232 */
233
234 int
235 ismymbox(struct mailname *np)
236 {
237         int oops;
238         register int len, i;
239         register char *cp;
240         register char *pp;
241         char buffer[BUFSIZ];
242         struct mailname *mp;
243         static char *am = NULL;
244         static struct mailname mq={NULL};
245
246         /*
247         ** If this is the first call, initialize
248         ** list of alternate mailboxes.
249         */
250         if (am == NULL) {
251                 mq.m_next = NULL;
252                 mq.m_mbox = getusername();
253                 if ((am = context_find("alternate-mailboxes")) == NULL)
254                         am = getusername();
255                 else {
256                         mp = &mq;
257                         oops = 0;
258                         while ((cp = getname(am))) {
259                                 if ((mp->m_next = getm(cp, NULL, 0, AD_NAME, NULL)) == NULL) {
260                                         admonish(NULL, "illegal address: %s", cp);
261                                         oops++;
262                                 } else {
263                                         mp = mp->m_next;
264                                         mp->m_type = W_NIL;
265                                         if (*mp->m_mbox == '*') {
266                                                 mp->m_type |= W_MBEG;
267                                                 mp->m_mbox++;
268                                         }
269                                         if (*(cp = mp->m_mbox + strlen(mp->m_mbox) - 1) == '*') {
270                                                 mp->m_type |= W_MEND;
271                                                 *cp = '\0';
272                                         }
273                                         if (mp->m_host) {
274                                                 if (*mp->m_host == '*') {
275                                                         mp->m_type |= W_HBEG;
276                                                         mp->m_host++;
277                                                 }
278                                                 if (*(cp = mp->m_host + strlen(mp->m_host) - 1) == '*') {
279                                                         mp->m_type |= W_HEND;
280                                                         *cp = '\0';
281                                                 }
282                                         }
283                                         if ((cp = getenv("MHWDEBUG")) && *cp)
284                                                 fprintf(stderr, "mbox=\"%s\" host=\"%s\" %s\n",
285                                                         mp->m_mbox, mp->m_host,
286                                                         snprintb(buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
287                                 }
288                         }
289                         if (oops)
290                                 advise(NULL, "please fix the profile entry %s",
291                                                 "alternate-mailboxes");
292                 }
293         }
294
295         if (np == NULL) /* XXX */
296                 return 0;
297
298         switch (np->m_type) {
299         case NETHOST:
300                 len = strlen(cp = LocalName());
301                 if (!uprf(np->m_host, cp) || np->m_host[len] != '.')
302                         break;
303                 goto local_test;
304
305         case LOCALHOST:
306 local_test: ;
307                 if (!mh_strcasecmp(np->m_mbox, mq.m_mbox))
308                         return 1;
309                 break;
310
311         default:
312                 break;
313         }
314
315         /*
316         ** Now scan through list of alternate
317         ** mailboxes, and check for a match.
318         */
319         for (mp = &mq; mp->m_next;) {
320                 mp = mp->m_next;
321                 if (!np->m_mbox)
322                         continue;
323                 if ((len = strlen(cp = np->m_mbox))
324                         < (i = strlen(pp = mp->m_mbox)))
325                         continue;
326                 switch (mp->m_type & W_MBOX) {
327                 case W_NIL:
328                         if (mh_strcasecmp(cp, pp))
329                                 continue;
330                         break;
331                 case W_MBEG:
332                         if (mh_strcasecmp(cp + len - i, pp))
333                                 continue;
334                         break;
335                 case W_MEND:
336                         if (!uprf(cp, pp))
337                                 continue;
338                         break;
339                 case W_MBEG | W_MEND:
340                         if (stringdex(pp, cp) < 0)
341                                 continue;
342                         break;
343                 }
344
345                 if (mp->m_nohost)
346                         return 1;
347                 if (np->m_host == NULL)
348                         continue;
349                 if ((len = strlen(cp = np->m_host))
350                         < (i = strlen(pp = mp->m_host)))
351                         continue;
352                 switch (mp->m_type & W_HOST) {
353                 case W_NIL:
354                         if (mh_strcasecmp(cp, pp))
355                                 continue;
356                         break;
357                 case W_HBEG:
358                         if (mh_strcasecmp (cp + len - i, pp))
359                                 continue;
360                         break;
361                 case W_HEND:
362                         if (!uprf(cp, pp))
363                                 continue;
364                         break;
365                 case W_HBEG | W_HEND:
366                         if (stringdex(pp, cp) < 0)
367                                 continue;
368                         break;
369                 }
370                 return 1;
371         }
372
373         return 0;
374 }