a1cdf8c37b49b1f5396937993583f53eef080ffb
[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 <h/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 extern boolean  username_extension_masquerading;  /* defined in mts.c */
75
76
77 /*
78  * external prototypes
79  */
80 char *getusername (void);
81
82
83 char *
84 getname (char *addrs)
85 {
86     struct adrx *ap;
87
88     pers = mbox = host = route = grp = note = NULL;
89     err[0] = '\0';
90
91     if ((ap = getadrx (addrs ? addrs : "")) == NULL)
92         return NULL;
93
94     strncpy (adr, ap->text, sizeof(adr));
95     pers = ap->pers;
96     mbox = ap->mbox;
97     host = ap->host;
98     route = ap->path;
99     grp = ap->grp;
100     ingrp = ap->ingrp;
101     note = ap->note;
102     if (ap->err && *ap->err)
103         strncpy (err, ap->err, sizeof(err));
104
105     return adr;
106 }
107
108
109 struct mailname *
110 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
111 {
112     char *pp;
113     struct mailname *mp;
114 #ifndef DUMB
115     char *dp;
116 #endif /* not DUMB */
117
118     if (err && err[0]) {
119         if (eresult)
120             strcpy (eresult, err);
121         else
122             if (wanthost == AD_HOST)
123                 admonish (NULL, "bad address '%s' - %s", str, err);
124         return NULL;
125     }
126     if (pers == NULL
127             && mbox == NULL && host == NULL && route == NULL
128             && grp == NULL) {
129         if (eresult)
130             strcpy (eresult, "null address");
131         else
132             if (wanthost == AD_HOST)
133                 admonish (NULL, "null address '%s'", str);
134         return NULL;
135     }
136     if (mbox == NULL && grp == NULL) {
137         if (eresult)
138             strcpy (eresult, "no mailbox in address");
139         else
140             if (wanthost == AD_HOST)
141                 admonish (NULL, "no mailbox in address '%s'", str);
142         return NULL;
143     }
144
145     if (dfhost == NULL) {
146         dfhost = LocalName ();
147         dftype = LOCALHOST;
148     }
149
150     mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp));
151     if (mp == NULL) {
152         if (eresult)
153            strcpy (eresult, "insufficient memory to represent address");
154         else
155             if (wanthost == AD_HOST)
156                 adios (NULL, "insufficient memory to represent address");
157         return NULL;
158     }
159
160     mp->m_next = NULL;
161     mp->m_text = getcpy (str);
162     if (pers)
163         mp->m_pers = getcpy (pers);
164
165     if (mbox == NULL) {
166         mp->m_type = BADHOST;
167         mp->m_nohost = 1;
168         mp->m_ingrp = ingrp;
169         mp->m_gname = getcpy (grp);
170         if (note)
171             mp->m_note = getcpy (note);
172         return mp;
173     }
174
175     if (host) {
176         mp->m_mbox = getcpy (mbox);
177         mp->m_host = getcpy (host);
178     }
179     else {
180         if ((pp = strchr(mbox, '!'))) {
181             *pp++ = '\0';
182             mp->m_mbox = getcpy (pp);
183             mp->m_host = getcpy (mbox);
184             mp->m_type = UUCPHOST;
185         }
186         else {
187             mp->m_nohost = 1;
188             mp->m_mbox = getcpy (mbox);
189 #ifdef DUMB
190             if (route == NULL && dftype == LOCALHOST) {
191                 mp->m_host = NULL;
192                 mp->m_type = dftype;
193             }
194             else
195 #endif /* DUMB */
196             {
197                 mp->m_host = route ? NULL : getcpy (dfhost);
198                 mp->m_type = route ? NETHOST : dftype;
199             }
200         }
201         goto got_host;
202     }
203
204     if (wanthost == AD_NHST)
205         mp->m_type = !strcasecmp (LocalName (), mp->m_host)
206             ? LOCALHOST : NETHOST;
207 #ifdef DUMB
208     else
209         mp->m_type = strcasecmp (LocalName(), mp->m_host) ?  NETHOST : LOCALHOST;
210 #else /* not DUMB */
211     else
212         if (pp = OfficialName (mp->m_host)) {
213     got_real_host: ;
214             free (mp->m_host);
215             mp->m_host = getcpy (pp);
216             mp->m_type = strcasecmp (LocalName(), mp->m_host) ? NETHOST : LOCALHOST;
217         }
218         else {
219             if (dp = strchr(mp->m_host, '.')) {
220                 *dp = NULL;
221                 if (pp = OfficialName (mp->m_host))
222                     goto got_real_host;
223                 *dp = '.';
224             }
225             mp->m_type = BADHOST;
226         }
227 #endif /* not DUMB */
228
229 got_host: ;
230     if (route)
231         mp->m_path = getcpy (route);
232     mp->m_ingrp = ingrp;
233     if (grp)
234         mp->m_gname = getcpy (grp);
235     if (note)
236         mp->m_note = getcpy (note);
237
238     return mp;
239 }
240
241
242 void
243 mnfree (struct mailname *mp)
244 {
245     if (!mp)
246         return;
247
248     if (mp->m_text)
249         free (mp->m_text);
250     if (mp->m_pers)
251         free (mp->m_pers);
252     if (mp->m_mbox)
253         free (mp->m_mbox);
254     if (mp->m_host)
255         free (mp->m_host);
256     if (mp->m_path)
257         free (mp->m_path);
258     if (mp->m_gname)
259         free (mp->m_gname);
260     if (mp->m_note)
261         free (mp->m_note);
262
263     free ((char *) mp);
264 }
265
266
267 #define empty(s) ((s) ? (s) : "")
268
269 char *
270 auxformat (struct mailname *mp, int extras)
271 {
272     static char addr[BUFSIZ];
273     static char buffer[BUFSIZ];
274
275 #ifdef DUMB
276         if (mp->m_nohost)
277             strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
278         else
279 #endif /* DUMB */
280
281 #ifndef BANG
282         if (mp->m_type != UUCPHOST)
283             snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
284                 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
285         else
286 #endif /* not BANG */
287             snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
288
289     if (!extras)
290         return addr;
291
292     if (mp->m_pers || mp->m_path) {
293         if (mp->m_note)
294             snprintf (buffer, sizeof(buffer), "%s %s <%s>",
295                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
296                     mp->m_note, addr);
297         else
298             snprintf (buffer, sizeof(buffer), "%s <%s>",
299                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
300                     addr);
301     }
302     else
303         if (mp->m_note)
304             snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
305         else
306             strncpy (buffer, addr, sizeof(buffer));
307
308     return buffer;
309 }
310
311
312 /*
313  * address specific "sprintf"
314  */
315
316 char *
317 adrsprintf (char *username, char *domain)
318 {
319     int          snprintf_return;
320     static char  addr[BUFSIZ];
321
322     if (username == NULL)
323         username = getusername();
324
325     if (username_extension_masquerading) {
326         /* mts.conf contains "masquerade:[...]username_extension[...]", so tack
327            on the value of the $USERNAME_EXTENSION environment variable, if set,
328            to username. */
329         char*        extension = getenv("USERNAME_EXTENSION");
330         static char  username_with_extension[BUFSIZ];
331
332         if (extension != NULL && *extension != '\0') {
333             snprintf_return = snprintf(username_with_extension,
334                                        sizeof(username_with_extension),
335                                        "%s%s", username, extension);
336             
337             if (snprintf_return < 0 ||
338                 snprintf_return >= sizeof(username_with_extension))
339                 adios(NULL, "snprintf() error writing username (%d chars) and"
340                       " $USERNAME_EXTENSION (%d chars) to array of BUFSIZ (%d)"
341                       " chars",
342                       strlen(username), strlen(extension), BUFSIZ);
343             
344             username = username_with_extension;
345         }
346     }
347
348 #ifdef REALLYDUMB
349     return username;
350 #endif
351
352     if (domain == NULL)
353         domain = LocalName();
354
355 #ifndef BANG
356     snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
357 #else /* BANG */
358     snprintf_return = snprintf (addr, sizeof(addr), "%s!%s", domain, username);
359 #endif /* BANG */
360
361     if (snprintf_return < 0 || snprintf_return >= sizeof(addr))
362         adios(NULL, "snprintf() error writing username (%d chars), domain (%d"
363               " chars), and 1 separator char to array of BUFSIZ (%d) chars",
364               strlen(username), strlen(domain), BUFSIZ);
365     
366     return addr;
367 }
368
369
370 #define W_NIL   0x0000
371 #define W_MBEG  0x0001
372 #define W_MEND  0x0002
373 #define W_MBOX  (W_MBEG | W_MEND)
374 #define W_HBEG  0x0004
375 #define W_HEND  0x0008
376 #define W_HOST  (W_HBEG | W_HEND)
377 #define WBITS   "\020\01MBEG\02MEND\03HBEG\04HEND"
378
379 /*
380  * Check if this is my address
381  */
382
383 int
384 ismymbox (struct mailname *np)
385 {
386     int oops;
387     register int len, i;
388     register char *cp;
389     register char *pp;
390     char buffer[BUFSIZ];
391     struct mailname *mp;
392     static char *am = NULL;
393     static struct mailname mq={NULL};
394
395     /*
396      * If this is the first call, initialize
397      * list of alternate mailboxes.
398      */
399     if (am == NULL) {
400         mq.m_next = NULL;
401         mq.m_mbox = getusername ();
402         if ((am = context_find ("alternate-mailboxes")) == NULL)
403             am = getusername();
404         else {
405             mp = &mq;
406             oops = 0;
407             while ((cp = getname (am))) {
408                 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
409                     admonish (NULL, "illegal address: %s", cp);
410                     oops++;
411                 } else {
412                     mp = mp->m_next;
413                     mp->m_type = W_NIL;
414                     if (*mp->m_mbox == '*') {
415                         mp->m_type |= W_MBEG;
416                         mp->m_mbox++;
417                     }
418                     if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
419                         mp->m_type |= W_MEND;
420                         *cp = '\0';
421                     }
422                     if (mp->m_host) {
423                         if (*mp->m_host == '*') {
424                             mp->m_type |= W_HBEG;
425                             mp->m_host++;
426                         }
427                         if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
428                             mp->m_type |= W_HEND;
429                             *cp = '\0';
430                         }
431                     }
432                     if ((cp = getenv ("MHWDEBUG")) && *cp)
433                         fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
434                             mp->m_mbox, mp->m_host,
435                             snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
436                 }
437             }
438             if (oops)
439                 advise (NULL, "please fix the %s: entry in your %s file",
440                         "alternate-mailboxes", mh_profile);
441         }
442     }
443
444     if (np == NULL) /* XXX */
445         return 0;
446     
447     switch (np->m_type) {
448         case NETHOST:
449             len = strlen (cp = LocalName ());
450             if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
451                 break;
452             goto local_test;
453
454         case UUCPHOST:
455             if (strcasecmp (np->m_host, SystemName()))
456                 break;          /* fall */
457         case LOCALHOST:
458 local_test: ;
459             if (!strcasecmp (np->m_mbox, mq.m_mbox))
460                 return 1;
461             break;
462
463         default:
464             break;
465     }
466
467     /*
468      * Now scan through list of alternate
469      * mailboxes, and check for a match.
470      */
471     for (mp = &mq; mp->m_next;) {
472         mp = mp->m_next;
473         if (!np->m_mbox)
474             continue;
475         if ((len = strlen (cp = np->m_mbox))
476                 < (i = strlen (pp = mp->m_mbox)))
477             continue;
478         switch (mp->m_type & W_MBOX) {
479             case W_NIL: 
480                 if (strcasecmp (cp, pp))
481                     continue;
482                 break;
483             case W_MBEG: 
484                 if (strcasecmp (cp + len - i, pp))
485                     continue;
486                 break;
487             case W_MEND: 
488                 if (!uprf (cp, pp))
489                     continue;
490                 break;
491             case W_MBEG | W_MEND: 
492                 if (stringdex (pp, cp) < 0)
493                     continue;
494                 break;
495         }
496
497         if (mp->m_nohost)
498             return 1;
499         if (np->m_host == NULL)
500             continue;
501         if ((len = strlen (cp = np->m_host))
502                 < (i = strlen (pp = mp->m_host)))
503             continue;
504         switch (mp->m_type & W_HOST) {
505             case W_NIL: 
506                 if (strcasecmp (cp, pp))
507                     continue;
508                 break;
509             case W_HBEG: 
510                 if (strcasecmp (cp + len - i, pp))
511                     continue;
512                 break;
513             case W_HEND: 
514                 if (!uprf (cp, pp))
515                     continue;
516                 break;
517             case W_HBEG | W_HEND: 
518                 if (stringdex (pp, cp) < 0)
519                     continue;
520                 break;
521         }
522         return 1;
523     }
524
525     return 0;
526 }