Fixed ismymbox() to look at Local-Mailbox as well as
[mmh] / sbr / addrsbr.c
1
2 /*
3  * addrsbr.c -- parse addresses 822-style
4  *
5  * This code is Copyright (c) 2002, by the authors of nmh.  See the
6  * COPYRIGHT file in the root directory of the nmh distribution for
7  * complete copyright information.
8  */
9
10 #include <h/mh.h>
11 #include <h/addrsbr.h>
12 #include <h/mf.h>
13 #include <h/mts.h>
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    The comments below are left in for historical purposes; DUMB and
22    REALLYDUMB are now the default in the code.
23
24    If #ifdef DUMB is in effect, a full 822-style parser is called
25    for syntax recongition.  This breaks each address into its components.
26    Note however that no semantics are assumed about the parts or their
27    totality.  This means that implicit hostnames aren't made explicit,
28    and explicit hostnames aren't expanded to their "official" represenations.
29
30    If DUMB is not in effect, then this module does some
31    high-level thinking about what the addresses are.
32
33    1. for MMDF systems:
34
35         string%<uucp>@<local>   ->      string
36
37    2. for non-MMDF systems:
38
39         string@host.<uucp>      ->      host!string
40
41    3. for any system, an address interpreted relative to the local host:
42
43         string@<uucp>           ->      string
44
45    For cases (1) and (3) above, the leftmost host is extracted.  If it's not
46    present, the local host is used.  If the tests above fail, the address is
47    considered to be a real 822-style address.
48
49    If an explicit host is not present, then MH checks for a bang to indicate
50    an explicit UUCP-style address.  If so, this is noted.  If not, the host is
51    defaulted, typically to the local host.  The lack of an explict host is
52    also noted.
53
54    If an explicit 822-style host is present, then MH checks to see if it
55    can expand this to the official name for the host.  If the hostname is
56    unknown, the address is so typed.
57
58    To summarize, when we're all done, here's what MH knows about the address:
59
60    DUMB -       type:   local, uucp, or network
61                 host:   not locally defaulted, not explicitly expanded
62                 everything else
63
64    other -      type:   local, uucp, network, unknown
65                 everything else
66  */
67
68
69 static int  ingrp = 0;
70 static char *pers = NULL;
71 static char *mbox = NULL;
72 static char *host = NULL;
73 static char *route = NULL;
74 static char *grp = NULL;
75 static char *note = NULL;
76 static char err[BUFSIZ];
77 static char adr[BUFSIZ];
78
79
80 char *
81 getname (char *addrs)
82 {
83     struct adrx *ap;
84
85     pers = mbox = host = route = grp = note = NULL;
86     err[0] = '\0';
87
88     if ((ap = getadrx (addrs ? addrs : "")) == NULL)
89         return NULL;
90
91     strncpy (adr, ap->text, sizeof(adr));
92     pers = ap->pers;
93     mbox = ap->mbox;
94     host = ap->host;
95     route = ap->path;
96     grp = ap->grp;
97     ingrp = ap->ingrp;
98     note = ap->note;
99     if (ap->err && *ap->err)
100         strncpy (err, ap->err, sizeof(err));
101
102     return adr;
103 }
104
105
106 struct mailname *
107 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
108 {
109     char *pp;
110     struct mailname *mp;
111
112     if (err[0]) {
113         if (eresult)
114             strcpy (eresult, err);
115         else
116             if (wanthost == AD_HOST)
117                 admonish (NULL, "bad address '%s' - %s", str, err);
118         return NULL;
119     }
120     if (pers == NULL
121             && mbox == NULL && host == NULL && route == NULL
122             && grp == NULL) {
123         if (eresult)
124             strcpy (eresult, "null address");
125         else
126             if (wanthost == AD_HOST)
127                 admonish (NULL, "null address '%s'", str);
128         return NULL;
129     }
130     if (mbox == NULL && grp == NULL) {
131         if (eresult)
132             strcpy (eresult, "no mailbox in address");
133         else
134             if (wanthost == AD_HOST)
135                 admonish (NULL, "no mailbox in address '%s'", str);
136         return NULL;
137     }
138
139     if (dfhost == NULL) {
140         dfhost = LocalName (0);
141         dftype = LOCALHOST;
142     }
143
144     mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp));
145     if (mp == NULL) {
146         if (eresult)
147            strcpy (eresult, "insufficient memory to represent address");
148         else
149             if (wanthost == AD_HOST)
150                 adios (NULL, "insufficient memory to represent address");
151         return NULL;
152     }
153
154     mp->m_next = NULL;
155     mp->m_text = getcpy (str);
156     if (pers)
157         mp->m_pers = getcpy (pers);
158
159     if (mbox == NULL) {
160         mp->m_type = BADHOST;
161         mp->m_nohost = 1;
162         mp->m_ingrp = ingrp;
163         mp->m_gname = getcpy (grp);
164         if (note)
165             mp->m_note = getcpy (note);
166         return mp;
167     }
168
169     if (host) {
170         mp->m_mbox = getcpy (mbox);
171         mp->m_host = getcpy (host);
172     }
173     else {
174         if ((pp = strchr(mbox, '!'))) {
175             *pp++ = '\0';
176             mp->m_mbox = getcpy (pp);
177             mp->m_host = getcpy (mbox);
178             mp->m_type = UUCPHOST;
179         }
180         else {
181             mp->m_nohost = 1;
182             mp->m_mbox = getcpy (mbox);
183             if (route == NULL && dftype == LOCALHOST) {
184                 mp->m_host = NULL;
185                 mp->m_type = dftype;
186             }
187             else
188             {
189                 mp->m_host = route ? NULL : getcpy (dfhost);
190                 mp->m_type = route ? NETHOST : dftype;
191             }
192         }
193         goto got_host;
194     }
195
196     /* For alternate mailboxes, m_type gets overwritten in ismymbox ()
197        to support wild-card matching. */
198     if (wanthost == AD_NHST)
199         mp->m_type = !mh_strcasecmp (LocalName (0), mp->m_host)
200             ? LOCALHOST : NETHOST;
201     else
202         mp->m_type = mh_strcasecmp (LocalName(0), mp->m_host) ?  NETHOST : LOCALHOST;
203
204 got_host: ;
205     if (route)
206         mp->m_path = getcpy (route);
207     mp->m_ingrp = ingrp;
208     if (grp)
209         mp->m_gname = getcpy (grp);
210     if (note)
211         mp->m_note = getcpy (note);
212
213     return mp;
214 }
215
216
217 void
218 mnfree (struct mailname *mp)
219 {
220     if (!mp)
221         return;
222
223     if (mp->m_text)
224         free (mp->m_text);
225     if (mp->m_pers)
226         free (mp->m_pers);
227     if (mp->m_mbox)
228         free (mp->m_mbox);
229     if (mp->m_host)
230         free (mp->m_host);
231     if (mp->m_path)
232         free (mp->m_path);
233     if (mp->m_gname)
234         free (mp->m_gname);
235     if (mp->m_note)
236         free (mp->m_note);
237
238     free ((char *) mp);
239 }
240
241
242 #define empty(s) ((s) ? (s) : "")
243
244 char *
245 auxformat (struct mailname *mp, int extras)
246 {
247     static char addr[BUFSIZ];
248     static char buffer[BUFSIZ];
249
250         if (mp->m_nohost)
251             strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
252         else
253
254         if (mp->m_type != UUCPHOST)
255             snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
256                 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
257         else
258             snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
259
260     if (!extras)
261         return addr;
262
263     if (mp->m_pers || mp->m_path) {
264         if (mp->m_note)
265             snprintf (buffer, sizeof(buffer), "%s %s <%s>",
266                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
267                     mp->m_note, addr);
268         else
269             snprintf (buffer, sizeof(buffer), "%s <%s>",
270                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
271                     addr);
272     }
273     else
274         if (mp->m_note)
275             snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
276         else
277             strncpy (buffer, addr, sizeof(buffer));
278
279     return buffer;
280 }
281
282
283 /*
284  * This used to be adrsprintf() (where it would format an address for you
285  * given a username and a domain).  But somewhere we got to the point where
286  * the only caller was post, and it only called it with both arguments NULL.
287  * So the function was renamed with a more sensible name.
288  */
289
290 char *
291 getlocaladdr(void)
292 {
293     char         *username;
294
295     username = getusername();
296
297     return username;
298 }
299
300
301 #define W_NIL   0x0000
302 #define W_MBEG  0x0001
303 #define W_MEND  0x0002
304 #define W_MBOX  (W_MBEG | W_MEND)
305 #define W_HBEG  0x0004
306 #define W_HEND  0x0008
307 #define W_HOST  (W_HBEG | W_HEND)
308 #define WBITS   "\020\01MBEG\02MEND\03HBEG\04HEND"
309
310 /*
311  * Check if this is my address
312  */
313
314 int
315 ismymbox (struct mailname *np)
316 {
317     int oops;
318     register int len, i;
319     register char *cp;
320     register char *pp;
321     char buffer[BUFSIZ];
322     struct mailname *mp;
323     static char *am = NULL;
324     static struct mailname mq;
325     static int localmailbox = 0;
326
327     /*
328      * If this is the first call, initialize
329      * list of alternate mailboxes.
330      */
331     if (am == NULL) {
332         mq.m_next = NULL;
333         mq.m_mbox = getusername ();
334
335         if ((am = context_find ("local-mailbox"))) {
336
337             localmailbox++;
338
339             if ((cp = getname(am)) == NULL) {
340                 admonish (NULL, "Unable to find address in local-mailbox");
341                 return 0;
342             }
343
344             if ((mq.m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
345                 admonish (NULL, "invalid entry in local-mailbox: %s", cp);
346                 return 0;
347             }
348
349             /*
350              * Sigh, it turns out that the address parser gets messed up
351              * if you don't call getname() until it returns NULL.
352              */
353
354             while ((cp = getname(am)) != NULL)
355                 ;
356         }
357
358         if ((am = context_find ("alternate-mailboxes")) == NULL)
359             am = getusername();
360         else {
361             mp = mq.m_next ? mq.m_next : &mq;
362             oops = 0;
363             while ((cp = getname (am))) {
364                 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
365                     admonish (NULL, "illegal address: %s", cp);
366                     oops++;
367                 } else {
368                     mp = mp->m_next;
369                     mp->m_type = W_NIL;
370                     if (*mp->m_mbox == '*') {
371                         mp->m_type |= W_MBEG;
372                         mp->m_mbox++;
373                     }
374                     if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
375                         mp->m_type |= W_MEND;
376                         *cp = '\0';
377                     }
378                     if (mp->m_host) {
379                         if (*mp->m_host == '*') {
380                             mp->m_type |= W_HBEG;
381                             mp->m_host++;
382                         }
383                         if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
384                             mp->m_type |= W_HEND;
385                             *cp = '\0';
386                         }
387                     }
388                 }
389             }
390             if (oops)
391                 advise (NULL, "please fix the %s: entry in your %s file",
392                         "alternate-mailboxes", mh_profile);
393         }
394
395         if ((cp = getenv ("MHWDEBUG")) && *cp) {
396             for (mp = &mq; mp; mp = mp->m_next) {
397               fprintf (stderr, "Local- or Alternate-Mailbox: text=\"%s\" "
398                        "mbox=\"%s\" host=\"%s\" %s\n",
399                        mp->m_text ? mp->m_text : "", mp->m_mbox,
400                        mp->m_host ? mp->m_host : "",
401                        snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type,
402                                  WBITS));
403             }
404         }
405     }
406
407     if (np == NULL) /* XXX */
408         return 0;
409     
410     /*
411      * Don't perform this "local" test if we have a Local-Mailbox set
412      */
413
414     if (! localmailbox)
415         switch (np->m_type) {
416             case NETHOST:
417                 len = strlen (cp = LocalName (0));
418                 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
419                     break;
420                 goto local_test;
421
422             case UUCPHOST:
423                 if (mh_strcasecmp (np->m_host, SystemName()))
424                     break;              /* fall */
425             case LOCALHOST:
426 local_test: ;
427                 if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
428                     return 1;
429                 break;
430
431             default:
432                 break;
433         }
434
435     /*
436      * Now scan through list of alternate
437      * mailboxes, and check for a match.
438      */
439     for (mp = &mq; mp->m_next;) {
440         mp = mp->m_next;
441         if (!np->m_mbox)
442             continue; if ((len = strlen (cp = np->m_mbox))
443                 < (i = strlen (pp = mp->m_mbox)))
444             continue;
445         switch (mp->m_type & W_MBOX) {
446             case W_NIL: 
447                 if (mh_strcasecmp (cp, pp))
448                     continue;
449                 break;
450             case W_MBEG: 
451                 if (mh_strcasecmp (cp + len - i, pp))
452                     continue;
453                 break;
454             case W_MEND: 
455                 if (!uprf (cp, pp))
456                     continue;
457                 break;
458             case W_MBEG | W_MEND: 
459                 if (stringdex (pp, cp) < 0)
460                     continue;
461                 break;
462         }
463
464         if (mp->m_nohost)
465             return 1;
466         if (np->m_host == NULL)
467             continue;
468         if ((len = strlen (cp = np->m_host))
469                 < (i = strlen (pp = mp->m_host)))
470             continue;
471         switch (mp->m_type & W_HOST) {
472             case W_NIL: 
473                 if (mh_strcasecmp (cp, pp))
474                     continue;
475                 break;
476             case W_HBEG: 
477                 if (mh_strcasecmp (cp + len - i, pp))
478                     continue;
479                 break;
480             case W_HEND: 
481                 if (!uprf (cp, pp))
482                     continue;
483                 break;
484             case W_HBEG | W_HEND: 
485                 if (stringdex (pp, cp) < 0)
486                     continue;
487                 break;
488         }
489         return 1;
490     }
491
492     return 0;
493 }