1 /**********************************************************************
2 * token.c September 1999
3 * Horms horms@verge.net.au
4 *
5 * Token to encapsulate a byte string
6 *
7 * perdition
8 * Mail retrieval proxy server
9 * Copyright (C) 1999-2005 Horms
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
24 *
25 **********************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "io.h"
32 #include "io_select.h"
33 #include "token.h"
34 #include "options.h"
35 #include "perdition_globals.h"
36
37 #ifdef DMALLOC
38 #include <dmalloc.h>
39 #endif
40
41
42
43 static char token_read_buffer[MAX_LINE_LENGTH];
44 static size_t token_read_offset=0;
45 static size_t token_read_bytes=0;
46
47 static int token_fill_buffer(io_t *io, const options_t *opt,
48 const char *log_str);
49 static int __token_fill_buffer(io_t *io, const options_t *opt,
50 const char *log_str);
51
52 /**********************************************************************
53 * token_create
54 * create an empty token
55 * pre: none
56 * post: token is created, and values are initialised
57 * return: allocated token_t
58 * NULL on error
59 *
60 * 8 bit clean
61 **********************************************************************/
62
token_create(void)63 token_t *token_create(void){
64 token_t *t;
65
66 if((t=(token_t *)malloc(sizeof(token_t)))==NULL){
67 VANESSA_LOGGER_DEBUG_ERRNO("malloc");
68 return(NULL);
69 }
70 t->n=0;
71 t->buf=NULL;
72 return(t);
73 }
74
75
76 /**********************************************************************
77 * token_assign
78 * place bytes into a token
79 * pre: t: token to place bytes in
80 * buf: buffer to use
81 * n: number of bytes in buffer
82 * flags: flags for token as per token.h
83 * post: if n!=0 then buf is used as the buffer in t
84 * (no copying)
85 * if n==0 the buffer in t is set to NULL
86 * the flag in t is set
87 * return: none
88 *
89 * 8 bit clean
90 **********************************************************************/
91
token_assign(token_t * t,char * buf,const size_t n,const flag_t flag)92 void token_assign(
93 token_t *t,
94 char *buf,
95 const size_t n,
96 const flag_t flag
97 ){
98 t->n=n;
99 t->flag=flag;
100 if(n==0){
101 if(buf!=NULL){
102 free(buf);
103 }
104 t->buf=NULL;
105 }
106 else {
107 t->buf=buf;
108 }
109 }
110
111
112 /**********************************************************************
113 * token_unassign
114 * make a token empty
115 * useful if you want to destroy a token but not what it contains
116 * pre: t: token to unassign values of
117 * post: values in t are reinitialised, but buffer is not destroyed
118 * return: none
119 *
120 * 8 bit clean
121 **********************************************************************/
122
token_unassign(token_t * t)123 void token_unassign(token_t *t){
124 token_assign(t, NULL, 0, 0);
125 }
126
127
128 /**********************************************************************
129 * token_destroy
130 * pre: t pointer to a token
131 * post: if the token is null no nothing
132 * if buf is non-NULL then free it
133 * free the token
134 * return: none
135 *
136 * 8 bit clean
137 **********************************************************************/
138
token_destroy(token_t ** t)139 void token_destroy(token_t **t){
140 if(*t==NULL){
141 return;
142 }
143
144 if((*t)->buf!=NULL){
145 free((*t)->buf);
146 }
147
148 free(*t);
149 *t=NULL;
150 }
151
152
153 /**********************************************************************
154 * token_write
155 * write a token to fd
156 * pre: io: io_t to write to
157 * token: token to write
158 * post: contents of token is written to fd using
159 * vanessa_socket_pipe_write_bytes
160 * return: -1 on error
161 * 0 otherwise
162 *
163 * 8 bit clean
164 **********************************************************************/
165
token_write(io_t * io,const token_t * t)166 int token_write(io_t *io, const token_t *t){
167 if(io_write(io, t->buf, t->n)){
168 VANESSA_LOGGER_DEBUG("vanessa_socket_pipe_write_bytes");
169 return(-1);
170 }
171
172 return(0);
173 }
174
175
176 /**********************************************************************
177 * token_flush
178 * Flush internal buffers used to read tokens.
179 * pre: none
180 * post: internal buffers are flushed
181 * return: none
182 **********************************************************************/
183
token_flush(void)184 void token_flush(void) {
185 token_read_offset = 0;
186 token_read_bytes = 0;
187 memset(token_read_buffer, 0, sizeof(token_read_buffer));
188 }
189
190
191 /**********************************************************************
192 * token_fill_buffer
193 * read a token in from fd
194 * pre: io: io_t to read from
195 * opt: options
196 * log_str: logging tag for connection logging
197 * post: Bytes are read from fd into a buffer, if the buffer is
198 * empty
199 * return: number of bytes read, or number of unread bytes in buffer
200 * -1 on error
201 *
202 * 8 bit clean
203 **********************************************************************/
204
token_fill_buffer(io_t * io,const options_t * opt,const char * log_str)205 static int token_fill_buffer(io_t *io, const options_t *opt,
206 const char *log_str) {
207 if(token_read_bytes>token_read_offset) {
208 if(token_read_bytes==0){
209 VANESSA_LOGGER_DEBUG("returning without read");
210 }
211 return(token_read_bytes);
212 }
213 return(__token_fill_buffer(io, opt, log_str));
214 }
215
__token_fill_buffer(io_t * io,const options_t * opt,const char * log_str)216 static int __token_fill_buffer(io_t *io, const options_t *opt,
217 const char *log_str){
218 int bytes_read;
219 char *dump_buf;
220
221 bytes_read = io_read(io, token_read_buffer, MAX_LINE_LENGTH-1);
222 if (bytes_read < 0) {
223 VANESSA_LOGGER_DEBUG_ERRNO("error reading input");
224 return -1;
225 }
226
227 token_read_offset = 0;
228 token_read_bytes = bytes_read;
229 if (opt->connection_logging) {
230 dump_buf = VANESSA_LOGGER_DUMP(token_read_buffer,
231 bytes_read, 0);
232 if (!dump_buf) {
233 VANESSA_LOGGER_DEBUG("VANESSA_LOGGER_DUMP");
234 return -1;
235 }
236 VANESSA_LOGGER_DEBUG_RAW_UNSAFE("%s \"%s\"", log_str, dump_buf);
237 free(dump_buf);
238 }
239
240 return bytes_read;
241 }
242
243
244 /**********************************************************************
245 * token_read
246 * read a token in from fd
247 * pre: io: io_t to read from
248 * literal_buf: buffer to store bytes read from server in
249 * n: pointer to size_t containing the size of literal_buf
250 * flag: If logical or of TOKEN_EOL then all characters
251 * up to a '\n' will be read as a token. That is the token may
252 * have spaces.
253 * If logical or of TOKEN_IMAP4 then spaces inside
254 * quotes will be treated as literals rather than token
255 * delimiters.
256 * If logical or of TOKEN_IMAP4_LITERAL then m bytes
257 * will be read as a single token.
258 * m: Bytes to read if flag is TOKEN_IMAP4_LITERAL
259 * log_str: logging tag for connection logging
260 * post: Token is read from fd into token
261 * ' ' will terminate a token
262 * '\r' is ignored
263 * '\n' will terminate a token and set the eol element to 1
264 * All other characters are considered to be a part of the token
265 * If literal_buf is not NULL, and n is not NULL and *n is not 0
266 * Bytes read from fd are copied to literal_buf, this includes
267 * ' ', '\r' and '\n'.
268 * return: token
269 * NULL on error
270 * Note: if a token larger than BUFFER_SIZE is read then only
271 * BUFFER_SIZE will be read and the remainder will be
272 * left (to be handled by an subsequent call to token_read).
273 * The same applies to *n if literal_buf is being filled.
274 *
275 * 8 bit clean
276 **********************************************************************/
277
token_read(io_t * io,char * literal_buf,size_t * n,flag_t flag,size_t m,const char * log_str)278 token_t *token_read(
279 io_t *io,
280 char *literal_buf,
281 size_t *n,
282 flag_t flag,
283 size_t m,
284 const char *log_str
285 ){
286 char buffer[MAX_LINE_LENGTH];
287 char *assign_buffer;
288 char c;
289 token_t *t;
290 size_t literal_offset=0;
291 size_t len=0;
292 int bytes_read = 0;
293 int do_literal;
294 flag_t save_flag=TOKEN_NONE;
295 flag_t quoted=0;
296
297 memset(buffer, 0, MAX_LINE_LENGTH);
298
299 do_literal=(literal_buf!=NULL && n!=NULL && *n!=0)?1:0;
300 while(!(do_literal && literal_offset>=*n) && len < MAX_LINE_LENGTH){
301 if((bytes_read=token_fill_buffer(io, &opt, log_str))<=0){
302 VANESSA_LOGGER_DEBUG("token_fill_buffer");
303 return(NULL);
304 }
305
306 c=token_read_buffer[token_read_offset++];
307
308 /*Place in literal buffer, if we are doooooooooooooing that today*/
309 if(do_literal){
310 *(literal_buf+(literal_offset++))=c;
311 }
312
313 if(flag&TOKEN_IMAP4_LITERAL) {
314 buffer[len++]=c;
315 if(len >= m) {
316 break;
317 }
318 continue;
319 }
320
321 switch(c){
322 case '\n':
323 save_flag=TOKEN_EOL;
324 goto end_while;
325 case '\r':
326 break;
327 case '\"':
328 if(flag&TOKEN_IMAP4){
329 quoted^=1;
330 }
331 buffer[len++]=c;
332 break;
333 case ' ':
334 if(!(flag&TOKEN_EOL) && !quoted){
335 goto end_while;
336 }
337 default:
338 buffer[len++]=c;
339 }
340 }
341 end_while:
342
343 /*Set return value for n*/
344 if(do_literal){
345 *n=literal_offset;
346 }
347
348 /*Create token to return*/
349 if((t=token_create())==NULL){
350 VANESSA_LOGGER_DEBUG("token_create");
351 return(NULL);
352 }
353 assign_buffer = malloc(len);
354 if (!assign_buffer) {
355 VANESSA_LOGGER_DEBUG_ERRNO("malloc");
356 token_destroy(&t);
357 return(NULL);
358 }
359 memcpy(assign_buffer, buffer, len);
360 token_assign(t, assign_buffer, len, save_flag);
361 return(t);
362 }
363
364
365 /**********************************************************************
366 * token_cmp
367 * compare two tokens
368 * pre: a: token to compare
369 * b: token to compare
370 * post: none
371 * return: 1 is they are the same
372 * 0 otherwise
373 * flag field will be ignored if either token has eol set to TOKEN_DONT_CARE
374 *
375 * Not 8 bit clean as it is case insensitive using toupper
376 **********************************************************************/
377
token_cmp(const token_t * a,const token_t * b)378 int token_cmp(const token_t *a, const token_t *b){
379 if(
380 a->n!=b->n ||
381 ((a->flag!=b->flag)&&(a->flag!=TOKEN_DONT_CARE)&&(b->flag!=TOKEN_DONT_CARE))
382 ){
383 return(0);
384 }
385
386 return(strncasecmp(a->buf, b->buf, a->n)?0:1);
387 }
388
389
390 /**********************************************************************
391 * token_to_string
392 * dump the buffer in a token into a \0 terminated string
393 * string will be dynamically allocated
394 * pre: t: token to dump to a string
395 * strip: Character to strip from first and last character of
396 * string if it is present. Ignored if TOKEN_NO_STRIP
397 * post: a string is allocated and the contents of it's buffer plus
398 * a trailing '\0' is placed in the string
399 * return: the string
400 * NULL on error
401 *
402 * Not 8 bit clean
403 **********************************************************************/
404
token_to_string(const token_t * t,const unsigned char strip)405 char *token_to_string(const token_t *t, const unsigned char strip){
406 char *string;
407 char *buf;
408 size_t n;
409
410 if(t==NULL || t->buf == NULL) {
411 string=malloc(1);
412 *string='\0';
413 return(string);
414 }
415
416 buf=t->buf;
417 n=t->n;
418
419 if(strip!=TOKEN_NO_STRIP && *buf==strip && *(buf+n-1)==strip){
420 buf++;
421 n-=2;
422 }
423
424 if((string=strn_to_str((char *)buf, n))==NULL){
425 VANESSA_LOGGER_DEBUG("strn_to_str");
426 return(NULL);
427 }
428 return(string);
429 }
430
431 /**********************************************************************
432 * token_casecmp_string
433 * Compare a token with a null-terminated string
434 * pre: t: token
435 * str: string
436 * return: 1 on match
437 * 0 otherwise
438 *
439 * Not 8 bit clean
440 **********************************************************************/
441
token_casecmp_string(const token_t * t,const char * str)442 int token_casecmp_string(const token_t *t, const char *str)
443 {
444 if (token_len(t) == strlen(str) &&
445 !strncasecmp((char *)token_buf(t), str, token_len(t)))
446 return 1;
447
448 return 0;
449 }
450
451