static char SccsId
[] = "@(#)parse.c 1.7 10/21/80";
** 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
** addrq 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
register struct parsetab
*t
;
extern struct parsetab ParseTab
[];
static char buf
[MAXNAME
];
** Initialize and prescan address.
if (prescan(addr
, buf
, &buf
[sizeof buf
], '\0') == NULL
)
** Look for the first entry designating a character
** that is contained in the address.
** Arrange for q to point to that character.
** Check to see that there is only one of the char
** Find the last one if the host is on the RHS.
** Insist that the host name is atomic.
** If just doing a map, do the map and then start all
for (t
= ParseTab
; t
->p_char
!= '\0'; t
++)
for (p
= buf
; (c
= *p
) != '\0'; p
++)
/* find the end of this token */
while (isalnum(c
) || c
== '-' || c
== '_')
/* do mapping as appropriate */
if (flagset(P_MAP
, t
->p_flags
))
if (flagset(P_ONE
, t
->p_flags
))
/* arrange for q to point to it */
if (q
!= NULL
&& flagset(P_ONE
, t
->p_flags
))
usrerr("multichar error");
if (q
== NULL
|| flagset(P_HLAST
, t
->p_flags
))
/* insist that host name is atomic */
if (flagset(P_HLAST
, t
->p_flags
))
** If we matched nothing cleanly, but we did match something
** somewhere in the process of scanning, then we have a
** syntax error. This can happen on things like a@b:c where
** @ has a right host and : has a left host.
** We also set `q' to the null string, in case someone forgets
** to put the P_MOVE bit in the local mailer entry of the
** t points to the entry for the mailer we will use.
** q points to the significant character.
a
= (addrq
*) xalloc(sizeof *a
);
p
= xalloc((unsigned) strlen(addr
) + 1);
a
->q_mailer
= &Mailer
[t
->p_mailer
];
if (flagset(P_MOVE
, t
->p_flags
))
/* send the message to another host & retry */
p
= xalloc((unsigned) strlen(buf
) + 1);
** Make local copies of the host & user and then
if (flagset(P_HLAST
, t
->p_flags
))
** Don't go to the net if already on the target host.
** This is important on the berkeley network, since
** it get confused if we ask to send to ourselves.
** For nets like the ARPANET, we probably will have
** the local list set to NULL to simplify testing.
** The canonical representation of the name is also set
** to be just the local name so the duplicate letter
** suppression algorithm will work.
if ((pvp
= a
->q_mailer
->m_local
) != NULL
)
if (!flagset(P_HST_UPPER
, t
->p_flags
))
if (strcmp(*pvp
++, buf2
) == 0)
if (parse(buf2
, a
, -1) == NULL
)
/* make copies if specified */
p
= xalloc((unsigned) strlen(a
->q_host
) + 1);
p
= xalloc((unsigned) strlen(a
->q_user
) + 1);
** Do UPPER->lower case mapping unless inhibited.
if (!flagset(P_HST_UPPER
, t
->p_flags
))
if (!flagset(P_USR_UPPER
, t
->p_flags
))
printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n",
addr
, a
->q_host
, a
->q_user
, t
->p_mailer
);
** MAKELOWER -- Translate a line into lower case
** p -- the string to translate. If NULL, return is
** String pointed to by p is translated to lower case.
for (; (c
= *p
) != '\0'; p
++)
if ((c
& 0200) == 0 && isupper(c
))
** 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.
** buf -- the buffer to copy it into.
** buflim -- the last usable address in the buffer
** (which will old a null byte). Normally
** 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 the terminator of buf.
prescan(addr
, buf
, buflim
, delim
)
bslashmode
= quotemode
= FALSE
;
for (p
= addr
; (c
= *p
++) != '\0'; )
/* chew up special characters */
usrerr("Unbalanced ')'");
/* we prefer using machine readable name */
usrerr("Unbalanced `>'");
** but only if "at" is a word.
** By the way, I violate the ARPANET RFC-733
** standard here, by assuming that 'space' delimits
** atoms. I assume that is just a mistake, since
** it violates the spirit of the semantics
if (space
&& (c
== 'a' || c
== 'A') &&
(p
[0] == 't' || p
[0] == 'T') &&
(any(p
[1], "()<>@,;:\\\"") || p
[1] <= 040))
if (((c
& 0200) != 0 || !isspace(c
)) && cmntcnt
<= 0)
usrerr("Address too long");
usrerr("Unbalanced '('");
usrerr("Unbalanced '\"'");
usrerr("Unbalanced '<'");