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