Viewing file:
imaptoken.c (9.6 KB) -rw-rw-rw-Select action/file-type:

(
+) |

(
+) |

(
+) |
Code (
+) |
Session (
+) |

(
+) |
SDB (
+) |

(
+) |

(
+) |

(
+) |

(
+) |

(
+) |
/*
** 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);
}