diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /imap/imaptoken.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
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); +} +		 | 
