Remove RCS keywords, since they no longer work after git migration.
[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 #ifndef BANG
284         if (mp->m_type != UUCPHOST)
285             snprintf (addr, sizeof(addr), mp->m_host ? "%s%s@%s" : "%s%s",
286                 empty(mp->m_path), empty(mp->m_mbox), mp->m_host);
287         else
288 #endif /* not BANG */
289             snprintf (addr, sizeof(addr), "%s!%s", mp->m_host, mp->m_mbox);
290
291     if (!extras)
292         return addr;
293
294     if (mp->m_pers || mp->m_path) {
295         if (mp->m_note)
296             snprintf (buffer, sizeof(buffer), "%s %s <%s>",
297                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
298                     mp->m_note, addr);
299         else
300             snprintf (buffer, sizeof(buffer), "%s <%s>",
301                     legal_person (mp->m_pers ? mp->m_pers : mp->m_mbox),
302                     addr);
303     }
304     else
305         if (mp->m_note)
306             snprintf (buffer, sizeof(buffer), "%s %s", addr, mp->m_note);
307         else
308             strncpy (buffer, addr, sizeof(buffer));
309
310     return buffer;
311 }
312
313
314 /*
315  * address specific "sprintf"
316  */
317
318 char *
319 adrsprintf (char *username, char *domain)
320 {
321     int          snprintf_return;
322     static char  addr[BUFSIZ];
323
324     if (username == NULL)
325         username = getusername();
326
327     if (username_extension_masquerading) {
328         /* mts.conf contains "masquerade:[...]username_extension[...]", so tack
329            on the value of the $USERNAME_EXTENSION environment variable, if set,
330            to username. */
331         char*        extension = getenv("USERNAME_EXTENSION");
332         static char  username_with_extension[BUFSIZ];
333
334         if (extension != NULL && *extension != '\0') {
335             snprintf_return = snprintf(username_with_extension,
336                                        sizeof(username_with_extension),
337                                        "%s%s", username, extension);
338             
339             if (snprintf_return < 0 ||
340                 snprintf_return >= sizeof(username_with_extension))
341                 adios(NULL, "snprintf() error writing username (%d chars) and"
342                       " $USERNAME_EXTENSION (%d chars) to array of BUFSIZ (%d)"
343                       " chars",
344                       strlen(username), strlen(extension), BUFSIZ);
345             
346             username = username_with_extension;
347         }
348     }
349
350 #ifdef REALLYDUMB
351     return username;
352 #endif
353
354     if (domain == NULL)
355         domain = LocalName();
356
357 #ifndef BANG
358     snprintf_return = snprintf (addr, sizeof(addr), "%s@%s", username, domain);
359 #else /* BANG */
360     snprintf_return = snprintf (addr, sizeof(addr), "%s!%s", domain, username);
361 #endif /* BANG */
362
363     if (snprintf_return < 0 || snprintf_return >= sizeof(addr))
364         adios(NULL, "snprintf() error writing username (%d chars), domain (%d"
365               " chars), and 1 separator char to array of BUFSIZ (%d) chars",
366               strlen(username), strlen(domain), BUFSIZ);
367     
368     return addr;
369 }
370
371
372 #define W_NIL   0x0000
373 #define W_MBEG  0x0001
374 #define W_MEND  0x0002
375 #define W_MBOX  (W_MBEG | W_MEND)
376 #define W_HBEG  0x0004
377 #define W_HEND  0x0008
378 #define W_HOST  (W_HBEG | W_HEND)
379 #define WBITS   "\020\01MBEG\02MEND\03HBEG\04HEND"
380
381 /*
382  * Check if this is my address
383  */
384
385 int
386 ismymbox (struct mailname *np)
387 {
388     int oops;
389     register int len, i;
390     register char *cp;
391     register char *pp;
392     char buffer[BUFSIZ];
393     struct mailname *mp;
394     static char *am = NULL;
395     static struct mailname mq={NULL};
396
397     /*
398      * If this is the first call, initialize
399      * list of alternate mailboxes.
400      */
401     if (am == NULL) {
402         mq.m_next = NULL;
403         mq.m_mbox = getusername ();
404         if ((am = context_find ("alternate-mailboxes")) == NULL)
405             am = getusername();
406         else {
407             mp = &mq;
408             oops = 0;
409             while ((cp = getname (am))) {
410                 if ((mp->m_next = getm (cp, NULL, 0, AD_NAME, NULL)) == NULL) {
411                     admonish (NULL, "illegal address: %s", cp);
412                     oops++;
413                 } else {
414                     mp = mp->m_next;
415                     mp->m_type = W_NIL;
416                     if (*mp->m_mbox == '*') {
417                         mp->m_type |= W_MBEG;
418                         mp->m_mbox++;
419                     }
420                     if (*(cp = mp->m_mbox + strlen (mp->m_mbox) - 1) == '*') {
421                         mp->m_type |= W_MEND;
422                         *cp = '\0';
423                     }
424                     if (mp->m_host) {
425                         if (*mp->m_host == '*') {
426                             mp->m_type |= W_HBEG;
427                             mp->m_host++;
428                         }
429                         if (*(cp = mp->m_host + strlen (mp->m_host) - 1) == '*') {
430                             mp->m_type |= W_HEND;
431                             *cp = '\0';
432                         }
433                     }
434                     if ((cp = getenv ("MHWDEBUG")) && *cp)
435                         fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
436                             mp->m_mbox, mp->m_host,
437                             snprintb (buffer, sizeof(buffer), (unsigned) mp->m_type, WBITS));
438                 }
439             }
440             if (oops)
441                 advise (NULL, "please fix the %s: entry in your %s file",
442                         "alternate-mailboxes", mh_profile);
443         }
444     }
445
446     if (np == NULL) /* XXX */
447         return 0;
448     
449     switch (np->m_type) {
450         case NETHOST:
451             len = strlen (cp = LocalName ());
452             if (!uprf (np->m_host, cp) || np->m_host[len] != '.')
453                 break;
454             goto local_test;
455
456         case UUCPHOST:
457             if (mh_strcasecmp (np->m_host, SystemName()))
458                 break;          /* fall */
459         case LOCALHOST:
460 local_test: ;
461             if (!mh_strcasecmp (np->m_mbox, mq.m_mbox))
462                 return 1;
463             break;
464
465         default:
466             break;
467     }
468
469     /*
470      * Now scan through list of alternate
471      * mailboxes, and check for a match.
472      */
473     for (mp = &mq; mp->m_next;) {
474         mp = mp->m_next;
475         if (!np->m_mbox)
476             continue;
477         if ((len = strlen (cp = np->m_mbox))
478                 < (i = strlen (pp = mp->m_mbox)))
479             continue;
480         switch (mp->m_type & W_MBOX) {
481             case W_NIL: 
482                 if (mh_strcasecmp (cp, pp))
483                     continue;
484                 break;
485             case W_MBEG: 
486                 if (mh_strcasecmp (cp + len - i, pp))
487                     continue;
488                 break;
489             case W_MEND: 
490                 if (!uprf (cp, pp))
491                     continue;
492                 break;
493             case W_MBEG | W_MEND: 
494                 if (stringdex (pp, cp) < 0)
495                     continue;
496                 break;
497         }
498
499         if (mp->m_nohost)
500             return 1;
501         if (np->m_host == NULL)
502             continue;
503         if ((len = strlen (cp = np->m_host))
504                 < (i = strlen (pp = mp->m_host)))
505             continue;
506         switch (mp->m_type & W_HOST) {
507             case W_NIL: 
508                 if (mh_strcasecmp (cp, pp))
509                     continue;
510                 break;
511             case W_HBEG: 
512                 if (mh_strcasecmp (cp + len - i, pp))
513                     continue;
514                 break;
515             case W_HEND: 
516                 if (!uprf (cp, pp))
517                     continue;
518                 break;
519             case W_HBEG | W_HEND: 
520                 if (stringdex (pp, cp) < 0)
521                     continue;
522                 break;
523         }
524         return 1;
525     }
526
527     return 0;
528 }