Fixed some more problems caught by gcc -ansi -pedantic.
[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     if (wanthost == AD_NHST)
197         mp->m_type = !mh_strcasecmp (LocalName (0), mp->m_host)
198             ? LOCALHOST : NETHOST;
199     else
200         mp->m_type = mh_strcasecmp (LocalName(0), mp->m_host) ?  NETHOST : LOCALHOST;
201
202 got_host: ;
203     if (route)
204         mp->m_path = getcpy (route);
205     mp->m_ingrp = ingrp;
206     if (grp)
207         mp->m_gname = getcpy (grp);
208     if (note)
209         mp->m_note = getcpy (note);
210
211     return mp;
212 }
213
214
215 void
216 mnfree (struct mailname *mp)
217 {
218     if (!mp)
219         return;
220
221     if (mp->m_text)
222         free (mp->m_text);
223     if (mp->m_pers)
224         free (mp->m_pers);
225     if (mp->m_mbox)
226         free (mp->m_mbox);
227     if (mp->m_host)
228         free (mp->m_host);
229     if (mp->m_path)
230         free (mp->m_path);
231     if (mp->m_gname)
232         free (mp->m_gname);
233     if (mp->m_note)
234         free (mp->m_note);
235
236     free ((char *) mp);
237 }
238
239
240 #define empty(s) ((s) ? (s) : "")
241
242 char *
243 auxformat (struct mailname *mp, int extras)
244 {
245     static char addr[BUFSIZ];
246     static char buffer[BUFSIZ];
247
248         if (mp->m_nohost)
249             strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
250         else
251
252         if (mp->m_type != UUCPHOST)
253             snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
254                 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
255         else
256             snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
257
258     if (!extras)
259         return addr;
260
261     if (mp->m_pers || mp->m_path) {
262         if (mp->m_note)
263             snprintf (buffer, sizeof(buffer), "%s %s <%s>",
264                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
265                     mp->m_note, addr);
266         else
267             snprintf (buffer, sizeof(buffer), "%s <%s>",
268                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
269                     addr);
270     }
271     else
272         if (mp->m_note)
273             snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
274         else
275             strncpy (buffer, addr, sizeof(buffer));
276
277     return buffer;
278 }
279
280
281 /*
282  * This used to be adrsprintf() (where it would format an address for you
283  * given a username and a domain).  But somewhere we got to the point where
284  * the only caller was post, and it only called it with both arguments NULL.
285  * So the function was renamed with a more sensible name.
286  */
287
288 char *
289 getlocaladdr(void)
290 {
291     char         *username;
292
293     username = getusername();
294
295     return username;
296 }
297
298
299 #define W_NIL   0x0000
300 #define W_MBEG  0x0001
301 #define W_MEND  0x0002
302 #define W_MBOX  (W_MBEG | W_MEND)
303 #define W_HBEG  0x0004
304 #define W_HEND  0x0008
305 #define W_HOST  (W_HBEG | W_HEND)
306 #define WBITS   "\020\01MBEG\02MEND\03HBEG\04HEND"
307
308 /*
309  * Check if this is my address
310  */
311
312 int
313 ismymbox (struct mailname *np)
314 {
315     int oops;
316     register int len, i;
317     register char *cp;
318     register char *pp;
319     char buffer[BUFSIZ];
320     struct mailname *mp;
321     static char *am = NULL;
322     static struct mailname mq;
323     static int localmailbox = 0;
324
325     /*
326      * If this is the first call, initialize
327      * list of alternate mailboxes.
328      */
329     if (am == NULL) {
330         mq.m_next = NULL;
331         mq.m_mbox = getusername ();
332
333         if ((am = context_find ("local-mailbox"))) {
334
335             localmailbox++;
336
337             if ((cp = getname(am)) == NULL) {
338                 admonish (NULL, "Unable to find address in local-mailbox");
339                 return 0;
340             }
341
342             if ((mq.m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
343                 admonish (NULL, "invalid entry in local-mailbox: %s", cp);
344                 return 0;
345             }
346
347             /*
348              * Sigh, it turns out that the address parser gets messed up
349              * if you don't call getname() until it returns NULL.
350              */
351
352             while ((cp = getname(am)) != NULL)
353                 ;
354         }
355
356         if ((am = context_find ("alternate-mailboxes")) == NULL)
357             am = getusername();
358         else {
359             mp = &mq;
360             oops = 0;
361             while ((cp = getname (am))) {
362                 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
363                     admonish (NULL, "illegal address: %s", cp);
364                     oops++;
365                 } else {
366                     mp = mp->m_next;
367                     mp->m_type = W_NIL;
368                     if (*mp->m_mbox == '*') {
369                         mp->m_type |= W_MBEG;
370                         mp->m_mbox++;
371                     }
372                     if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
373                         mp->m_type |= W_MEND;
374                         *cp = '\0';
375                     }
376                     if (mp->m_host) {
377                         if (*mp->m_host == '*') {
378                             mp->m_type |= W_HBEG;
379                             mp->m_host++;
380                         }
381                         if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
382                             mp->m_type |= W_HEND;
383                             *cp = '\0';
384                         }
385                     }
386                     if ((cp = getenv ("MHWDEBUG")) && *cp)
387                         fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
388                             mp->m_mbox, mp->m_host,
389                             snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
390                 }
391             }
392             if (oops)
393                 advise (NULL, "please fix the %s: entry in your %s file",
394                         "alternate-mailboxes", mh_profile);
395         }
396     }
397
398     if (np == NULL) /* XXX */
399         return 0;
400     
401     /*
402      * Don't perform this "local" test if we have a Local-Mailbox set
403      */
404
405     if (! localmailbox)
406         switch (np->m_type) {
407             case NETHOST:
408                 len = strlen (cp = LocalName (0));
409                 if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
410                     break;
411                 goto local_test;
412
413             case UUCPHOST:
414                 if (mh_strcasecmp (np->m_host, SystemName()))
415                     break;              /* fall */
416             case LOCALHOST:
417 local_test: ;
418                 if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
419                     return 1;
420                 break;
421
422             default:
423                 break;
424         }
425
426     /*
427      * Now scan through list of alternate
428      * mailboxes, and check for a match.
429      */
430     for (mp = &mq; mp->m_next;) {
431         mp = mp->m_next;
432         if (!np->m_mbox)
433             continue; if ((len = strlen (cp = np->m_mbox))
434                 < (i = strlen (pp = mp->m_mbox)))
435             continue;
436         switch (mp->m_type & W_MBOX) {
437             case W_NIL: 
438                 if (mh_strcasecmp (cp, pp))
439                     continue;
440                 break;
441             case W_MBEG: 
442                 if (mh_strcasecmp (cp + len - i, pp))
443                     continue;
444                 break;
445             case W_MEND: 
446                 if (!uprf (cp, pp))
447                     continue;
448                 break;
449             case W_MBEG | W_MEND: 
450                 if (stringdex (pp, cp) < 0)
451                     continue;
452                 break;
453         }
454
455         if (mp->m_nohost)
456             return 1;
457         if (np->m_host == NULL)
458             continue;
459         if ((len = strlen (cp = np->m_host))
460                 < (i = strlen (pp = mp->m_host)))
461             continue;
462         switch (mp->m_type & W_HOST) {
463             case W_NIL: 
464                 if (mh_strcasecmp (cp, pp))
465                     continue;
466                 break;
467             case W_HBEG: 
468                 if (mh_strcasecmp (cp + len - i, pp))
469                     continue;
470                 break;
471             case W_HEND: 
472                 if (!uprf (cp, pp))
473                     continue;
474                 break;
475             case W_HBEG | W_HEND: 
476                 if (stringdex (pp, cp) < 0)
477                     continue;
478                 break;
479         }
480         return 1;
481     }
482
483     return 0;
484 }