Changed msg_style and msg_delim to be file static to m_getfld.c
[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         mp->m_type =
173             mh_strcasecmp (LocalName(0), mp->m_host) ? NETHOST : LOCALHOST;
174     } else {
175         if ((pp = strchr(mbox, '!'))) {
176             *pp++ = '\0';
177             mp->m_mbox = getcpy (pp);
178             mp->m_host = getcpy (mbox);
179             mp->m_type = UUCPHOST;
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             } else {
187                 mp->m_host = route ? NULL : getcpy (dfhost);
188                 mp->m_type = route ? NETHOST : dftype;
189             }
190         }
191     }
192
193     /* For alternate mailboxes, m_type gets overwritten in ismymbox ()
194        to support wild-card matching. */
195
196     if (route)
197         mp->m_path = getcpy (route);
198     mp->m_ingrp = ingrp;
199     if (grp)
200         mp->m_gname = getcpy (grp);
201     if (note)
202         mp->m_note = getcpy (note);
203
204     return mp;
205 }
206
207
208 void
209 mnfree (struct mailname *mp)
210 {
211     if (!mp)
212         return;
213
214     if (mp->m_text)
215         free (mp->m_text);
216     if (mp->m_pers)
217         free (mp->m_pers);
218     if (mp->m_mbox)
219         free (mp->m_mbox);
220     if (mp->m_host)
221         free (mp->m_host);
222     if (mp->m_path)
223         free (mp->m_path);
224     if (mp->m_gname)
225         free (mp->m_gname);
226     if (mp->m_note)
227         free (mp->m_note);
228
229     free ((char *) mp);
230 }
231
232
233 #define empty(s) ((s) ? (s) : "")
234
235 char *
236 auxformat (struct mailname *mp, int extras)
237 {
238     static char addr[BUFSIZ];
239     static char buffer[BUFSIZ];
240
241         if (mp->m_nohost)
242             strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
243         else
244
245         if (mp->m_type != UUCPHOST)
246             snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
247                 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
248         else
249             snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
250
251     if (!extras)
252         return addr;
253
254     if (mp->m_pers || mp->m_path) {
255         if (mp->m_note)
256             snprintf (buffer, sizeof(buffer), "%s %s <%s>",
257                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
258                     mp->m_note, addr);
259         else
260             snprintf (buffer, sizeof(buffer), "%s <%s>",
261                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
262                     addr);
263     }
264     else
265         if (mp->m_note)
266             snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
267         else
268             strncpy (buffer, addr, sizeof(buffer));
269
270     return buffer;
271 }
272
273
274 /*
275  * This used to be adrsprintf() (where it would format an address for you
276  * given a username and a domain).  But somewhere we got to the point where
277  * the only caller was post, and it only called it with both arguments NULL.
278  * So the function was renamed with a more sensible name.
279  */
280
281 char *
282 getlocaladdr(void)
283 {
284     char         *username;
285
286     username = getusername();
287
288     return username;
289 }
290
291
292 #define W_NIL   0x0000
293 #define W_MBEG  0x0001
294 #define W_MEND  0x0002
295 #define W_MBOX  (W_MBEG | W_MEND)
296 #define W_HBEG  0x0004
297 #define W_HEND  0x0008
298 #define W_HOST  (W_HBEG | W_HEND)
299 #define WBITS   "\020\01MBEG\02MEND\03HBEG\04HEND"
300
301 /*
302  * Check if this is my address
303  */
304
305 int
306 ismymbox (struct mailname *np)
307 {
308     int oops;
309     register int len, i;
310     register char *cp;
311     register char *pp;
312     char buffer[BUFSIZ];
313     struct mailname *mp;
314     static char *am = NULL;
315     static struct mailname mq;
316     static int localmailbox = 0;
317
318     /*
319      * If this is the first call, initialize
320      * list of alternate mailboxes.
321      */
322     if (am == NULL) {
323         mq.m_next = NULL;
324         mq.m_mbox = getusername ();
325
326         if ((am = context_find ("local-mailbox"))) {
327
328             localmailbox++;
329
330             if ((cp = getname(am)) == NULL) {
331                 admonish (NULL, "Unable to find address in local-mailbox");
332                 return 0;
333             }
334
335             if ((mq.m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
336                 admonish (NULL, "invalid entry in local-mailbox: %s", cp);
337                 return 0;
338             }
339
340             /*
341              * Sigh, it turns out that the address parser gets messed up
342              * if you don't call getname() until it returns NULL.
343              */
344
345             while ((cp = getname(am)) != NULL)
346                 ;
347         }
348
349         if ((am = context_find ("alternate-mailboxes")) == NULL)
350             am = getusername();
351         else {
352             mp = mq.m_next ? mq.m_next : &mq;
353             oops = 0;
354             while ((cp = getname (am))) {
355                 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
356                     admonish (NULL, "illegal address: %s", cp);
357                     oops++;
358                 } else {
359                     mp = mp->m_next;
360                     mp->m_type = W_NIL;
361                     if (*mp->m_mbox == '*') {
362                         mp->m_type |= W_MBEG;
363                         mp->m_mbox++;
364                     }
365                     if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
366                         mp->m_type |= W_MEND;
367                         *cp = '\0';
368                     }
369                     if (mp->m_host) {
370                         if (*mp->m_host == '*') {
371                             mp->m_type |= W_HBEG;
372                             mp->m_host++;
373                         }
374                         if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
375                             mp->m_type |= W_HEND;
376                             *cp = '\0';
377                         }
378                     }
379                 }
380             }
381             if (oops)
382                 advise (NULL, "please fix the %s: entry in your %s file",
383                         "alternate-mailboxes", mh_profile);
384         }
385
386         if ((cp = getenv ("MHWDEBUG")) && *cp) {
387             for (mp = &mq; mp; mp = mp->m_next) {
388               fprintf (stderr, "Local- or Alternate-Mailbox: text=\"%s\" "
389                        "mbox=\"%s\" host=\"%s\" %s\n",
390                        mp->m_text ? mp->m_text : "", mp->m_mbox,
391                        mp->m_host ? mp->m_host : "",
392                        snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type,
393                                  WBITS));
394             }
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 }