Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / sbr / addrsbr.c
1 /* addrsbr.c - parse addresses 822-style */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: addrsbr.c,v 1.13 1992/10/26 22:44:26 jromine Exp $";
4 #endif /* lint */
5
6 #include "../h/mh.h"
7 #include "../h/addrsbr.h"
8 #include "../zotnet/mf.h"
9 #include <stdio.h>
10 #ifdef  BERK
11 #include <ctype.h>
12 #endif /* BERK */
13
14 /* High level parsing of addresses:
15
16    The routines in zotnet/mf/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 BERK is in effect, the routines in mf.c aren't called and only
21    the most rudimentary syntax parse is done.  The parse is not 822-conformant.
22    This causes problems as there is no semantics associated with the address
23    at all--it's just a string. (the author of the BERK code disagrees with
24    the preceding, of course.  BERK solves problems for incoming mail
25    because it will accept damn near any address.  BERK was intended to be
26    used when spost is the interface to the mail delivery system which means
27    all outgoing address interpretation is left to sendmail.  It is possible,
28    though unlikely, for BERK address parsing to interact poorly with 
29    "post". - van@monet.berkeley.edu).
30
31    Instead, if #ifdef DUMB is in effect, a full 822-style parser is called
32    for syntax recongition.  This breaks each address into its components.
33    Note however that no semantics are assumed about the parts or their
34    totality.  This means that implicit hostnames aren't made explicit,
35    and explicit hostnames aren't expanded to their "official" represenations.
36
37    If neither BERK nor DUMB is in effect, then this module does some
38    high-level thinking about what the addresses are.  If #ifdef MF is in
39    effect, then MH will deduce UUCP-style addressing masquerading as
40    822-style addresses.
41
42    1. for MMDF systems:
43
44         string%<uucp>@<local>   ->      string
45
46    2. for non-MMDF systems:
47
48         string@host.<uucp>      ->      host!string
49
50    3. for any system, an address interpreted relative to the local host:
51
52         string@<uucp>           ->      string
53
54    For cases (1) and (3) above, the leftmost host is extracted.  If it's not
55    present, the local host is used.  If #ifdef MF is not in effect or the
56    tests above fail, the address is considered to be a real 822-style address.
57
58    If an explicit host is not present, then MH checks for a bang to indicate
59    an explicit UUCP-style address.  If so, this is noted.  If not, the host is
60    defaulted, typically to the local host.  The lack of an explict host is
61    also noted.
62
63    If an explicit 822-style host is present, then MH checks to see if it
64    can expand this to the official name for the host.  If the hostname is
65    unknown, the address is so typed.
66
67    To summarize, when we're all done, here's what MH knows about the address:
68
69    BERK -       type:   local
70                 nohost: set if no '@' or '!' in mailbox
71                 text:   exact copy of address
72                 mbox:   lowercase version of mailbox
73
74    DUMB -       type:   local, uucp, or network
75                 host:   not locally defaulted, not explicitly expanded
76                 everything else
77
78    other -      type:   local, uucp, network, unknown
79                 everything else
80  */
81
82 /* \f */
83
84 #if     !defined(DUMB) && defined(SENDMTS) && !defined(BANG)
85 #define MF
86 #define UucpChan()      "UUCP"
87 #endif /* MF */
88
89 #ifdef  BERK
90 static char *err = NULL;
91 static char adrtext[BUFSIZ];
92 #else /* not BERK */
93 static int  ingrp = 0;
94
95 static char *pers = NULL;
96 static char *mbox = NULL;
97 static char *host = NULL;
98 static char *route = NULL;
99 static char *grp = NULL;
100 static char *note = NULL;
101
102 static char err[BUFSIZ];
103 #endif /* not BERK */
104 static char adr[BUFSIZ];
105
106
107 char   *getusr ();
108
109 /* \f */
110
111 char   *getname (addrs)
112 register char   *addrs;
113 {
114 #ifdef  BERK
115     /*
116      * Berkeley uses a very simple parser since Sendmail does all the work.
117      * The only thing that does address parsing if BERK is defined is the
118      * routine "ismybox" used by "scan" & "repl" to identify the current
119      * users maildrop.
120      *
121      * This routine does essentially the same address interpretation as the
122      * routine "prescan" in "sendmail".  The intent is that MH should 
123      * make minimum assumptions about address forms since it doesn't
124      * have access to the information in the sendmail config file
125      * (God forbid that anything but sendmail has to deal with a sendmail
126      * config file) and, therefore, hasn't the faintest idea of what will
127      * or won't be a legal address.
128      *
129      * Since this parse is only used by "ismybox" and repl, it just does
130      * two things: split multiple addr on a line into separate addresses and 
131      * locate the "mailbox" portion of an address.  The parse uses rfc-822
132      * metacharacters and quoting but is much less restrictive that rfc-822.
133      * In detail, `,' or eos terminate addresses.  "Empty" addresses
134      * (e.g., `,,') are ignored.  Double quote ("), backslash, left & right
135      * paren and left and right angle brackets are metacharacters.  Left &
136      * right parens must balance as must left & right angle brackets.  Any
137      * metacharacter may be escaped by preceding it with a backslash.
138      * Any text between parens is considered a comment and ignored (i.e.,
139      * only `(', `)' and `\' are metacharacters following a `(').  Text
140      * between double quotes is considered escaped (i.e., only `"' and
141      * `\' are metacharacters following a `"').  The `mailbox' portion
142      * of an address is the non-comment text between angle-brackets if
143      * the address contains any angle brackets.  Otherwise, it is all the
144      * non-comment text.  Blanks, tabs & newlines will not be included
145      * in the mailbox portion of an address unless they are escaped.
146      */
147
148 /* Scanner states */
149 #define NORMAL  (0<<8)
150 #define QS      (1<<8)  /* in quoted string */
151 #define COM     (2<<8)  /* in comment (...) */
152 #define ERR     (3<<8)  /* found an error */
153 #define EOA     (4<<8)  /* end of address */
154
155     static char *saved_addr = NULL;     /* saved address line ptr */
156     static char *adr_ptr = NULL;        /* where to start looking for
157                                            next address on line */
158     register char *nxtout = adr;        /* where to put next character of
159                                            `mailbox' part of address */
160     register char c;
161     register int state = NORMAL;
162     register char *adrcopy = adrtext;   /* where to put next character of
163                                            address */
164     register int lbcnt = 0;             /* number of unmatched "(" */
165     register int lpcnt = 0;             /* number of unmatched "<" */
166
167     err = NULL;
168     if (! addrs) {
169         adr_ptr = NULL;
170         return NULL;
171     }
172     if (adr_ptr)
173         addrs = adr_ptr;
174     else
175         addrs = saved_addr = getcpy(addrs ? addrs : "");
176
177     /* skip any leading whitespace or commas. */
178     while ( (c = *addrs++) == ',' || isspace(c))
179         ;
180     
181     *nxtout = *adrcopy = '\0';
182     while (state != EOA) {
183         *adrcopy++ = c;
184         if (state != COM)
185             *nxtout++ = (isalpha(c) && isupper (c)) ? tolower (c) : c;
186         switch (state+c) {
187
188         case NORMAL+'\n':       /* discard newlines */
189         case QS+'\n':
190         case COM+'\n':
191         case ERR+'\n':
192             --nxtout;
193             --adrcopy;
194             break;
195
196         case NORMAL+' ':        /* skip unquoted whitespace */
197         case NORMAL+'\t':
198             --nxtout;
199             break;
200
201         case NORMAL+'"':        /* start quoted string */
202             state = QS;
203             break;
204
205         case QS+'"':            /* end quoted string */
206             state = NORMAL;
207             break;
208
209         case NORMAL+'<':
210             nxtout = adr;       /* start over accumulating address */
211             lbcnt++;
212             break;
213
214         case NORMAL+'>':
215             --lbcnt;
216             if (lbcnt < 0) {
217                 state = ERR;
218                 err = "extra >";
219             } else
220                 *(nxtout-1) = '\0';
221             break;
222
223         case NORMAL+'(':
224             state = COM;
225             --nxtout;
226         case COM+'(':
227             lpcnt++;
228             break;
229
230         case COM+')':
231             --lpcnt;
232             if (lpcnt < 0) {
233                 state = ERR;
234                 err = "extra )";
235             } else if (lpcnt == 0)
236                 state = NORMAL;
237             break;
238
239         case NORMAL+'\\':
240         case QS+'\\':
241         case COM+'\\':
242             if ((c = *addrs++) == '\n' || c == '\0') {
243                 state = EOA;
244                 err = "illegal \\";
245             }
246             *adrcopy++ = c;
247             *nxtout++ = (isalpha(c) && isupper (c)) ? tolower (c) : c;
248             break;
249
250         case NORMAL+',':
251         case ERR+',':
252         case NORMAL+'\0':
253         case ERR+'\0':
254             state = EOA;
255             if (lbcnt)
256                 err = "missing >";
257             break;
258
259         case COM+'\0':
260             state = EOA;
261             err = "missing )";
262             if (nxtout == adr)
263                 nxtout++;
264             break;
265
266         case QS+'\0':
267             state = EOA;
268             err = "missing \"";
269             break;
270         }
271         if (c != '\0')
272             c = *addrs++;
273     }
274     /*
275      * at this point adr contains the `mailbox' part of the address
276      * in lower case & minus any comment or unquoted whitespace.
277      * adrtext contains an exact copy of the address and
278      * addr points to where we should start scanning next time.
279      */
280     *(nxtout-1) = *(adrcopy-1) = '\0';
281     if (*adr && !err) {
282         adr_ptr = addrs-1;
283         return adrtext;
284     } else {
285         free (saved_addr);
286         adr_ptr = NULL;
287         return NULL;
288     }
289 #else /* not BERK */
290     register struct adrx *ap;
291
292     pers = mbox = host = route = grp = note = NULL;
293     err[0] = '\0';
294
295     if ((ap = getadrx (addrs ? addrs : "")) == NULL)
296         return NULL;
297
298     (void) strcpy (adr, ap -> text);
299     pers = ap -> pers;
300     mbox = ap -> mbox;
301     host = ap -> host;
302     route = ap -> path;
303     grp = ap -> grp;
304     ingrp = ap -> ingrp;
305     note = ap -> note;
306     if (ap -> err && *ap -> err)
307         (void) strcpy (err, ap -> err);
308
309     return adr;
310 #endif /* not BERK */
311 }
312
313 /* \f */
314
315 #ifdef  BERK
316 /* ARGSUSED */
317 #endif /* BERK */
318
319 struct mailname *getm (str, dfhost, dftype, wanthost, eresult)
320 register char   *str,
321                 *eresult;
322 char   *dfhost;
323 int     dftype,
324         wanthost;
325 {
326 #ifndef BERK
327     register char   *pp;
328 #ifndef DUMB
329     register char   *dp;
330 #endif /* not DUMB */
331 #ifdef  MF
332     char   *up = UucpChan ();
333 #endif /* MF */
334 #endif /* not BERK */
335     register struct mailname *mp;
336
337     if (err && err[0]) {
338         if (eresult)
339             (void) strcpy (eresult, err);
340         else
341             if (wanthost == AD_HOST)
342                 admonish (NULLCP, "bad address '%s' - %s", str, err);
343         return NULL;
344     }
345 #ifdef  BERK
346     if (str == NULL || *str == '\0') {
347 #else /* not BERK */
348     if (pers == NULL
349             && mbox == NULL && host == NULL && route == NULL
350             && grp == NULL) {
351 #endif /* not BERK */
352         if (eresult)
353             (void) strcpy (eresult, "null address");
354         else
355             if (wanthost == AD_HOST)
356                 admonish (NULLCP, "null address '%s'", str);
357         return NULL;
358     }
359 #ifndef BERK
360     if (mbox == NULL && grp == NULL) {
361         if (eresult)
362             (void) strcpy (eresult, "no mailbox in address");
363         else
364             if (wanthost == AD_HOST)
365                 admonish (NULLCP, "no mailbox in address '%s'", str);
366         return NULL;
367     }
368
369     if (dfhost == NULL) {
370         dfhost = LocalName ();
371         dftype = LOCALHOST;
372     }
373 #endif /* not BERK */
374
375     mp = (struct mailname  *) calloc ((unsigned) 1, sizeof *mp);
376     if (mp == NULL) {
377         if (eresult)
378            (void) strcpy (eresult, "insufficient memory to represent address");
379         else
380             if (wanthost == AD_HOST)
381                 adios (NULLCP, "insufficient memory to represent address");
382         return NULL;
383     }
384
385     mp -> m_next = NULL;
386     mp -> m_text = getcpy (str);
387 #ifdef  BERK
388     mp -> m_type = LOCALHOST;
389     mp -> m_mbox = getcpy (adr);
390     if (!index (adr, '@') && !index (adr, '!'))
391         mp -> m_nohost = 1;
392 #else /* not BERK */
393     if (pers)
394         mp -> m_pers = getcpy (pers);
395
396     if (mbox == NULL) {
397         mp -> m_type = BADHOST;
398         mp -> m_nohost = 1;
399         mp -> m_ingrp = ingrp;
400         mp -> m_gname = getcpy (grp);
401         if (note)
402             mp -> m_note = getcpy (note);
403         return mp;
404     }
405
406 /* \f */
407
408     if (host) {
409 #ifdef MF
410 #ifdef  MMDFMTS
411         if (up && uleq (host, LocalName ())
412                 && (pp = rindex (mbox, '%'))
413                 && uleq (up, pp + 1)) {/* uucpaddr%<uucp>@<local> */
414             *pp = NULL;
415             goto get_uucp;
416         }
417 #else /* not MMDFMTS */
418         if (up && (pp = index (host, '.')) 
419                 && uleq (up, pp + 1)) {/* uucpaddr@host.<uucp> */
420             *pp = NULL;
421             mp -> m_host = getcpy (host);
422             mp -> m_mbox = getcpy (mbox);
423             mp -> m_type = UUCPHOST;
424             goto got_host;
425         }
426 #endif /* not MMDFMTS */
427         if (up && uleq (dfhost, LocalName ())
428                 && uleq (up, host)) {/* uucpaddr@<uucp> [local] */
429             if (pp = index (mbox, '!')) {
430                 *pp++ = NULL;
431                 mp -> m_host = getcpy (mbox);
432                 mp -> m_mbox = getcpy (pp);
433             }
434             else {
435                 mp -> m_host = getcpy (SystemName ());
436                 mp -> m_mbox = getcpy (mbox);
437             }
438             mp -> m_type = UUCPHOST;
439             goto got_host;
440         }
441 #endif /* MF */
442         mp -> m_mbox = getcpy (mbox);
443         mp -> m_host = getcpy (host);
444     }
445     else {
446         if (pp = index (mbox, '!')) {
447             *pp++ = '\0';
448             mp -> m_mbox = getcpy (pp);
449             mp -> m_host = getcpy (mbox);
450             mp -> m_type = UUCPHOST;
451         }
452         else {
453             mp -> m_nohost = 1;
454             mp -> m_mbox = getcpy (mbox);
455 #ifdef  DUMB
456             if (route == NULL && dftype == LOCALHOST) {
457                 mp -> m_host = NULLCP;
458                 mp -> m_type = dftype;
459             }
460             else
461 #endif /* DUMB */
462             {
463                 mp -> m_host = route ? NULLCP : getcpy (dfhost);
464                 mp -> m_type = route ? NETHOST : dftype;
465             }
466         }
467         goto got_host;
468     }
469
470 /* \f */
471
472     if (wanthost == AD_NHST)
473         mp -> m_type = uleq (LocalName (), mp -> m_host)
474             ? LOCALHOST : NETHOST;
475 #ifdef  DUMB
476     else
477         mp -> m_type = uleq (LocalName (), mp -> m_host) ? LOCALHOST
478                 : NETHOST;
479 #else /* not DUMB */
480     else
481         if (pp = OfficialName (mp -> m_host)) {
482     got_real_host: ;
483             free (mp -> m_host);
484             mp -> m_host = getcpy (pp);
485             mp -> m_type = uleq (LocalName (), mp -> m_host) ? LOCALHOST
486                     : NETHOST;
487         }
488         else {
489             if (dp = index (mp -> m_host, '.')) {
490                 *dp = NULL;
491                 if (pp = OfficialName (mp -> m_host))
492                     goto got_real_host;
493                 *dp = '.';
494             }
495             mp -> m_type = BADHOST;
496         }
497 #endif /* not DUMB */
498
499 got_host: ;
500     if (route)
501         mp -> m_path = getcpy (route);
502     mp -> m_ingrp = ingrp;
503     if (grp)
504         mp -> m_gname = getcpy (grp);
505     if (note)
506         mp -> m_note = getcpy (note);
507 #endif /* not BERK */
508
509     return mp;
510 }
511
512 /* \f */
513
514 void    mnfree (mp)
515 register struct mailname *mp;
516 {
517     if (!mp)
518         return;
519
520     if (mp -> m_text)
521         free (mp -> m_text);
522     if (mp -> m_pers)
523         free (mp -> m_pers);
524     if (mp -> m_mbox)
525         free (mp -> m_mbox);
526     if (mp -> m_host)
527         free (mp -> m_host);
528     if (mp -> m_path)
529         free (mp -> m_path);
530     if (mp -> m_gname)
531         free (mp -> m_gname);
532     if (mp -> m_note)
533         free (mp -> m_note);
534 #ifdef  MHMTS
535     if (mp -> m_aka)
536         free (mp -> m_aka);
537 #endif /* MHMTS */
538
539     free ((char *) mp);
540 }
541
542 /* \f */
543
544 char   *auxformat (mp, extras)
545 register struct mailname   *mp;
546 int     extras;
547 {
548 #ifndef BERK
549 #ifdef  MF
550     char   *up = UucpChan ();
551 #endif /* MF */
552     static char addr[BUFSIZ];
553 #endif /* not BERK */
554     static char buffer[BUFSIZ];
555
556 #ifdef  BERK
557     /* this "if" is a crufty hack to handle "visible" aliases */
558     if (mp->m_pers && !extras)
559         (void) sprintf (buffer, "%s <%s>", mp->m_pers, mp->m_mbox);
560     else
561         (void) strcpy (buffer, mp -> m_text);
562 #else /* not BERK */
563
564 #ifdef  MF
565     if (up && mp -> m_type == UUCPHOST)
566 #ifdef  MMDFMTS
567         (void) sprintf (addr, "%s!%s%%%s@%s", mp -> m_host, mp -> m_mbox,
568                 up, LocalName ());
569 #else /* not MMDFMTS */
570         (void) sprintf (addr, "%s@%s.%s", mp -> m_mbox, mp -> m_host, up);
571 #endif /* not MMDFMTS */
572     else 
573 #endif /* MF */
574
575 #ifdef  DUMB
576         if (mp -> m_nohost)
577             (void) strcpy (addr, mp -> m_mbox ? mp -> m_mbox : "");
578         else
579 #endif /* DUMB */
580
581 #ifndef BANG
582         if (mp -> m_type != UUCPHOST)
583             (void) sprintf (addr, mp -> m_host ? "%s%s@%s" : "%s%s",
584                 mp -> m_path ? mp -> m_path : "", mp -> m_mbox, mp -> m_host);
585         else
586 #endif /* not BANG */
587             (void) sprintf (addr, "%s!%s", mp -> m_host, mp -> m_mbox);
588
589     if (!extras)
590         return addr;
591
592     if (mp -> m_pers || mp -> m_path)
593         if (mp -> m_note)
594             (void) sprintf (buffer, "%s %s <%s>",
595                     legal_person (mp -> m_pers ? mp -> m_pers : mp -> m_mbox),
596                     mp -> m_note, addr);
597         else
598             (void) sprintf (buffer, "%s <%s>",
599                     legal_person (mp -> m_pers ? mp -> m_pers : mp -> m_mbox),
600                     addr);
601     else
602         if (mp -> m_note)
603             (void) sprintf (buffer, "%s %s", addr, mp -> m_note);
604         else
605             (void) strcpy (buffer, addr);
606 #endif /* not BERK */
607
608     return buffer;
609 }
610
611 /* \f */
612
613 #if     defined(BERK) || (defined(DUMB) && !defined(MMDFMTS) && !defined(SMTP))
614 #define REALLYDUMB
615 #else
616 #undef  REALLYDUMB
617 #endif
618
619 char   *adrsprintf (local, domain)
620 char   *local,
621        *domain;
622 {
623     static char addr[BUFSIZ];
624
625     if (local == NULL)
626 #ifdef  REALLYDUMB
627         return getusr ();
628     else
629 #endif /* REALLYDUMB */
630         local = getusr ();
631
632     if (domain == NULL)
633 #ifdef  REALLYDUMB
634         return local;
635     else
636 #endif /* REALLYDUMB */
637         domain = LocalName ();
638
639 #ifndef BANG
640     (void) sprintf (addr, "%s@%s", local, domain);
641 #else /* BANG */
642     (void) sprintf (addr, "%s!%s", domain, local);
643 #endif /* BANG */
644
645     return addr;
646 }
647
648 /* \f */
649
650 #define W_NIL   0x0000
651 #define W_MBEG  0x0001
652 #define W_MEND  0x0002
653 #define W_MBOX  (W_MBEG | W_MEND)
654 #define W_HBEG  0x0004
655 #define W_HEND  0x0008
656 #define W_HOST  (W_HBEG | W_HEND)
657 #define WBITS   "\020\01MBEG\02MEND\03HBEG\04HEND"
658
659
660 int     ismymbox (np)
661 register struct mailname *np;
662 {
663     int     oops;
664     register int    len,
665                     i;
666     register char  *cp;
667 #ifndef BERK
668     register char  *pp;
669     char    buffer[BUFSIZ];
670 #endif /* not BERK */
671     register struct mailname   *mp;
672     static char *am = NULL;
673     static struct mailname  mq={NULL};
674
675     /* if this is the first call, init. alternate mailboxes list */
676     if (am == NULL) {
677         mq.m_next = NULL;
678         mq.m_mbox = getusr ();
679         if ((am = m_find ("alternate-mailboxes")) == NULL)
680             am = getusr ();
681         else {
682             mp = &mq;
683             oops = 0;
684             while (cp = getname (am))
685                 if ((mp -> m_next = getm (cp, NULLCP, 0, AD_NAME, NULLCP))
686                         == NULL)
687                     admonish (NULLCP, "illegal address: %s", cp), oops++;
688                 else {
689                     mp = mp -> m_next;
690                     mp -> m_type = W_NIL;
691 #ifdef  BERK
692                     /* check for wildcards on the mailbox name and
693                        set m_type accordingly. */
694                     mp -> m_ingrp = strlen (mp -> m_mbox);
695                     if (*(mp -> m_mbox) == '*') {
696                         mp -> m_type |= W_MBEG;
697                         mp -> m_mbox++;
698                         --mp -> m_ingrp;
699                     }
700                     if (mp -> m_mbox[mp -> m_ingrp - 1] == '*') {
701                         mp -> m_type |= W_MEND;
702                         mp -> m_ingrp--;
703                         mp -> m_mbox[mp -> m_ingrp] = 0;
704                     }
705 #else /* not BERK */
706                     /* owing to screwy munging, wildcarding is a great idea
707                        even under #ifndef BERK, so... */
708                     mp -> m_type = W_NIL;
709                     if (*mp -> m_mbox == '*')
710                         mp -> m_type |= W_MBEG, mp -> m_mbox++;
711                     if (*(cp = mp -> m_mbox + strlen (mp -> m_mbox) - 1)
712                             == '*')
713                         mp -> m_type |= W_MEND, *cp = '\0';
714                     if (mp -> m_host) {
715                         if (*mp -> m_host == '*')
716                             mp -> m_type |= W_HBEG, mp -> m_host++;
717                         if (*(cp = mp -> m_host + strlen (mp -> m_host) - 1)
718                                 == '*')
719                             mp -> m_type |= W_HEND, *cp = '\0';
720                     }
721                     if ((cp = getenv ("MHWDEBUG")) && *cp)
722                         fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
723                             mp -> m_mbox, mp -> m_host,
724                             sprintb (buffer, (unsigned) mp -> m_type, WBITS));
725 #endif /* not BERK */
726                 }
727             if (oops)
728                 advise (NULLCP, "please fix the %s: entry in your %s file",
729                         "alternate-mailboxes", mh_profile);
730         }
731     }
732     if (np == NULL) /* XXX */
733         return 0;
734     
735 #ifdef  BERK
736     cp = np -> m_mbox;
737     if (strcmp (cp, mq.m_mbox) == 0)
738         return 1;
739 #else /* not BERK */
740     switch (np -> m_type) {
741         case NETHOST:
742             len = strlen (cp = LocalName ());
743             if (!uprf (np -> m_host, cp) || np -> m_host[len] != '.')
744                 break;
745             goto local_test;
746
747         case UUCPHOST:
748             if (!uleq (np -> m_host, SystemName ()))
749                 break;          /* fall */
750         case LOCALHOST:
751 local_test: ;
752             if (uleq (np -> m_mbox, mq.m_mbox))
753                 return 1;
754             break;
755
756         default:
757             break;
758     }
759 #endif /* not BERK */
760
761 #ifdef  BERK
762     len = strlen (cp);
763     for (mp = &mq; mp = mp -> m_next;)
764         if (len >= mp -> m_ingrp)
765             switch (mp -> m_type) {
766                 case W_NIL:     /* no wildcards */
767                     if (strcmp (cp, mp -> m_mbox) == 0)
768                         return 1;
769                     break;
770
771                 case W_MBEG:    /* wildcard at beginning */
772                     if (strcmp (&cp[len - mp -> m_ingrp], mp -> m_mbox) == 0)
773                         return 1;
774                     break;
775
776                 case W_MEND:    /* wildcard at end */
777                     if (strncmp (cp, mp -> m_mbox, mp -> m_ingrp) == 0)
778                         return 1;
779                     break;
780
781                 case W_MBEG | W_MEND: /* wildcard at beginning & end */
782                     for (i = 0; i <= len - mp -> m_ingrp; i++)
783                         if (strncmp (&cp[i], mp -> m_mbox, mp -> m_ingrp) == 0)
784                             return 1;
785             }
786 #else /* not BERK */
787     for (mp = &mq; mp = mp -> m_next;) {
788         if (np -> m_mbox == NULL)
789             continue;
790         if ((len = strlen (cp = np -> m_mbox))
791                 < (i = strlen (pp = mp -> m_mbox)))
792             continue;
793         switch (mp -> m_type & W_MBOX) {
794             case W_NIL: 
795                 if (!uleq (cp, pp))
796                     continue;
797                 break;
798             case W_MBEG: 
799                 if (!uleq (cp + len - i, pp))
800                     continue;
801                 break;
802             case W_MEND: 
803                 if (!uprf (cp, pp))
804                     continue;
805                 break;
806             case W_MBEG | W_MEND: 
807                 if (stringdex (pp, cp) < 0)
808                     continue;
809                 break;
810         }
811
812         if (mp -> m_nohost)
813             return 1;
814         if (np -> m_host == NULL)
815             continue;
816         if ((len = strlen (cp = np -> m_host))
817                 < (i = strlen (pp = mp -> m_host)))
818             continue;
819         switch (mp -> m_type & W_HOST) {
820             case W_NIL: 
821                 if (!uleq (cp, pp))
822                     continue;
823                 break;
824             case W_HBEG: 
825                 if (!uleq (cp + len - i, pp))
826                     continue;
827                 break;
828             case W_HEND: 
829                 if (!uprf (cp, pp))
830                     continue;
831                 break;
832             case W_HBEG | W_HEND: 
833                 if (stringdex (pp, cp) < 0)
834                     continue;
835                 break;
836         }
837         return 1;
838     }
839 #endif /* not BERK */
840
841     return 0;
842 }