static char SccsId
[] = "@(#)parseaddr.c 3.15 %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 "$()<>,;\\\"\r\n" /* word delimiters */
# define SPACESUB ('.'|0200) /* substitution for <lwsp> */
register struct mailer
*m
;
extern ADDRESS
*buildaddr();
** Initialize and prescan address.
printf("\n--parse(%s)\n", addr
);
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 '=': /* match one token of class */
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.
static bool firstime
= TRUE
;
expand("$o", buf
, &buf
[sizeof buf
- 1]);
if (iscntrl(c
) || index(buf
, c
) != NULL
)
** 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
[ruleset
]; 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
);
/* match any token in a class */
if (s
== NULL
|| (s
->s_class
& (1 << class)) == 0)
/* must have exact match */
/* 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 `");
for (vp
= pvp
; *vp
!= NULL
; vp
++)
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
; 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");
** SAMEADDR -- Determine if two addresses are the same
** This is not just a straight comparison -- if the mailer doesn't
** care about the host we just ignore it, etc.
** a, b -- pointers to the internal forms to compare.
** wildflg -- if TRUE, 'a' may have no user specified,
** in which case it is to match anything.
** TRUE -- they represent the same mailbox.
/* if they don't have the same mailer, forget it */
if (a
->q_mailer
!= b
->q_mailer
)
/* if the user isn't the same, we can drop out */
if ((!wildflg
|| a
->q_user
[0] != '\0') && strcmp(a
->q_user
, b
->q_user
) != 0)
/* if the mailer ignores hosts, we have succeeded! */
if (bitset(M_NOHOST
, Mailer
[a
->q_mailer
]->m_flags
))
/* otherwise compare hosts (but be careful for NULL ptrs) */
if (a
->q_host
== NULL
|| b
->q_host
== NULL
)
if (strcmp(a
->q_host
, b
->q_host
) != 0)
** PRINTADDR -- print address (for debugging)
** a -- the address to print
** follow -- follow the q_next chain.
printf("%s: mailer %d (%s), host `%s', user `%s'\n", a
->q_paddr
,
a
->q_mailer
, Mailer
[a
->q_mailer
]->m_name
, a
->q_host
, a
->q_user
);
printf("\tnext=%x flags=%o, rmailer %d\n", a
->q_next
,
a
->q_flags
, a
->q_rmailer
);