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