Postfix3.3.1
smtpd_token.c
[詳解]
1 /*++
2 /* NAME
3 /* smtpd_token 3
4 /* SUMMARY
5 /* tokenize SMTPD command
6 /* SYNOPSIS
7 /* #include <smtpd_token.h>
8 /*
9 /* typedef struct {
10 /* .in +4
11 /* int tokval;
12 /* char *strval;
13 /* /* other stuff... */
14 /* .in -4
15 /* } SMTPD_TOKEN;
16 /*
17 /* int smtpd_token(str, argvp)
18 /* char *str;
19 /* SMTPD_TOKEN **argvp;
20 /* DESCRIPTION
21 /* smtpd_token() routine converts the string in \fIstr\fR to an
22 /* array of tokens in \fIargvp\fR. The number of tokens is returned
23 /* via the function return value.
24 /*
25 /* Token types:
26 /* .IP SMTPD_TOK_OTHER
27 /* The token is something else.
28 /* .IP SMTPD_TOK_ERROR
29 /* A malformed token.
30 /* BUGS
31 /* This tokenizer understands just enough to tokenize SMTPD commands.
32 /* It understands backslash escapes, white space, quoted strings,
33 /* and addresses (including quoted text) enclosed by < and >.
34 /* The input is broken up into tokens by whitespace, except for
35 /* whitespace that is protected by quotes etc.
36 /* LICENSE
37 /* .ad
38 /* .fi
39 /* The Secure Mailer license must be distributed with this software.
40 /* AUTHOR(S)
41 /* Wietse Venema
42 /* IBM T.J. Watson Research
43 /* P.O. Box 704
44 /* Yorktown Heights, NY 10598, USA
45 /*--*/
46 
47 /* System library. */
48 
49 #include <sys_defs.h>
50 #include <ctype.h>
51 #include <string.h>
52 #include <unistd.h>
53 
54 #ifdef STRCASECMP_IN_STRINGS_H
55 #include <strings.h>
56 #endif
57 
58 /* Utility library. */
59 
60 #include <mymalloc.h>
61 #include <mvect.h>
62 
63 /* Application-specific. */
64 
65 #include "smtpd_token.h"
66 
67 /* smtp_quoted - read until closing quote */
68 
69 static char *smtp_quoted(char *cp, SMTPD_TOKEN *arg, int start, int last)
70 {
71  static VSTRING *stack;
72  int wanted;
73  int c;
74 
75  /*
76  * Parser stack. `ch' is always the most-recently entered character.
77  */
78 #define ENTER_CHAR(buf, ch) VSTRING_ADDCH(buf, ch);
79 #define LEAVE_CHAR(buf, ch) { \
80  vstring_truncate(buf, VSTRING_LEN(buf) - 1); \
81  ch = vstring_end(buf)[-1]; \
82  }
83 
84  if (stack == 0)
85  stack = vstring_alloc(1);
86  VSTRING_RESET(stack);
87  ENTER_CHAR(stack, wanted = last);
88 
89  VSTRING_ADDCH(arg->vstrval, start);
90  for (;;) {
91  if ((c = *cp) == 0)
92  break;
93  cp++;
94  VSTRING_ADDCH(arg->vstrval, c);
95  if (c == '\\') { /* parse escape sequence */
96  if ((c = *cp) == 0)
97  break;
98  cp++;
99  VSTRING_ADDCH(arg->vstrval, c);
100  } else if (c == wanted) { /* closing quote etc. */
101  if (VSTRING_LEN(stack) == 1)
102  return (cp);
103  LEAVE_CHAR(stack, wanted);
104  } else if (c == '"') {
105  ENTER_CHAR(stack, wanted = '"'); /* highest precedence */
106  } else if (c == '<' && wanted == '>') {
107  ENTER_CHAR(stack, wanted = '>'); /* lowest precedence */
108  }
109  }
110  arg->tokval = SMTPD_TOK_ERROR; /* missing end */
111  return (cp);
112 }
113 
114 /* smtp_next_token - extract next token from input, update cp */
115 
116 static char *smtp_next_token(char *cp, SMTPD_TOKEN *arg)
117 {
118  int c;
119 
120  VSTRING_RESET(arg->vstrval);
121  arg->tokval = SMTPD_TOK_OTHER;
122 
123 #define STR(x) vstring_str(x)
124 #define LEN(x) VSTRING_LEN(x)
125 #define STREQ(x,y,l) (strncasecmp((x), (y), (l)) == 0)
126 
127  for (;;) {
128  if ((c = *cp) == 0) /* end of input */
129  break;
130  cp++;
131  if (ISSPACE(c)) { /* whitespace, skip */
132  while (*cp && ISSPACE(*cp))
133  cp++;
134  if (LEN(arg->vstrval) > 0) /* end of token */
135  break;
136  } else if (c == '<') { /* <stuff> */
137  cp = smtp_quoted(cp, arg, c, '>');
138  } else if (c == '"') { /* "stuff" */
139  cp = smtp_quoted(cp, arg, c, c);
140  } else if (c == ':') { /* this is gross, but... */
141  VSTRING_ADDCH(arg->vstrval, c);
142  if (STREQ(STR(arg->vstrval), "to:", LEN(arg->vstrval))
143  || STREQ(STR(arg->vstrval), "from:", LEN(arg->vstrval)))
144  break;
145  } else { /* other */
146  if (c == '\\') {
147  VSTRING_ADDCH(arg->vstrval, c);
148  if ((c = *cp) == 0)
149  break;
150  cp++;
151  }
152  VSTRING_ADDCH(arg->vstrval, c);
153  }
154  }
155  if (LEN(arg->vstrval) <= 0) /* no token found */
156  return (0);
158  arg->strval = vstring_str(arg->vstrval);
159  return (cp);
160 }
161 
162 /* smtpd_token_init - initialize token structures */
163 
164 static void smtpd_token_init(char *ptr, ssize_t count)
165 {
166  SMTPD_TOKEN *arg;
167  int n;
168 
169  for (arg = (SMTPD_TOKEN *) ptr, n = 0; n < count; arg++, n++)
170  arg->vstrval = vstring_alloc(10);
171 }
172 
173 /* smtpd_token - tokenize SMTPD command */
174 
175 int smtpd_token(char *cp, SMTPD_TOKEN **argvp)
176 {
177  static SMTPD_TOKEN *smtp_argv;
178  static MVECT mvect;
179  int n;
180 
181  if (smtp_argv == 0)
182  smtp_argv = (SMTPD_TOKEN *) mvect_alloc(&mvect, sizeof(*smtp_argv), 1,
183  smtpd_token_init, (MVECT_FN) 0);
184  for (n = 0; /* void */ ; n++) {
185  smtp_argv = (SMTPD_TOKEN *) mvect_realloc(&mvect, n + 1);
186  if ((cp = smtp_next_token(cp, smtp_argv + n)) == 0)
187  break;
188  }
189  *argvp = smtp_argv;
190  return (n);
191 }
192 
193 #ifdef TEST
194 
195  /*
196  * Test program for the SMTPD command tokenizer.
197  */
198 
199 #include <stdlib.h>
200 #include <vstream.h>
201 #include <vstring_vstream.h>
202 
203 int main(int unused_argc, char **unused_argv)
204 {
205  VSTRING *vp = vstring_alloc(10);
206  int tok_argc;
207  SMTPD_TOKEN *tok_argv;
208  int i;
209 
210  for (;;) {
211  if (isatty(STDIN_FILENO))
212  vstream_printf("enter SMTPD command: ");
215  break;
216  if (*vstring_str(vp) == '#')
217  continue;
218  if (!isatty(STDIN_FILENO))
219  vstream_printf("%s\n", vstring_str(vp));
220  tok_argc = smtpd_token(vstring_str(vp), &tok_argv);
221  for (i = 0; i < tok_argc; i++) {
222  vstream_printf("Token type: %s\n",
223  tok_argv[i].tokval == SMTPD_TOK_OTHER ? "other" :
224  tok_argv[i].tokval == SMTPD_TOK_ERROR ? "error" :
225  "unknown");
226  vstream_printf("Token value: %s\n", tok_argv[i].strval);
227  }
228  }
229  vstring_free(vp);
230  exit(0);
231 }
232 
233 #endif
#define VSTREAM_EOF
Definition: vstream.h:110
Definition: mvect.h:19
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
#define vstring_str(vp)
Definition: vstring.h:71
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
#define LEAVE_CHAR(buf, ch)
#define VSTREAM_IN
Definition: vstream.h:66
#define STR(x)
#define VSTRING_LEN(vp)
Definition: vstring.h:72
#define LEN(x)
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define VSTRING_RESET(vp)
Definition: vstring.h:77
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define STREQ(x, y, l)
char * mvect_alloc(MVECT *vect, ssize_t elsize, ssize_t nelm, void(*init_fn)(char *, ssize_t), void(*wipe_fn)(char *, ssize_t))
Definition: mvect.c:75
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void(* MVECT_FN)(char *, ssize_t)
Definition: mvect.h:17
char * mvect_realloc(MVECT *vect, ssize_t nelm)
Definition: mvect.c:91
#define SMTPD_TOK_OTHER
Definition: smtpd_token.h:25
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define ISSPACE(c)
Definition: sys_defs.h:1753
int smtpd_token(char *cp, SMTPD_TOKEN **argvp)
Definition: smtpd_token.c:175
char * strval
Definition: smtpd_token.h:21
VSTRING * vstrval
Definition: smtpd_token.h:22
#define ENTER_CHAR(buf, ch)
#define SMTPD_TOK_ERROR
Definition: smtpd_token.h:27