9ed9ddd3635fcfd712de9fec4c71efe03df7238f
static char SccsId
[] = "@(#)parseaddr.c 3.6 %G%";
** PARSE -- Parse an address
** Parses an address and breaks it up into three parts: a
** net to transmit the message on, the host to transmit it
** to, and a user on that host. These are loaded into an
** ADDRESS header with the values squirreled away if necessary.
** The "user" part may not be a real user; the process may
** just reoccur on that machine. For example, on a machine
** with an arpanet connection, the address
** will break up to a "user" of 'csvax.bill' and a host
** of 'berkeley' -- to be transmitted over the arpanet.
** addr -- the address to parse.
** a -- a pointer to the address descriptor buffer.
** If NULL, a header will be created.
** copyf -- determines what shall be copied:
** -1 -- don't copy anything. The printname
** (q_paddr) is just addr, and the
** user & host are allocated internally
** 0 -- copy out the parsed user & host, but
** don't copy the printname.
** +1 -- copy everything.
** A pointer to the address descriptor header (`a' if
# define DELIMCHARS "$()<>@!.,;:\\\" \t\r\n" /* word delimiters */
# define SPACESUB ('.'|0200) /* substitution for <lwsp> */
register struct mailer
*m
;
extern ADDRESS
*buildaddr();
** Initialize and prescan address.
pvp
= prescan(addr
, '\0');
** Apply rewriting rules.
** See if we resolved to a real mailer.
if (pvp
[0][0] != CANONNET
)
usrerr("cannot resolve name");
** Build canonical address from pvp.
** Make local copies of the host & user and then
a
->q_paddr
= newstr(addr
);
a
->q_host
= newstr(a
->q_host
);
if (a
->q_user
!= a
->q_paddr
)
a
->q_user
= newstr(a
->q_user
);
** Do UPPER->lower case mapping unless inhibited.
if (!bitset(M_HST_UPPER
, m
->m_flags
))
if (!bitset(M_USR_UPPER
, m
->m_flags
))
printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n",
addr
, a
->q_host
, a
->q_user
, a
->q_mailer
);
** PRESCAN -- Prescan name and make it canonical
** Scans a name and turns it into canonical form. This involves
** deleting blanks, comments (in parentheses), and turning the
** word "at" into an at-sign ("@"). The name is copied as this
** is done; it is legal to copy a name onto itself, since this
** process can only make things smaller.
** This routine knows about quoted strings and angle brackets.
** There are certain subtleties to this routine. The one that
** comes to mind now is that backslashes on the ends of names
** are silently stripped off; this is intentional. The problem
** is that some versions of sndmsg (like at LBL) set the kill
** character to something other than @ when reading addresses;
** so people type "csvax.eric\@berkeley" -- which screws up the
** addr -- the name to chomp.
** delim -- the delimiter for the address, normally
** '\0' or ','; \0 is accepted in any case.
** are moving in place; set buflim to high core.
** A pointer to a vector of tokens.
static char buf
[MAXNAME
+MAXATOM
];
static char *av
[MAXATOM
+1];
for (p
= addr
; *p
!= '\0' && *p
!= delim
; )
while ((c
= *p
++) != '\0' && c
!= delim
)
/* chew up special characters */
case QSTRING
: /* in quoted string */
case ATOM
: /* regular atom */
case GETONE
: /* grab one character */
case EOTOK
: /* after atom or q-string */
case SPACE
: /* linear white space */
case OPER
: /* operator */
case DOLLAR
: /* $- etc. */
case '$': /* literal $ */
case '+': /* match anything */
case '-': /* match one token */
case '#': /* canonical net name */
case '@': /* canonical host name */
case ':': /* canonical user name */
syserr("prescan: unknown state %d", state
);
if (c
== '$' && delim
== '\t')
if (q
>= &buf
[sizeof buf
- 5])
usrerr("Address too long");
/* decide whether this represents end of token */
if (c
== '\0' || c
== delim
)
usrerr("Unbalanced ')'");
usrerr("multiple < spec");
/* we prefer using machine readable name */
usrerr("Unbalanced `>'");
** but only if "at" is a word.
if (lower(tok
[0]) == 'a' && lower(tok
[1]) == 't' && tok
[2] == '\0')
usrerr("Unbalanced '('");
usrerr("Unbalanced '<'");
else if (state
== QSTRING
)
usrerr("Unbalanced '\"'");
** TOKTYPE -- return token type
** c -- the character in question.
if (index(DELIMCHARS
, c
) != NULL
|| iscntrl(c
))
** REWRITE -- apply rewrite rules to token vector.
** pvp -- pointer to token vector.
char **firsttok
; /* first token matched */
char **lasttok
; /* last token matched */
char name
; /* name of parameter */
# define MAXMATCH 8 /* max params per rewrite */
register char *ap
; /* address pointer */
register char *rp
; /* rewrite pointer */
register char **avp
; /* address vector pointer */
register char **rvp
; /* rewrite vector pointer */
struct match mlist
[MAXMATCH
];
char *npvp
[MAXATOM
+1]; /* temporary space for rebuild */
printf("rewrite: original pvp:\n");
** Run through the list of rewrite rules, applying
for (rwr
= RewriteRules
; rwr
!= NULL
; )
printf("-----trying rule:\n");
/* try to match on this rule */
for (rvp
= rwr
->r_lhs
, avp
= pvp
; *avp
!= NULL
; )
/* end-of-pattern before end-of-address */
/* match exactly one token */
setmatch(mlist
, rp
[1], avp
, avp
);
/* match any number of tokens */
setmatch(mlist
, rp
[1], NULL
, avp
);
/* must have exact match */
/* can scribble rp & ap here safely */
while (*rp
!= '\0' && *ap
!= '\0')
if (*rp
++ != lower(*ap
++))
/* successful match on this token */
/* match failed -- back up */
while (--rvp
>= rwr
->r_lhs
)
/* can't extend match: back up everything */
setmatch(mlist
, rp
[1], NULL
, NULL
);
/* total failure to match */
** See if we successfully matched
if (rvp
>= rwr
->r_lhs
&& *rvp
== NULL
)
printf("-----rule matches:\n");
for (rvp
= rwr
->r_rhs
, avp
= npvp
; *rvp
!= NULL
; rvp
++)
register struct match
*m
;
extern struct match
*findmatch();
m
= findmatch(mlist
, rp
[1]);
} while (pp
++ != m
->lasttok
);
bmove(npvp
, pvp
, (avp
- npvp
) * sizeof *avp
);
printf("rewritten as:\n");
if (pvp
[0][0] == CANONNET
)
printf("----- rule fails\n");
** SETMATCH -- set parameter value in match vector
** mlist -- list of match values.
** name -- the character name of this parameter.
** first -- the first location of the replacement.
** last -- the last location of the replacement.
** If last == NULL, delete this entry.
** If first == NULL, extend this entry (or add it if
setmatch(mlist
, name
, first
, last
)
register struct match
*m
;
struct match
*nullm
= NULL
;
for (m
= mlist
; m
< &mlist
[MAXMATCH
]; m
++)
if (m
>= &mlist
[MAXMATCH
])
** FINDMATCH -- find match in mlist
** mlist -- list to search.
** pointer to match structure.
register struct match
*m
;
for (m
= mlist
; m
< &mlist
[MAXMATCH
]; m
++)
** CLRMATCH -- clear match list
** mlist -- list to clear.
register struct match
*m
;
for (m
= mlist
; m
< &mlist
[MAXMATCH
]; m
++)
** BUILDADDR -- build address from token vector.
** a -- pointer to address descriptor to fill.
** If NULL, one will be allocated.
static char buf
[MAXNAME
];
register struct mailer
*m
;
a
= (ADDRESS
*) xalloc(sizeof *a
);
/* figure out what net/mailer to use */
syserr("buildaddr: no net");
for (mp
= Mailer
, i
= 0; (m
= *mp
) != NULL
; m
++, i
++)
if (strcmp(m
->m_name
, *tv
) == 0)
syserr("buildaddr: unknown net %s", *tv
);
/* figure out what host (if any) */
if (!bitset(M_NOHOST
, m
->m_flags
))
syserr("buildaddr: no host");
/* figure out the user */
syserr("buildaddr: no user");