#include <sys_defs.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <mymalloc.h>
#include <mvect.h>
#include "smtpd_token.h"
static char *smtp_quoted(char *cp, SMTPD_TOKEN *arg, int start, int last)
{
static VSTRING *stack;
int wanted;
int c;
#define ENTER_CHAR(buf, ch) VSTRING_ADDCH(buf, ch);
#define LEAVE_CHAR(buf, ch) { \
vstring_truncate(buf, VSTRING_LEN(buf) - 1); \
ch = vstring_end(buf)[-1]; \
}
if (stack == 0)
stack = vstring_alloc(1);
VSTRING_RESET(stack);
ENTER_CHAR(stack, wanted = last);
VSTRING_ADDCH(arg->vstrval, start);
for (;;) {
if ((c = *cp) == 0)
break;
cp++;
VSTRING_ADDCH(arg->vstrval, c);
if (c == '\\') {
if ((c = *cp) == 0)
break;
cp++;
VSTRING_ADDCH(arg->vstrval, c);
} else if (c == wanted) {
if (VSTRING_LEN(stack) == 1)
return (cp);
LEAVE_CHAR(stack, wanted);
} else if (c == '"') {
ENTER_CHAR(stack, wanted = '"');
} else if (c == '<' && wanted == '>') {
ENTER_CHAR(stack, wanted = '>');
}
}
arg->tokval = SMTPD_TOK_ERROR;
return (cp);
}
static char *smtp_next_token(char *cp, SMTPD_TOKEN *arg)
{
int c;
VSTRING_RESET(arg->vstrval);
arg->tokval = SMTPD_TOK_OTHER;
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
#define STREQ(x,y,l) (strncasecmp((x), (y), (l)) == 0)
for (;;) {
if ((c = *cp) == 0)
break;
cp++;
if (ISSPACE(c)) {
while (*cp && ISSPACE(*cp))
cp++;
if (LEN(arg->vstrval) > 0)
break;
} else if (c == '<') {
cp = smtp_quoted(cp, arg, c, '>');
} else if (c == '"') {
cp = smtp_quoted(cp, arg, c, c);
} else if (c == ':') {
VSTRING_ADDCH(arg->vstrval, c);
if (STREQ(STR(arg->vstrval), "to:", LEN(arg->vstrval))
|| STREQ(STR(arg->vstrval), "from:", LEN(arg->vstrval)))
break;
} else {
if (c == '\\') {
VSTRING_ADDCH(arg->vstrval, c);
if ((c = *cp) == 0)
break;
cp++;
}
VSTRING_ADDCH(arg->vstrval, c);
}
}
if (LEN(arg->vstrval) <= 0)
return (0);
VSTRING_TERMINATE(arg->vstrval);
arg->strval = vstring_str(arg->vstrval);
return (cp);
}
static void smtpd_token_init(char *ptr, int count)
{
SMTPD_TOKEN *arg;
int n;
for (arg = (SMTPD_TOKEN *) ptr, n = 0; n < count; arg++, n++)
arg->vstrval = vstring_alloc(10);
}
int smtpd_token(char *cp, SMTPD_TOKEN **argvp)
{
static SMTPD_TOKEN *smtp_argv;
static MVECT mvect;
int n;
if (smtp_argv == 0)
smtp_argv = (SMTPD_TOKEN *) mvect_alloc(&mvect, sizeof(*smtp_argv), 1,
smtpd_token_init, (MVECT_FN) 0);
for (n = 0; ; n++) {
smtp_argv = (SMTPD_TOKEN *) mvect_realloc(&mvect, n + 1);
if ((cp = smtp_next_token(cp, smtp_argv + n)) == 0)
break;
}
*argvp = smtp_argv;
return (n);
}
#ifdef TEST
#include <stdlib.h>
#include <vstream.h>
#include <vstring_vstream.h>
int main(int unused_argc, char **unused_argv)
{
VSTRING *vp = vstring_alloc(10);
int tok_argc;
SMTPD_TOKEN *tok_argv;
int i;
for (;;) {
if (isatty(STDIN_FILENO))
vstream_printf("enter SMTPD command: ");
vstream_fflush(VSTREAM_OUT);
if (vstring_get_nonl(vp, VSTREAM_IN) == VSTREAM_EOF)
break;
if (*vstring_str(vp) == '#')
continue;
if (!isatty(STDIN_FILENO))
vstream_printf("%s\n", vstring_str(vp));
tok_argc = smtpd_token(vstring_str(vp), &tok_argv);
for (i = 0; i < tok_argc; i++) {
vstream_printf("Token type: %s\n",
tok_argv[i].tokval == SMTPD_TOK_OTHER ? "other" :
tok_argv[i].tokval == SMTPD_TOK_ERROR ? "error" :
"unknown");
vstream_printf("Token value: %s\n", tok_argv[i].strval);
}
}
exit(0);
}
#endif