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