7 /* tokenize SMTPD command
9 /* #include <smtpd_token.h>
15 /* /* other stuff... */
19 /* int smtpd_token(str, argvp)
21 /* SMTPD_TOKEN **argvp;
23 /* smtpd_token() routine converts the string in \fIstr\fR to an
24 /* array of tokens in \fIargvp\fR. The number of tokens is returned
25 /* via the function return value.
28 /* .IP SMTPD_TOK_OTHER
29 /* The token is something else.
30 /* .IP SMTPD_TOK_ERROR
33 /* This tokenizer understands just enough to tokenize SMTPD commands.
34 /* It understands backslash escapes, white space, quoted strings,
35 /* and addresses (including quoted text) enclosed by < and >.
36 /* The input is broken up into tokens by whitespace, except for
37 /* whitespace that is protected by quotes etc.
41 /* The Secure Mailer license must be distributed with this software.
44 /* IBM T.J. Watson Research
46 /* Yorktown Heights, NY 10598, USA
56 #ifdef STRCASECMP_IN_STRINGS_H
60 /* Utility library. */
65 /* Application-specific. */
67 #include "smtpd_token.h"
69 /* smtp_quoted - read until closing quote */
71 static char *smtp_quoted(char *cp
, SMTPD_TOKEN
*arg
, int start
, int last
)
73 static VSTRING
*stack
;
78 * Parser stack. `ch' is always the most-recently entered character.
80 #define ENTER_CHAR(buf, ch) VSTRING_ADDCH(buf, ch);
81 #define LEAVE_CHAR(buf, ch) { \
82 vstring_truncate(buf, VSTRING_LEN(buf) - 1); \
83 ch = vstring_end(buf)[-1]; \
87 stack
= vstring_alloc(1);
89 ENTER_CHAR(stack
, wanted
= last
);
91 VSTRING_ADDCH(arg
->vstrval
, start
);
96 VSTRING_ADDCH(arg
->vstrval
, c
);
97 if (c
== '\\') { /* parse escape sequence */
101 VSTRING_ADDCH(arg
->vstrval
, c
);
102 } else if (c
== wanted
) { /* closing quote etc. */
103 if (VSTRING_LEN(stack
) == 1)
105 LEAVE_CHAR(stack
, wanted
);
106 } else if (c
== '"') {
107 ENTER_CHAR(stack
, wanted
= '"'); /* highest precedence */
108 } else if (c
== '<' && wanted
== '>') {
109 ENTER_CHAR(stack
, wanted
= '>'); /* lowest precedence */
112 arg
->tokval
= SMTPD_TOK_ERROR
; /* missing end */
116 /* smtp_next_token - extract next token from input, update cp */
118 static char *smtp_next_token(char *cp
, SMTPD_TOKEN
*arg
)
122 VSTRING_RESET(arg
->vstrval
);
123 arg
->tokval
= SMTPD_TOK_OTHER
;
125 #define STR(x) vstring_str(x)
126 #define LEN(x) VSTRING_LEN(x)
127 #define STREQ(x,y,l) (strncasecmp((x), (y), (l)) == 0)
130 if ((c
= *cp
) == 0) /* end of input */
133 if (ISSPACE(c
)) { /* whitespace, skip */
134 while (*cp
&& ISSPACE(*cp
))
136 if (LEN(arg
->vstrval
) > 0) /* end of token */
138 } else if (c
== '<') { /* <stuff> */
139 cp
= smtp_quoted(cp
, arg
, c
, '>');
140 } else if (c
== '"') { /* "stuff" */
141 cp
= smtp_quoted(cp
, arg
, c
, c
);
142 } else if (c
== ':') { /* this is gross, but... */
143 VSTRING_ADDCH(arg
->vstrval
, c
);
144 if (STREQ(STR(arg
->vstrval
), "to:", LEN(arg
->vstrval
))
145 || STREQ(STR(arg
->vstrval
), "from:", LEN(arg
->vstrval
)))
149 VSTRING_ADDCH(arg
->vstrval
, c
);
154 VSTRING_ADDCH(arg
->vstrval
, c
);
157 if (LEN(arg
->vstrval
) <= 0) /* no token found */
159 VSTRING_TERMINATE(arg
->vstrval
);
160 arg
->strval
= vstring_str(arg
->vstrval
);
164 /* smtpd_token_init - initialize token structures */
166 static void smtpd_token_init(char *ptr
, int count
)
171 for (arg
= (SMTPD_TOKEN
*) ptr
, n
= 0; n
< count
; arg
++, n
++)
172 arg
->vstrval
= vstring_alloc(10);
175 /* smtpd_token - tokenize SMTPD command */
177 int smtpd_token(char *cp
, SMTPD_TOKEN
**argvp
)
179 static SMTPD_TOKEN
*smtp_argv
;
184 smtp_argv
= (SMTPD_TOKEN
*) mvect_alloc(&mvect
, sizeof(*smtp_argv
), 1,
185 smtpd_token_init
, (MVECT_FN
) 0);
186 for (n
= 0; /* void */ ; n
++) {
187 smtp_argv
= (SMTPD_TOKEN
*) mvect_realloc(&mvect
, n
+ 1);
188 if ((cp
= smtp_next_token(cp
, smtp_argv
+ n
)) == 0)
198 * Test program for the SMTPD command tokenizer.
203 #include <vstring_vstream.h>
205 int main(int unused_argc
, char **unused_argv
)
207 VSTRING
*vp
= vstring_alloc(10);
209 SMTPD_TOKEN
*tok_argv
;
213 if (isatty(STDIN_FILENO
))
214 vstream_printf("enter SMTPD command: ");
215 vstream_fflush(VSTREAM_OUT
);
216 if (vstring_get_nonl(vp
, VSTREAM_IN
) == VSTREAM_EOF
)
218 if (*vstring_str(vp
) == '#')
220 if (!isatty(STDIN_FILENO
))
221 vstream_printf("%s\n", vstring_str(vp
));
222 tok_argc
= smtpd_token(vstring_str(vp
), &tok_argv
);
223 for (i
= 0; i
< tok_argc
; i
++) {
224 vstream_printf("Token type: %s\n",
225 tok_argv
[i
].tokval
== SMTPD_TOK_OTHER
? "other" :
226 tok_argv
[i
].tokval
== SMTPD_TOK_ERROR
? "error" :
228 vstream_printf("Token value: %s\n", tok_argv
[i
].strval
);