Sync usage with man page.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / smtpd / smtpd_token.c
blob1e1badcf95b911cd20872290763b169a176d3588
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* smtpd_token 3
6 /* SUMMARY
7 /* tokenize SMTPD command
8 /* SYNOPSIS
9 /* #include <smtpd_token.h>
11 /* typedef struct {
12 /* .in +4
13 /* int tokval;
14 /* char *strval;
15 /* /* other stuff... */
16 /* .in -4
17 /* } SMTPD_TOKEN;
19 /* int smtpd_token(str, argvp)
20 /* char *str;
21 /* SMTPD_TOKEN **argvp;
22 /* DESCRIPTION
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.
27 /* Token types:
28 /* .IP SMTPD_TOK_OTHER
29 /* The token is something else.
30 /* .IP SMTPD_TOK_ERROR
31 /* A malformed token.
32 /* BUGS
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.
38 /* LICENSE
39 /* .ad
40 /* .fi
41 /* The Secure Mailer license must be distributed with this software.
42 /* AUTHOR(S)
43 /* Wietse Venema
44 /* IBM T.J. Watson Research
45 /* P.O. Box 704
46 /* Yorktown Heights, NY 10598, USA
47 /*--*/
49 /* System library. */
51 #include <sys_defs.h>
52 #include <ctype.h>
53 #include <string.h>
54 #include <unistd.h>
56 #ifdef STRCASECMP_IN_STRINGS_H
57 #include <strings.h>
58 #endif
60 /* Utility library. */
62 #include <mymalloc.h>
63 #include <mvect.h>
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;
74 int wanted;
75 int c;
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]; \
86 if (stack == 0)
87 stack = vstring_alloc(1);
88 VSTRING_RESET(stack);
89 ENTER_CHAR(stack, wanted = last);
91 VSTRING_ADDCH(arg->vstrval, start);
92 for (;;) {
93 if ((c = *cp) == 0)
94 break;
95 cp++;
96 VSTRING_ADDCH(arg->vstrval, c);
97 if (c == '\\') { /* parse escape sequence */
98 if ((c = *cp) == 0)
99 break;
100 cp++;
101 VSTRING_ADDCH(arg->vstrval, c);
102 } else if (c == wanted) { /* closing quote etc. */
103 if (VSTRING_LEN(stack) == 1)
104 return (cp);
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 */
113 return (cp);
116 /* smtp_next_token - extract next token from input, update cp */
118 static char *smtp_next_token(char *cp, SMTPD_TOKEN *arg)
120 int c;
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)
129 for (;;) {
130 if ((c = *cp) == 0) /* end of input */
131 break;
132 cp++;
133 if (ISSPACE(c)) { /* whitespace, skip */
134 while (*cp && ISSPACE(*cp))
135 cp++;
136 if (LEN(arg->vstrval) > 0) /* end of token */
137 break;
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)))
146 break;
147 } else { /* other */
148 if (c == '\\') {
149 VSTRING_ADDCH(arg->vstrval, c);
150 if ((c = *cp) == 0)
151 break;
152 cp++;
154 VSTRING_ADDCH(arg->vstrval, c);
157 if (LEN(arg->vstrval) <= 0) /* no token found */
158 return (0);
159 VSTRING_TERMINATE(arg->vstrval);
160 arg->strval = vstring_str(arg->vstrval);
161 return (cp);
164 /* smtpd_token_init - initialize token structures */
166 static void smtpd_token_init(char *ptr, int count)
168 SMTPD_TOKEN *arg;
169 int n;
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;
180 static MVECT mvect;
181 int n;
183 if (smtp_argv == 0)
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)
189 break;
191 *argvp = smtp_argv;
192 return (n);
195 #ifdef TEST
198 * Test program for the SMTPD command tokenizer.
201 #include <stdlib.h>
202 #include <vstream.h>
203 #include <vstring_vstream.h>
205 int main(int unused_argc, char **unused_argv)
207 VSTRING *vp = vstring_alloc(10);
208 int tok_argc;
209 SMTPD_TOKEN *tok_argv;
210 int i;
212 for (;;) {
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)
217 break;
218 if (*vstring_str(vp) == '#')
219 continue;
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" :
227 "unknown");
228 vstream_printf("Token value: %s\n", tok_argv[i].strval);
231 vstring_free(vp);
232 exit(0);
235 #endif