diff options
Diffstat (limited to 'imap/imaptoken.c')
| -rw-r--r-- | imap/imaptoken.c | 208 |
1 files changed, 148 insertions, 60 deletions
diff --git a/imap/imaptoken.c b/imap/imaptoken.c index 7df8846..a11310a 100644 --- a/imap/imaptoken.c +++ b/imap/imaptoken.c @@ -1,5 +1,5 @@ /* -** Copyright 1998 - 2005 Double Precision, Inc. +** Copyright 1998 - 2018 Double Precision, Inc. ** See COPYING for distribution information. */ @@ -16,6 +16,8 @@ #include <sys/types.h> #include <sys/time.h> #include "numlib/numlib.h" +#include "imapd.h" +#include <courier-unicode.h> #if HAVE_UNISTD_H #include <unistd.h> #endif @@ -222,8 +224,59 @@ void smap_readline(char *buffer, size_t bufsize) #endif +static int ignore_output_func(const char *ptr, size_t cnt, void *ignore) +{ + return 0; +} + +static struct imaptoken *do_readtoken_nolog(int touc); + static struct imaptoken *do_readtoken(int touc) { + struct imaptoken *tok=do_readtoken_nolog(touc); + + if (debugfile) + { + char *p=0; + + fprintf(debugfile, "READ: "); + switch (tok->tokentype) { + case IT_ATOM: + p=curtoken.tokenbuf; fprintf(debugfile, "ATOM"); break; + case IT_NUMBER: + p=curtoken.tokenbuf; fprintf(debugfile, "NUMBER"); break; + case IT_QUOTED_STRING: + p=curtoken.tokenbuf; fprintf(debugfile, "QUOTED_STRING"); break; + case IT_LPAREN: + fprintf(debugfile, "LPAREN"); break; + case IT_RPAREN: + fprintf(debugfile, "RPAREN"); break; + case IT_NIL: + fprintf(debugfile, "NIL"); break; + case IT_ERROR: + fprintf(debugfile, "ERROR"); break; + case IT_EOL: + fprintf(debugfile, "EOL"); break; + case IT_LBRACKET: + fprintf(debugfile, "LBRACKET"); break; + case IT_RBRACKET: + fprintf(debugfile, "RBRACKET"); break; + case IT_LITERAL_STRING_START: + fprintf(debugfile, "{%lu}", tok->tokennum); break; + case IT_LITERAL8_STRING_START: + fprintf(debugfile, "~{%lu}", tok->tokennum); break; + } + + if (p) + fprintf(debugfile, ": %s", p); + fprintf(debugfile, "\n"); + fflush(debugfile); + } + return tok; +} + +static struct imaptoken *do_readtoken_nolog(int touc) +{ int c=0; unsigned l; @@ -269,6 +322,8 @@ unsigned l; if (c == '"') { + int bit8=0; + l=0; while ((c=READ()) != '"') { @@ -280,16 +335,62 @@ unsigned l; curtoken.tokentype=IT_ERROR; return (&curtoken); } - if (l < 8192) + if (l >= BUFSIZ) { - appendch(c); + writes("* NO [ALERT] IMAP command too long.\r\n"); + curtoken.tokentype=IT_ERROR; } + if (c & 0x80) + bit8=1; + appendch(c); } appendch(0); curtoken.tokentype=IT_QUOTED_STRING; + + /* + ** Strings must be valid UTF-8. Shortcut check. + */ + + if (bit8) + { + int errptr=0; + + unicode_convert_handle_t h= + unicode_convert_init("utf-8", + unicode_u_ucs4_native, + ignore_output_func, + (void *)0); + + if (unicode_convert(h, curtoken.tokenbuf, + strlen(curtoken.tokenbuf))) + { + curtoken.tokentype=IT_ERROR; + } + + if (unicode_convert_deinit(h, &errptr) || errptr) + { + curtoken.tokentype=IT_ERROR; + } + } return (&curtoken); } + /* + ** Parse LITERAL or LITERAL8 + */ + curtoken.tokentype=IT_LITERAL_STRING_START; + + if (c == '~') + { + c=READ(); + if (c != '{') + { + curtoken.tokentype=IT_ERROR; + return (&curtoken); + } + curtoken.tokentype=IT_LITERAL8_STRING_START; + } + if (c == '{') { curtoken.tokennum=0; @@ -313,7 +414,6 @@ unsigned l; curtoken.tokentype=IT_ERROR; return (&curtoken); } - curtoken.tokentype=IT_LITERAL_STRING_START; return (&curtoken); } @@ -339,9 +439,11 @@ unsigned l; } while (c != '\r' && c != '\n' - && !isspace((int)(unsigned char)c) - && c != '\\' && c != '"' && c != LPAREN_CHAR && c != RPAREN_CHAR - && c != '{' && c != '}' && c != LBRACKET_CHAR && c != RBRACKET_CHAR) + && !isspace((int)(unsigned char)c) + && (((unsigned char)c) & 0x80) == 0 + && c != '\\' && c != '"' && c != LPAREN_CHAR && c != RPAREN_CHAR + && c != '~' + && c != '{' && c != '}' && c != LBRACKET_CHAR && c != RBRACKET_CHAR) { curtoken.tokentype=IT_ATOM; if (l < IT_MAX_ATOM_SIZE) @@ -352,7 +454,7 @@ unsigned l; } else { - write_error_exit("max atom size too small"); + write_error_exit("max atom size too small"); } c=READ(); } @@ -371,65 +473,52 @@ unsigned l; static struct imaptoken *readtoken(int touc) { -struct imaptoken *tok=do_readtoken(touc); + struct imaptoken *tok=do_readtoken(touc); - if (tok->tokentype == IT_LITERAL_STRING_START) - { - unsigned long nbytes=curtoken.tokennum; + convert_literal_tokens(tok); + return (tok); +} - if (nbytes > 8192) - { - writes("* NO [ALERT] IMAP command too long.\r\n"); - tok->tokentype=IT_ERROR; - } - else - { - unsigned long i; +/* +** If a token is a LITERAL, read it and replace it with a QUOTED_STRING. +*/ - writes("+ OK\r\n"); - writeflush(); - alloc_tokenbuf(nbytes+1); - for (i=0; i<nbytes; i++) - tok->tokenbuf[i]= READ(); - tok->tokenbuf[i]=0; - tok->tokentype=IT_QUOTED_STRING; - } - } +void convert_literal_tokens(struct imaptoken *tok) +{ + unsigned long nbytes; - if (debugfile) + if (tok->tokentype != IT_LITERAL_STRING_START && + tok->tokentype != IT_LITERAL8_STRING_START) + return; + + nbytes=curtoken.tokennum; + + if (nbytes > BUFSIZ) + { + writes("* NO [ALERT] IMAP command too long.\r\n"); + tok->tokentype=IT_ERROR; + } + else { - char *p=0; + unsigned long i; - fprintf(debugfile, "READ: "); - switch (tok->tokentype) { - case IT_ATOM: - p=curtoken.tokenbuf; fprintf(debugfile, "ATOM"); break; - case IT_NUMBER: - p=curtoken.tokenbuf; fprintf(debugfile, "NUMBER"); break; - case IT_QUOTED_STRING: - p=curtoken.tokenbuf; fprintf(debugfile, "QUOTED_STRING"); break; - case IT_LPAREN: - fprintf(debugfile, "LPAREN"); break; - case IT_RPAREN: - fprintf(debugfile, "RPAREN"); break; - case IT_NIL: - fprintf(debugfile, "NIL"); break; - case IT_ERROR: - fprintf(debugfile, "ERROR"); break; - case IT_EOL: - fprintf(debugfile, "EOL"); break; - case IT_LBRACKET: - fprintf(debugfile, "LBRACKET"); break; - case IT_RBRACKET: - fprintf(debugfile, "RBRACKET"); break; - } + /* - if (p) - fprintf(debugfile, ": %s", p); - fprintf(debugfile, "\n"); - fflush(debugfile); + RFC4466: In addition, the non-terminal "literal8" defined + in [BINARY] got extended to allow for non-synchronizing + literals if both [BINARY] and [LITERAL+] extensions are + supported by the server. + + */ + + writes("+ OK\r\n"); + writeflush(); + alloc_tokenbuf(nbytes+1); + for (i=0; i<nbytes; i++) + tok->tokenbuf[i]= READ(); + tok->tokenbuf[i]=0; + tok->tokentype=IT_QUOTED_STRING; } - return (tok); } struct imaptoken *nexttoken(void) @@ -564,4 +653,3 @@ int ismsgset_str(const char *p) if (*p) return (0); return (1); } - |
