diff options
Diffstat (limited to 'imap/imaptoken.c')
| -rw-r--r-- | imap/imaptoken.c | 562 |
1 files changed, 562 insertions, 0 deletions
diff --git a/imap/imaptoken.c b/imap/imaptoken.c new file mode 100644 index 0000000..a2d3cd8 --- /dev/null +++ b/imap/imaptoken.c @@ -0,0 +1,562 @@ +/* +** Copyright 1998 - 2005 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imaptoken.h" +#include "imapwrite.h" +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include "numlib/numlib.h" +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifndef BUFSIZ +#define BUFSIZ 8192 +#endif + + +static struct imaptoken curtoken; +static char readbuf[BUFSIZ]; + +char *imap_readptr=0; +size_t imap_readptrleft=0; +time_t start_time; + +static time_t readtimeout; + +extern FILE *debugfile; + +extern unsigned long header_count, body_count; + +unsigned long bytes_received_count = 0; /* counter for received bytes */ +unsigned long bytes_sent_count; /* counter for sent bytes (imapwrite.c) */ + +extern void bye(); + +void bye_msg(const char *type) +{ + const char *a=getenv("AUTHENTICATED"); + char buf[NUMBUFSIZE]; + const char *tls=getenv("IMAP_TLS"); + + libmail_str_time_t(time(NULL)-start_time, buf); + + if (tls && atoi(tls)) + tls=", starttls=1"; + else + tls=""; + + if (a && *a) + fprintf(stderr, "%s, user=%s, " + "ip=[%s], headers=%lu, body=%lu, rcvd=%lu, sent=%lu, time=%s%s\n", + type, + a, getenv("TCPREMOTEIP"), header_count, body_count, bytes_received_count, bytes_sent_count, + buf, tls); + else + fprintf(stderr, "DEBUG: Disconnected, ip=[%s], time=%s%s\n", + getenv("TCPREMOTEIP"), + buf, tls); +} + +void disconnected() +{ + bye_msg("INFO: DISCONNECTED"); + bye(); +} + +static void disconnected_timeout(void) +{ + writes("* BYE Disconnected for inactivity.\r\n"); + writeflush(); + bye_msg("INFO: TIMEOUT"); + bye(); +} + +int doidle(time_t idletimeout, int extraFd) +{ +fd_set fds; +struct timeval tv; +time_t t; + + time(&t); + if (t >= readtimeout) disconnected_timeout(); + if (imap_readptrleft > 0) return 1; + + FD_ZERO(&fds); + FD_SET(0, &fds); + + if (extraFd > 0) + { + FD_SET(extraFd, &fds); + } + else + { + extraFd=0; + } + + tv.tv_sec=idletimeout; + tv.tv_usec=0; + + select(extraFd + 1, &fds, 0, 0, &tv); + return (FD_ISSET(0, &fds)); +} + +size_t doread(char *buf, size_t bufsiz) +{ +fd_set fds; +struct timeval tv; +time_t t; +int n = 0; + + time(&t); + if (t >= readtimeout) disconnected_timeout(); + + FD_ZERO(&fds); + FD_SET(0, &fds); + tv.tv_sec=readtimeout - t; + tv.tv_usec=0; + + if (select(1, &fds, 0, 0, &tv) <= 0) + { + disconnected_timeout(); + return (0); + } + if (!FD_ISSET(0, &fds) || (n=read(0, buf, bufsiz)) <= 0) + { + if ( n > 0 ) + bytes_received_count += n; /* count received bytes */ + disconnected(); + return (0); + } + if ( n > 0 ) + bytes_received_count += n; /* count received bytes */ + return (n); +} + +void readfill() +{ + imap_readptrleft=doread(readbuf, sizeof(readbuf)); + imap_readptr=readbuf; +} + +#define UNREAD(c) (*--imap_readptr=(c), ++imap_readptrleft) + +void unread(int c) +{ + UNREAD(c); +} + +void read_eol() +{ +int c; + + while ( (c=READ()) != '\n') + ; + curtoken.tokentype=IT_EOL; +} + +void read_timeout(time_t t) +{ +time_t tt; + + time(&tt); + readtimeout=tt+t; +} + +static void alloc_tokenbuf(unsigned l) +{ + if (l >= curtoken.tokenbuf_size) + { + char *p=curtoken.tokenbuf ? realloc(curtoken.tokenbuf, l + 256): + malloc(l + 256); + + if (!p) + write_error_exit("malloc"); + + curtoken.tokenbuf_size = l+256; + curtoken.tokenbuf=p; + } +} + +static char LPAREN_CHAR='('; +static char RPAREN_CHAR=')'; +static char LBRACKET_CHAR='['; +static char RBRACKET_CHAR=']'; + +void ignorepunct() +{ + LPAREN_CHAR=RPAREN_CHAR=LBRACKET_CHAR=RBRACKET_CHAR='\n'; +} + +#if SMAP + +void smap_readline(char *buffer, size_t bufsize) +{ + int c; + + while ((c=READ()) != '\n') + { + if (bufsize > 1) + { + *buffer++ = c; + --bufsize; + } + } + *buffer=0; +} + +#endif + +static struct imaptoken *do_readtoken(int touc) +{ +int c=0; +unsigned l; + +#define appendch(c) alloc_tokenbuf(l+1); curtoken.tokenbuf[l++]=(c); + + if (curtoken.tokentype == IT_ERROR) return (&curtoken); + + do + { + c=READ(); + } while (c == '\r' || c == ' ' || c == '\t'); + + if (c == '\n') + { + UNREAD(c); + curtoken.tokentype=IT_EOL; + return (&curtoken); + } + c=(unsigned char)c; + if (c == LPAREN_CHAR) + { + curtoken.tokentype=IT_LPAREN; + return (&curtoken); + } + + if (c == RPAREN_CHAR) + { + curtoken.tokentype=IT_RPAREN; + return (&curtoken); + } + + if (c == LBRACKET_CHAR) + { + curtoken.tokentype=IT_LBRACKET; + return (&curtoken); + } + + if (c == RBRACKET_CHAR) + { + curtoken.tokentype=IT_RBRACKET; + return (&curtoken); + } + + if (c == '"') + { + l=0; + while ((c=READ()) != '"') + { + if (c == '\\') + c=READ(); + if (c == '\r' || c == '\n') + { + UNREAD(c); + curtoken.tokentype=IT_ERROR; + return (&curtoken); + } + if (l < 8192) + { + appendch(c); + } + } + appendch(0); + curtoken.tokentype=IT_QUOTED_STRING; + return (&curtoken); + } + + if (c == '{') + { + curtoken.tokennum=0; + while ((c=READ()) != '}') + { + if (!isdigit((int)(unsigned char)c)) + { + UNREAD(c); + curtoken.tokentype=IT_ERROR; + return (&curtoken); + } + curtoken.tokennum = curtoken.tokennum*10 + (c-'0'); + } + c=READ(); + if (c == '\r') + { + c=READ(); + } + if (c != '\n') + { + curtoken.tokentype=IT_ERROR; + return (&curtoken); + } + curtoken.tokentype=IT_LITERAL_STRING_START; + return (&curtoken); + } + + l=0; + if (c == '\\') + { + appendch(c); /* Message flag */ + c=READ(); + } + else if (isdigit(c)) + { + curtoken.tokentype=IT_NUMBER; + curtoken.tokennum=0; + do + { + appendch(c); + curtoken.tokennum = curtoken.tokennum*10 + + (c-'0'); + c=READ(); + } while (isdigit( (int)(unsigned char)c)); + + /* Could be stuff like mime.spec, so continue reading. */ + } + + 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) + { + curtoken.tokentype=IT_ATOM; + if (l < IT_MAX_ATOM_SIZE) + { + if (touc) + c=toupper(c); + appendch(c); + } + else + { + write_error_exit("max atom size too small"); + } + c=READ(); + } + if (l == 0) + { + curtoken.tokentype=IT_ERROR; + return (&curtoken); + } + appendch(0); + UNREAD(c); + + if (strcmp(curtoken.tokenbuf, "NIL") == 0) + curtoken.tokentype=IT_NIL; + return (&curtoken); +} + +static struct imaptoken *readtoken(int touc) +{ +struct imaptoken *tok=do_readtoken(touc); + + if (tok->tokentype == IT_LITERAL_STRING_START) + { + unsigned long nbytes=curtoken.tokennum; + + if (nbytes > 8192) + { + writes("* NO [ALERT] IMAP command too long.\r\n"); + tok->tokentype=IT_ERROR; + } + else + { + unsigned long i; + + 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; + } + } + + 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; + } + + if (p) + fprintf(debugfile, ": %s", p); + fprintf(debugfile, "\n"); + fflush(debugfile); + } + return (tok); +} + +struct imaptoken *nexttoken(void) +{ + return (readtoken(1)); +} + +struct imaptoken *nexttoken_nouc(void) +{ + return (readtoken(0)); +} + +/* RFC 2060 sucks */ + +struct imaptoken *nexttoken_okbracket(void) +{ + struct imaptoken *t; + + LBRACKET_CHAR=RBRACKET_CHAR='\n'; + + t=nexttoken(); + + LBRACKET_CHAR='['; + RBRACKET_CHAR=']'; + return (t); +} + +struct imaptoken *nexttoken_nouc_okbracket(void) +{ + struct imaptoken *t; + + LBRACKET_CHAR=RBRACKET_CHAR='\n'; + + t=nexttoken_nouc(); + + LBRACKET_CHAR='['; + RBRACKET_CHAR=']'; + return (t); +} + +struct imaptoken *currenttoken(void) +{ + return (&curtoken); +} + +struct imaptoken *nexttoken_noparseliteral(void) +{ + return (do_readtoken(0)); +} + +/* Read an IMAP literal string (or a portion of) */ + +void read_string(char **ptr, unsigned long *left, unsigned long cnt) +{ + if (imap_readptrleft == 0) + { + /* Keep reading until we fill the buffer or until we've + ** read the entire string. + */ + + read_timeout(SOCKET_TIMEOUT); + imap_readptr=readbuf; + while (imap_readptrleft < sizeof(readbuf) && imap_readptrleft < cnt) + imap_readptrleft += doread(readbuf+imap_readptrleft, + sizeof(readbuf)-imap_readptrleft); + } + + if (cnt < imap_readptrleft) /* Can satisfy fully from buffer */ + { + *ptr=imap_readptr; + *left=cnt; + imap_readptr += cnt; + imap_readptrleft -= cnt; + return; + } + + *ptr=imap_readptr; + *left=imap_readptrleft; + imap_readptrleft=0; + return; +} + +char *my_strdup(const char *s) +{ +char *q=strdup(s); + + if (!q) write_error_exit("malloc"); + return (q); +} + +int ismsgset(struct imaptoken *tok) + /* See if this token is a syntactically valid message set */ +{ + + if (tok->tokentype == IT_NUMBER) return (1); + if (tok->tokentype != IT_ATOM) return (0); + + return ismsgset_str(tok->tokenbuf); +} + +int ismsgset_str(const char *p) +{ + while (isdigit((int)(unsigned char)*p) || *p == '*') + { + if (*p == '0') return (0); + if (*p == '*') + ++p; + else + do + { + ++p; + } while (isdigit((int)(unsigned char)*p)); + + if (*p == ':') + { + ++p; + if (!isdigit((int)(unsigned char)*p) && + *p != '*') + return (0); + if (*p == '0') return (0); + if (*p == '*') + ++p; + else + do + { + ++p; + } while (isdigit((int)(unsigned char)*p)); + } + if (*p != ',') break; + ++p; + } + if (*p) return (0); + return (1); +} + |
