9 date 92.10.26.22.44.26; author jromine; state Exp;
14 date 92.05.12.22.10.48; author jromine; state Exp;
19 date 92.01.31.21.43.01; author jromine; state Exp;
24 date 92.01.30.22.39.48; author jromine; state Exp;
29 date 92.01.24.19.48.48; author jromine; state Exp;
34 date 92.01.24.17.58.41; author jromine; state Exp;
39 date 90.11.05.12.26.41; author mh; state Exp;
44 date 90.04.05.15.31.05; author sources; state Exp;
49 date 90.04.05.14.45.10; author sources; state Exp;
54 date 90.03.12.14.02.34; author sources; state Exp;
59 date 90.02.08.15.12.39; author sources; state Exp;
64 date 90.02.06.16.43.28; author sources; state Exp;
69 date 90.02.01.16.09.43; author sources; state Exp;
80 @use isupper with isascii
83 @/* addrsbr.c - parse addresses 822-style */
85 static char ident[] = "@@(#)$Id: addrsbr.c,v 1.12 1992/05/12 22:10:48 jromine Exp jromine $";
89 #include "../h/addrsbr.h"
90 #include "../zotnet/mf.h"
96 /* High level parsing of addresses:
98 The routines in zotnet/mf/mf.c parse the syntactic representations of
99 addresses. The routines in sbr/addrsbr.c associate semantics with those
102 If #ifdef BERK is in effect, the routines in mf.c aren't called and only
103 the most rudimentary syntax parse is done. The parse is not 822-conformant.
104 This causes problems as there is no semantics associated with the address
105 at all--it's just a string. (the author of the BERK code disagrees with
106 the preceding, of course. BERK solves problems for incoming mail
107 because it will accept damn near any address. BERK was intended to be
108 used when spost is the interface to the mail delivery system which means
109 all outgoing address interpretation is left to sendmail. It is possible,
110 though unlikely, for BERK address parsing to interact poorly with
111 "post". - van@@monet.berkeley.edu).
113 Instead, if #ifdef DUMB is in effect, a full 822-style parser is called
114 for syntax recongition. This breaks each address into its components.
115 Note however that no semantics are assumed about the parts or their
116 totality. This means that implicit hostnames aren't made explicit,
117 and explicit hostnames aren't expanded to their "official" represenations.
119 If neither BERK nor DUMB is in effect, then this module does some
120 high-level thinking about what the addresses are. If #ifdef MF is in
121 effect, then MH will deduce UUCP-style addressing masquerading as
126 string%<uucp>@@<local> -> string
128 2. for non-MMDF systems:
130 string@@host.<uucp> -> host!string
132 3. for any system, an address interpreted relative to the local host:
134 string@@<uucp> -> string
136 For cases (1) and (3) above, the leftmost host is extracted. If it's not
137 present, the local host is used. If #ifdef MF is not in effect or the
138 tests above fail, the address is considered to be a real 822-style address.
140 If an explicit host is not present, then MH checks for a bang to indicate
141 an explicit UUCP-style address. If so, this is noted. If not, the host is
142 defaulted, typically to the local host. The lack of an explict host is
145 If an explicit 822-style host is present, then MH checks to see if it
146 can expand this to the official name for the host. If the hostname is
147 unknown, the address is so typed.
149 To summarize, when we're all done, here's what MH knows about the address:
152 nohost: set if no '@@' or '!' in mailbox
153 text: exact copy of address
154 mbox: lowercase version of mailbox
156 DUMB - type: local, uucp, or network
157 host: not locally defaulted, not explicitly expanded
160 other - type: local, uucp, network, unknown
166 #if !defined(DUMB) && defined(SENDMTS) && !defined(BANG)
168 #define UucpChan() "UUCP"
172 static char *err = NULL;
173 static char adrtext[BUFSIZ];
175 static int ingrp = 0;
177 static char *pers = NULL;
178 static char *mbox = NULL;
179 static char *host = NULL;
180 static char *route = NULL;
181 static char *grp = NULL;
182 static char *note = NULL;
184 static char err[BUFSIZ];
185 #endif /* not BERK */
186 static char adr[BUFSIZ];
193 char *getname (addrs)
194 register char *addrs;
198 * Berkeley uses a very simple parser since Sendmail does all the work.
199 * The only thing that does address parsing if BERK is defined is the
200 * routine "ismybox" used by "scan" & "repl" to identify the current
203 * This routine does essentially the same address interpretation as the
204 * routine "prescan" in "sendmail". The intent is that MH should
205 * make minimum assumptions about address forms since it doesn't
206 * have access to the information in the sendmail config file
207 * (God forbid that anything but sendmail has to deal with a sendmail
208 * config file) and, therefore, hasn't the faintest idea of what will
209 * or won't be a legal address.
211 * Since this parse is only used by "ismybox" and repl, it just does
212 * two things: split multiple addr on a line into separate addresses and
213 * locate the "mailbox" portion of an address. The parse uses rfc-822
214 * metacharacters and quoting but is much less restrictive that rfc-822.
215 * In detail, `,' or eos terminate addresses. "Empty" addresses
216 * (e.g., `,,') are ignored. Double quote ("), backslash, left & right
217 * paren and left and right angle brackets are metacharacters. Left &
218 * right parens must balance as must left & right angle brackets. Any
219 * metacharacter may be escaped by preceding it with a backslash.
220 * Any text between parens is considered a comment and ignored (i.e.,
221 * only `(', `)' and `\' are metacharacters following a `('). Text
222 * between double quotes is considered escaped (i.e., only `"' and
223 * `\' are metacharacters following a `"'). The `mailbox' portion
224 * of an address is the non-comment text between angle-brackets if
225 * the address contains any angle brackets. Otherwise, it is all the
226 * non-comment text. Blanks, tabs & newlines will not be included
227 * in the mailbox portion of an address unless they are escaped.
231 #define NORMAL (0<<8)
232 #define QS (1<<8) /* in quoted string */
233 #define COM (2<<8) /* in comment (...) */
234 #define ERR (3<<8) /* found an error */
235 #define EOA (4<<8) /* end of address */
237 static char *saved_addr = NULL; /* saved address line ptr */
238 static char *adr_ptr = NULL; /* where to start looking for
239 next address on line */
240 register char *nxtout = adr; /* where to put next character of
241 `mailbox' part of address */
243 register int state = NORMAL;
244 register char *adrcopy = adrtext; /* where to put next character of
246 register int lbcnt = 0; /* number of unmatched "(" */
247 register int lpcnt = 0; /* number of unmatched "<" */
257 addrs = saved_addr = getcpy(addrs ? addrs : "");
259 /* skip any leading whitespace or commas. */
260 while ( (c = *addrs++) == ',' || isspace(c))
263 *nxtout = *adrcopy = '\0';
264 while (state != EOA) {
267 *nxtout++ = (isalpha(c) && isupper (c)) ? tolower (c) : c;
270 case NORMAL+'\n': /* discard newlines */
278 case NORMAL+' ': /* skip unquoted whitespace */
283 case NORMAL+'"': /* start quoted string */
287 case QS+'"': /* end quoted string */
292 nxtout = adr; /* start over accumulating address */
317 } else if (lpcnt == 0)
324 if ((c = *addrs++) == '\n' || c == '\0') {
329 *nxtout++ = (isalpha(c) && isupper (c)) ? tolower (c) : c;
357 * at this point adr contains the `mailbox' part of the address
358 * in lower case & minus any comment or unquoted whitespace.
359 * adrtext contains an exact copy of the address and
360 * addr points to where we should start scanning next time.
362 *(nxtout-1) = *(adrcopy-1) = '\0';
372 register struct adrx *ap;
374 pers = mbox = host = route = grp = note = NULL;
377 if ((ap = getadrx (addrs ? addrs : "")) == NULL)
380 (void) strcpy (adr, ap -> text);
388 if (ap -> err && *ap -> err)
389 (void) strcpy (err, ap -> err);
392 #endif /* not BERK */
401 struct mailname *getm (str, dfhost, dftype, wanthost, eresult)
412 #endif /* not DUMB */
414 char *up = UucpChan ();
416 #endif /* not BERK */
417 register struct mailname *mp;
421 (void) strcpy (eresult, err);
423 if (wanthost == AD_HOST)
424 admonish (NULLCP, "bad address '%s' - %s", str, err);
428 if (str == NULL || *str == '\0') {
431 && mbox == NULL && host == NULL && route == NULL
433 #endif /* not BERK */
435 (void) strcpy (eresult, "null address");
437 if (wanthost == AD_HOST)
438 admonish (NULLCP, "null address '%s'", str);
442 if (mbox == NULL && grp == NULL) {
444 (void) strcpy (eresult, "no mailbox in address");
446 if (wanthost == AD_HOST)
447 admonish (NULLCP, "no mailbox in address '%s'", str);
451 if (dfhost == NULL) {
452 dfhost = LocalName ();
455 #endif /* not BERK */
457 mp = (struct mailname *) calloc ((unsigned) 1, sizeof *mp);
460 (void) strcpy (eresult, "insufficient memory to represent address");
462 if (wanthost == AD_HOST)
463 adios (NULLCP, "insufficient memory to represent address");
468 mp -> m_text = getcpy (str);
470 mp -> m_type = LOCALHOST;
471 mp -> m_mbox = getcpy (adr);
472 if (!index (adr, '@@') && !index (adr, '!'))
476 mp -> m_pers = getcpy (pers);
479 mp -> m_type = BADHOST;
481 mp -> m_ingrp = ingrp;
482 mp -> m_gname = getcpy (grp);
484 mp -> m_note = getcpy (note);
493 if (up && uleq (host, LocalName ())
494 && (pp = rindex (mbox, '%'))
495 && uleq (up, pp + 1)) {/* uucpaddr%<uucp>@@<local> */
499 #else /* not MMDFMTS */
500 if (up && (pp = index (host, '.'))
501 && uleq (up, pp + 1)) {/* uucpaddr@@host.<uucp> */
503 mp -> m_host = getcpy (host);
504 mp -> m_mbox = getcpy (mbox);
505 mp -> m_type = UUCPHOST;
508 #endif /* not MMDFMTS */
509 if (up && uleq (dfhost, LocalName ())
510 && uleq (up, host)) {/* uucpaddr@@<uucp> [local] */
511 if (pp = index (mbox, '!')) {
513 mp -> m_host = getcpy (mbox);
514 mp -> m_mbox = getcpy (pp);
517 mp -> m_host = getcpy (SystemName ());
518 mp -> m_mbox = getcpy (mbox);
520 mp -> m_type = UUCPHOST;
524 mp -> m_mbox = getcpy (mbox);
525 mp -> m_host = getcpy (host);
528 if (pp = index (mbox, '!')) {
530 mp -> m_mbox = getcpy (pp);
531 mp -> m_host = getcpy (mbox);
532 mp -> m_type = UUCPHOST;
536 mp -> m_mbox = getcpy (mbox);
538 if (route == NULL && dftype == LOCALHOST) {
539 mp -> m_host = NULLCP;
540 mp -> m_type = dftype;
545 mp -> m_host = route ? NULLCP : getcpy (dfhost);
546 mp -> m_type = route ? NETHOST : dftype;
554 if (wanthost == AD_NHST)
555 mp -> m_type = uleq (LocalName (), mp -> m_host)
556 ? LOCALHOST : NETHOST;
559 mp -> m_type = uleq (LocalName (), mp -> m_host) ? LOCALHOST
563 if (pp = OfficialName (mp -> m_host)) {
566 mp -> m_host = getcpy (pp);
567 mp -> m_type = uleq (LocalName (), mp -> m_host) ? LOCALHOST
571 if (dp = index (mp -> m_host, '.')) {
573 if (pp = OfficialName (mp -> m_host))
577 mp -> m_type = BADHOST;
579 #endif /* not DUMB */
583 mp -> m_path = getcpy (route);
584 mp -> m_ingrp = ingrp;
586 mp -> m_gname = getcpy (grp);
588 mp -> m_note = getcpy (note);
589 #endif /* not BERK */
597 register struct mailname *mp;
613 free (mp -> m_gname);
626 char *auxformat (mp, extras)
627 register struct mailname *mp;
632 char *up = UucpChan ();
634 static char addr[BUFSIZ];
635 #endif /* not BERK */
636 static char buffer[BUFSIZ];
639 /* this "if" is a crufty hack to handle "visible" aliases */
640 if (mp->m_pers && !extras)
641 (void) sprintf (buffer, "%s <%s>", mp->m_pers, mp->m_mbox);
643 (void) strcpy (buffer, mp -> m_text);
647 if (up && mp -> m_type == UUCPHOST)
649 (void) sprintf (addr, "%s!%s%%%s@@%s", mp -> m_host, mp -> m_mbox,
651 #else /* not MMDFMTS */
652 (void) sprintf (addr, "%s@@%s.%s", mp -> m_mbox, mp -> m_host, up);
653 #endif /* not MMDFMTS */
659 (void) strcpy (addr, mp -> m_mbox ? mp -> m_mbox : "");
664 if (mp -> m_type != UUCPHOST)
665 (void) sprintf (addr, mp -> m_host ? "%s%s@@%s" : "%s%s",
666 mp -> m_path ? mp -> m_path : "", mp -> m_mbox, mp -> m_host);
668 #endif /* not BANG */
669 (void) sprintf (addr, "%s!%s", mp -> m_host, mp -> m_mbox);
674 if (mp -> m_pers || mp -> m_path)
676 (void) sprintf (buffer, "%s %s <%s>",
677 legal_person (mp -> m_pers ? mp -> m_pers : mp -> m_mbox),
680 (void) sprintf (buffer, "%s <%s>",
681 legal_person (mp -> m_pers ? mp -> m_pers : mp -> m_mbox),
685 (void) sprintf (buffer, "%s %s", addr, mp -> m_note);
687 (void) strcpy (buffer, addr);
688 #endif /* not BERK */
695 #if defined(BERK) || (defined(DUMB) && !defined(MMDFMTS) && !defined(SMTP))
701 char *adrsprintf (local, domain)
705 static char addr[BUFSIZ];
711 #endif /* REALLYDUMB */
718 #endif /* REALLYDUMB */
719 domain = LocalName ();
722 (void) sprintf (addr, "%s@@%s", local, domain);
724 (void) sprintf (addr, "%s!%s", domain, local);
733 #define W_MBEG 0x0001
734 #define W_MEND 0x0002
735 #define W_MBOX (W_MBEG | W_MEND)
736 #define W_HBEG 0x0004
737 #define W_HEND 0x0008
738 #define W_HOST (W_HBEG | W_HEND)
739 #define WBITS "\020\01MBEG\02MEND\03HBEG\04HEND"
743 register struct mailname *np;
752 #endif /* not BERK */
753 register struct mailname *mp;
754 static char *am = NULL;
755 static struct mailname mq={NULL};
757 /* if this is the first call, init. alternate mailboxes list */
760 mq.m_mbox = getusr ();
761 if ((am = m_find ("alternate-mailboxes")) == NULL)
766 while (cp = getname (am))
767 if ((mp -> m_next = getm (cp, NULLCP, 0, AD_NAME, NULLCP))
769 admonish (NULLCP, "illegal address: %s", cp), oops++;
772 mp -> m_type = W_NIL;
774 /* check for wildcards on the mailbox name and
775 set m_type accordingly. */
776 mp -> m_ingrp = strlen (mp -> m_mbox);
777 if (*(mp -> m_mbox) == '*') {
778 mp -> m_type |= W_MBEG;
782 if (mp -> m_mbox[mp -> m_ingrp - 1] == '*') {
783 mp -> m_type |= W_MEND;
785 mp -> m_mbox[mp -> m_ingrp] = 0;
788 /* owing to screwy munging, wildcarding is a great idea
789 even under #ifndef BERK, so... */
790 mp -> m_type = W_NIL;
791 if (*mp -> m_mbox == '*')
792 mp -> m_type |= W_MBEG, mp -> m_mbox++;
793 if (*(cp = mp -> m_mbox + strlen (mp -> m_mbox) - 1)
795 mp -> m_type |= W_MEND, *cp = '\0';
797 if (*mp -> m_host == '*')
798 mp -> m_type |= W_HBEG, mp -> m_host++;
799 if (*(cp = mp -> m_host + strlen (mp -> m_host) - 1)
801 mp -> m_type |= W_HEND, *cp = '\0';
803 if ((cp = getenv ("MHWDEBUG")) && *cp)
804 fprintf (stderr, "mbox=\"%s\" host=\"%s\" %s\n",
805 mp -> m_mbox, mp -> m_host,
806 sprintb (buffer, (unsigned) mp -> m_type, WBITS));
807 #endif /* not BERK */
810 advise (NULLCP, "please fix the %s: entry in your %s file",
811 "alternate-mailboxes", mh_profile);
814 if (np == NULL) /* XXX */
819 if (strcmp (cp, mq.m_mbox) == 0)
822 switch (np -> m_type) {
824 len = strlen (cp = LocalName ());
825 if (!uprf (np -> m_host, cp) || np -> m_host[len] != '.')
830 if (!uleq (np -> m_host, SystemName ()))
834 if (uleq (np -> m_mbox, mq.m_mbox))
841 #endif /* not BERK */
845 for (mp = &mq; mp = mp -> m_next;)
846 if (len >= mp -> m_ingrp)
847 switch (mp -> m_type) {
848 case W_NIL: /* no wildcards */
849 if (strcmp (cp, mp -> m_mbox) == 0)
853 case W_MBEG: /* wildcard at beginning */
854 if (strcmp (&cp[len - mp -> m_ingrp], mp -> m_mbox) == 0)
858 case W_MEND: /* wildcard at end */
859 if (strncmp (cp, mp -> m_mbox, mp -> m_ingrp) == 0)
863 case W_MBEG | W_MEND: /* wildcard at beginning & end */
864 for (i = 0; i <= len - mp -> m_ingrp; i++)
865 if (strncmp (&cp[i], mp -> m_mbox, mp -> m_ingrp) == 0)
869 for (mp = &mq; mp = mp -> m_next;) {
870 if (np -> m_mbox == NULL)
872 if ((len = strlen (cp = np -> m_mbox))
873 < (i = strlen (pp = mp -> m_mbox)))
875 switch (mp -> m_type & W_MBOX) {
881 if (!uleq (cp + len - i, pp))
888 case W_MBEG | W_MEND:
889 if (stringdex (pp, cp) < 0)
896 if (np -> m_host == NULL)
898 if ((len = strlen (cp = np -> m_host))
899 < (i = strlen (pp = mp -> m_host)))
901 switch (mp -> m_type & W_HOST) {
907 if (!uleq (cp + len - i, pp))
914 case W_HBEG | W_HEND:
915 if (stringdex (pp, cp) < 0)
921 #endif /* not BERK */
935 static char ident[] = "@@(#)$Id: addrsbr.c,v 1.11 1992/01/31 21:43:01 jromine Exp jromine $";
938 *nxtout++ = isupper (c) ? tolower (c) : c;
941 *nxtout++ = isupper (c) ? tolower (c) : c;
952 static char ident[] = "@@(#)$Id: addrsbr.c,v 1.10 1992/01/30 22:39:48 jromine Exp jromine $";
1071 mp -> m_type |= W_MEND, *cp = NULL;
1074 mp -> m_type |= W_HEND, *cp = NULL;
1100 static char ident[] = "@@(#)$Id: addrsbr.c,v 1.9 1992/01/24 19:48:48 jromine Exp jromine $";
1103 mp -> m_mbox[mp -> m_ingrp] = NULL;
1109 @do_wp gets set to zero by compiler
1114 static char ident[] = "@@(#)$Id: addrsbr.c,v 1.8 1992/01/24 17:58:41 jromine Exp jromine $";
1118 int do_wp; /* initialized to zero by compiler */
1127 if (do_wp && c == '<' && *addrs == '<') {
1132 if (cp = index (++addrs, '>')) {
1134 if (dp = wp_expand (addrs, NULLCP)) {
1135 *(addrs - 1) = NULL;
1136 ep = concat (saved_addr, dp, cp, NULLCP);
1137 addrs = ep + strlen (saved_addr);
1138 while ((c = *addrs++) == ',' || isspace (c))
1145 err = "unable to expand WhitePages query";
1146 (void) strcpy (adrtext, addrs);
1179 static char *fredproc = NULL;
1182 char *wp_expand (query, error)
1189 TYPESIG (*istat) (), (*qstat) (), (*pstat) ();
1196 static int child_id = NOTOK,
1201 (void) strcpy (error, "unable to expand WhitePages query: ");
1203 if (child_id == NOTOK || kill (child_id, 0) == NOTOK) {
1204 if (!isatty (fileno (stdout))) {
1206 (void) strcat (error, "not a tty");
1210 if (fredproc == NULL && (fredproc = m_find ("fredproc")) == NULL)
1213 if (pipe (pdi) == NOTOK) {
1215 (void) strcat (error, "unable to pipe");
1220 if (pipe (pdo) == NOTOK) {
1222 (void) strcat (error, "unable to pipe");
1225 (void) close (pdi[0]);
1226 (void) close (pdi[1]);
1230 for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
1236 (void) strcat (error, "unable to fork");
1238 (void) close (pdo[0]);
1239 (void) close (pdo[1]);
1243 (void) close (pdi[0]);
1244 (void) close (pdo[1]);
1245 (void) sprintf (fds, "%d %d", pdo[0], pdi[1]);
1247 vec[vecp++] = r1bindex (fredproc, '/');
1251 execvp (fredproc, vec);
1252 _exit (-1); /* NOTREACHED */
1255 (void) close (pdi[1]);
1256 (void) close (pdo[0]);
1261 istat = signal (SIGINT, SIG_IGN);
1262 qstat = signal (SIGQUIT, SIG_IGN);
1264 pstat = signal (SIGPIPE, SIG_IGN);
1266 (void) sprintf (buffer, "%s\n", query);
1267 cc = write (pdo[1], buffer, i = strlen (buffer));
1269 (void) signal (SIGPIPE, pstat);
1273 (void) strcat (error, "write to pipe failed");
1276 (void) kill (child_id, SIGTERM);
1277 (void) close (pdi[0]);
1278 (void) close (pdo[1]);
1284 for (ep = (bp = buffer) + sizeof buffer - 1;
1285 (i = read (pdi[0], bp, ep - bp)) > 0; ) {
1286 for (cp = bp + i; bp < cp; bp++)
1293 (void) signal (SIGINT, istat);
1294 (void) signal (SIGQUIT, qstat);
1298 (void) strcat (error, "read from pipe failed");
1303 (void) sprintf (error + strlen (error), "%s exited prematurely",
1313 (void) strcpy (error, "unable to expand WhitePages query");
1315 return (*buffer ? getcpy (buffer) : NULLCP);
1323 @extern do_wp for shared libs
1328 static char ident[] = "@@(#)$Id: addrsbr.c,v 1.7 1990/11/05 12:26:41 mh Exp jromine $";
1331 extern int do_wp; /* initialized to zero in sbr/addrdef.c */
1337 @fix from Kathleen Sullivan <sullivan@@venera.isi.edu>
1342 static char ident[] = "@@(#)$Id: addrsbr.c,v 1.6 90/04/05 15:31:05 sources Exp Locker: mh $";
1356 static char ident[] = "@@(#)$Id:$";
1369 static char ident[] = "$Id:";
1384 @don't consider newline part of mbox -- Van Jacobson fix
1389 int (*istat) (), (*qstat) (), (*pstat) ();
1400 * In detail, `,' or newline terminate addresses. "Empty" addresses
1403 * non-comment text. Blanks & tabs will not be included in the mailbox
1404 * portion of an address unless they are escaped.