Convert from the poorly-named and confusing adrsprintf() to getlocaladdr().
[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    The comments below are left in for historical purposes; DUMB and
21    REALLYDUMB are now the default in the code.
22
23    If #ifdef DUMB is in effect, a full 822-style parser is called
24    for syntax recongition.  This breaks each address into its components.
25    Note however that no semantics are assumed about the parts or their
26    totality.  This means that implicit hostnames aren't made explicit,
27    and explicit hostnames aren't expanded to their "official" represenations.
28
29    If DUMB is not in effect, then this module does some
30    high-level thinking about what the addresses are.
31
32    1. for MMDF systems:
33
34         string%<uucp>@<local>   ->      string
35
36    2. for non-MMDF systems:
37
38         string@host.<uucp>      ->      host!string
39
40    3. for any system, an address interpreted relative to the local host:
41
42         string@<uucp>           ->      string
43
44    For cases (1) and (3) above, the leftmost host is extracted.  If it's not
45    present, the local host is used.  If the tests above fail, the address is
46    considered to be a real 822-style address.
47
48    If an explicit host is not present, then MH checks for a bang to indicate
49    an explicit UUCP-style address.  If so, this is noted.  If not, the host is
50    defaulted, typically to the local host.  The lack of an explict host is
51    also noted.
52
53    If an explicit 822-style host is present, then MH checks to see if it
54    can expand this to the official name for the host.  If the hostname is
55    unknown, the address is so typed.
56
57    To summarize, when we're all done, here's what MH knows about the address:
58
59    DUMB -       type:   local, uucp, or network
60                 host:   not locally defaulted, not explicitly expanded
61                 everything else
62
63    other -      type:   local, uucp, network, unknown
64                 everything else
65  */
66
67
68 static int  ingrp = 0;
69 static char *pers = NULL;
70 static char *mbox = NULL;
71 static char *host = NULL;
72 static char *route = NULL;
73 static char *grp = NULL;
74 static char *note = NULL;
75 static char err[BUFSIZ];
76 static char adr[BUFSIZ];
77
78
79 extern boolean  username_extension_masquerading;  /* defined in mts.c */
80
81
82 /*
83  * external prototypes
84  */
85 char *getusername (void);
86
87
88 char *
89 getname (char *addrs)
90 {
91     struct adrx *ap;
92
93     pers = mbox = host = route = grp = note = NULL;
94     err[0] = '\0';
95
96     if ((ap = getadrx (addrs ? addrs : "")) == NULL)
97         return NULL;
98
99     strncpy (adr, ap->text, sizeof(adr));
100     pers = ap->pers;
101     mbox = ap->mbox;
102     host = ap->host;
103     route = ap->path;
104     grp = ap->grp;
105     ingrp = ap->ingrp;
106     note = ap->note;
107     if (ap->err && *ap->err)
108         strncpy (err, ap->err, sizeof(err));
109
110     return adr;
111 }
112
113
114 struct mailname *
115 getm (char *str, char *dfhost, int dftype, int wanthost, char *eresult)
116 {
117     char *pp;
118     struct mailname *mp;
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             if (route == NULL && dftype == LOCALHOST) {
192                 mp->m_host = NULL;
193                 mp->m_type = dftype;
194             }
195             else
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 = !mh_strcasecmp (LocalName (), mp->m_host)
206             ? LOCALHOST : NETHOST;
207     else
208         mp->m_type = mh_strcasecmp (LocalName(), mp->m_host) ?  NETHOST : LOCALHOST;
209
210 got_host: ;
211     if (route)
212         mp->m_path = getcpy (route);
213     mp->m_ingrp = ingrp;
214     if (grp)
215         mp->m_gname = getcpy (grp);
216     if (note)
217         mp->m_note = getcpy (note);
218
219     return mp;
220 }
221
222
223 void
224 mnfree (struct mailname *mp)
225 {
226     if (!mp)
227         return;
228
229     if (mp->m_text)
230         free (mp->m_text);
231     if (mp->m_pers)
232         free (mp->m_pers);
233     if (mp->m_mbox)
234         free (mp->m_mbox);
235     if (mp->m_host)
236         free (mp->m_host);
237     if (mp->m_path)
238         free (mp->m_path);
239     if (mp->m_gname)
240         free (mp->m_gname);
241     if (mp->m_note)
242         free (mp->m_note);
243
244     free ((char *) mp);
245 }
246
247
248 #define empty(s) ((s) ? (s) : "")
249
250 char *
251 auxformat (struct mailname *mp, int extras)
252 {
253     static char addr[BUFSIZ];
254     static char buffer[BUFSIZ];
255
256         if (mp->m_nohost)
257             strncpy (addr, mp->m_mbox ? mp->m_mbox : "", sizeof(addr));
258         else
259
260         if (mp->m_type != UUCPHOST)
261             snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
262                 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
263         else
264             snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
265
266     if (!extras)
267         return addr;
268
269     if (mp->m_pers || mp->m_path) {
270         if (mp->m_note)
271             snprintf (buffer, sizeof(buffer), "%s %s <%s>",
272                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
273                     mp->m_note, addr);
274         else
275             snprintf (buffer, sizeof(buffer), "%s <%s>",
276                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
277                     addr);
278     }
279     else
280         if (mp->m_note)
281             snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
282         else
283             strncpy (buffer, addr, sizeof(buffer));
284
285     return buffer;
286 }
287
288
289 /*
290  * This used to be adrsprintf() (where it would format an address for you
291  * given a username and a domain).  But somewhere we got to the point where
292  * the only caller was post, and it only called it with both arguments NULL.
293  * So the function was renamed with a more sensible name.
294  */
295
296 char *
297 getlocaladdr(void)
298 {
299     int          snprintf_return;
300     char         *username, *domain;
301     static char  addr[BUFSIZ];
302
303     username = getusername();
304
305     if (username_extension_masquerading) {
306         /* mts.conf contains "masquerade:[...]username_extension[...]", so tack
307            on the value of the $USERNAME_EXTENSION environment variable, if set,
308            to username. */
309         char*        extension = getenv("USERNAME_EXTENSION");
310         static char  username_with_extension[BUFSIZ];
311
312         if (extension != NULL && *extension != '\0') {
313             snprintf_return = snprintf(username_with_extension,
314                                        sizeof(username_with_extension),
315                                        "%s%s", username, extension);
316             
317             if (snprintf_return < 0 ||
318                 snprintf_return >= (int) sizeof(username_with_extension))
319                 adios(NULL, "snprintf() error writing username (%d chars) and"
320                       " $USERNAME_EXTENSION (%d chars) to array of BUFSIZ (%d)"
321                       " chars",
322                       strlen(username), strlen(extension), BUFSIZ);
323             
324             username = username_with_extension;
325         }
326     }
327
328     return username;
329
330     domain = LocalName();
331
332     snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
333
334     if (snprintf_return < 0 || snprintf_return >= (int) sizeof(addr))
335         adios(NULL, "snprintf() error writing username (%d chars), domain (%d"
336               " chars), and 1 separator char to array of BUFSIZ (%d) chars",
337               strlen(username), strlen(domain), BUFSIZ);
338     
339     return addr;
340 }
341
342
343 #define W_NIL   0x0000
344 #define W_MBEG  0x0001
345 #define W_MEND  0x0002
346 #define W_MBOX  (W_MBEG | W_MEND)
347 #define W_HBEG  0x0004
348 #define W_HEND  0x0008
349 #define W_HOST  (W_HBEG | W_HEND)
350 #define WBITS   "\020\01MBEG\02MEND\03HBEG\04HEND"
351
352 /*
353  * Check if this is my address
354  */
355
356 int
357 ismymbox (struct mailname *np)
358 {
359     int oops;
360     register int len, i;
361     register char *cp;
362     register char *pp;
363     char buffer[BUFSIZ];
364     struct mailname *mp;
365     static char *am = NULL;
366     static struct mailname mq;
367
368     /*
369      * If this is the first call, initialize
370      * list of alternate mailboxes.
371      */
372     if (am == NULL) {
373         mq.m_next = NULL;
374         mq.m_mbox = getusername ();
375         if ((am = context_find ("alternate-mailboxes")) == NULL)
376             am = getusername();
377         else {
378             mp = &mq;
379             oops = 0;
380             while ((cp = getname (am))) {
381                 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
382                     admonish (NULL, "illegal address: %s", cp);
383                     oops++;
384                 } else {
385                     mp = mp->m_next;
386                     mp->m_type = W_NIL;
387                     if (*mp->m_mbox == '*') {
388                         mp->m_type |= W_MBEG;
389                         mp->m_mbox++;
390                     }
391                     if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
392                         mp->m_type |= W_MEND;
393                         *cp = '\0';
394                     }
395                     if (mp->m_host) {
396                         if (*mp->m_host == '*') {
397                             mp->m_type |= W_HBEG;
398                             mp->m_host++;
399                         }
400                         if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
401                             mp->m_type |= W_HEND;
402                             *cp = '\0';
403                         }
404                     }
405                     if ((cp = getenv ("MHWDEBUG")) && *cp)
406                         fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
407                             mp->m_mbox, mp->m_host,
408                             snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
409                 }
410             }
411             if (oops)
412                 advise (NULL, "please fix the %s: entry in your %s file",
413                         "alternate-mailboxes", mh_profile);
414         }
415     }
416
417     if (np == NULL) /* XXX */
418         return 0;
419     
420     switch (np->m_type) {
421         case NETHOST:
422             len = strlen (cp = LocalName ());
423             if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
424                 break;
425             goto local_test;
426
427         case UUCPHOST:
428             if (mh_strcasecmp (np->m_host, SystemName()))
429                 break;          /* fall */
430         case LOCALHOST:
431 local_test: ;
432             if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
433                 return 1;
434             break;
435
436         default:
437             break;
438     }
439
440     /*
441      * Now scan through list of alternate
442      * mailboxes, and check for a match.
443      */
444     for (mp = &mq; mp->m_next;) {
445         mp = mp->m_next;
446         if (!np->m_mbox)
447             continue;
448         if ((len = strlen (cp = np->m_mbox))
449                 < (i = strlen (pp = mp->m_mbox)))
450             continue;
451         switch (mp->m_type & W_MBOX) {
452             case W_NIL: 
453                 if (mh_strcasecmp (cp, pp))
454                     continue;
455                 break;
456             case W_MBEG: 
457                 if (mh_strcasecmp (cp + len - i, pp))
458                     continue;
459                 break;
460             case W_MEND: 
461                 if (!uprf (cp, pp))
462                     continue;
463                 break;
464             case W_MBEG | W_MEND: 
465                 if (stringdex (pp, cp) < 0)
466                     continue;
467                 break;
468         }
469
470         if (mp->m_nohost)
471             return 1;
472         if (np->m_host == NULL)
473             continue;
474         if ((len = strlen (cp = np->m_host))
475                 < (i = strlen (pp = mp->m_host)))
476             continue;
477         switch (mp->m_type & W_HOST) {
478             case W_NIL: 
479                 if (mh_strcasecmp (cp, pp))
480                     continue;
481                 break;
482             case W_HBEG: 
483                 if (mh_strcasecmp (cp + len - i, pp))
484                     continue;
485                 break;
486             case W_HEND: 
487                 if (!uprf (cp, pp))
488                     continue;
489                 break;
490             case W_HBEG | W_HEND: 
491                 if (stringdex (pp, cp) < 0)
492                     continue;
493                 break;
494         }
495         return 1;
496     }
497
498     return 0;
499 }