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