/* main.c   by Michael Thorpe   2003-07-04 */

#include <string.h>
#include <unistd.h>
#include "imapd.h"

int state=STATE_NONAUTH;
char *errmsg=0;
struct mailbox *curmailbox=0;

struct command {
	const char *name;
	void (*func)(str *tag,str **args);
	unsigned char namelen;
	unsigned char when;
	unsigned char numargs; /* -1 means the func will fetch its args itself */
};

/* This structure must be in descending order by namelen */
static struct command cmds[]={
{"AUTHENTICATE",cmd_authenticate,12,STATE_NONAUTH,1},
{"CAPABILITY",cmd_capability,10,STATE_NONAUTH|STATE_AUTH|STATE_SELECT,0},
{"EXAMINE",cmd_examine,7,STATE_AUTH|STATE_SELECT,1},
{"LOGOUT",cmd_logout,6,STATE_NONAUTH|STATE_AUTH|STATE_SELECT,0},
{"SELECT",cmd_select,6,STATE_AUTH|STATE_SELECT,1},
{"CLOSE",cmd_close,5,STATE_SELECT,0},
{"FETCH",cmd_fetch,5,STATE_SELECT,-1},
{"LOGIN",cmd_login,5,STATE_NONAUTH,2},
{"STORE",cmd_store,5,STATE_SELECT,-1},
{"LIST",cmd_list,4,STATE_AUTH|STATE_SELECT,2},
{"LSUB",cmd_lsub,4,STATE_AUTH|STATE_SELECT,2},
{"NOOP",cmd_noop,4,STATE_NONAUTH|STATE_AUTH|STATE_SELECT,0},
{"UID",cmd_uid,3,STATE_SELECT,-1},
/* Authed: APPEND, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE */
/* Selected: CHECK, COPY, EXPUNGE, PARTIAL, SEARCH */
/* Obsolete: FIND, SUBSCRIBE MAILBOX, UNSUBSCRIBE MAILBOX */
{0,0,0,-1}
};

static void doloop() {
	str *tag,*cmd,**args;
	int i;

	while(state != STATE_LOGOUT) {
		tag=getword();
		if(!tag)
			continue;
		cmd=getword();
		if(!cmd || !cmd->len)
			goto badcommand;
		for(i=0;cmds[i].namelen>cmd->len;i++)
			;
		while(cmds[i].namelen==cmd->len) {
			if(state&cmds[i].when && !strncasecmp(cmds[i].name,cmd->s,cmd->len)) {
				args=0;
				if(cmds[i].numargs != (unsigned char)-1) {
					args=getwords(cmds[i].numargs);
					if(!args) {
						writetagstr(tag,"BAD invalid parameter count");
						goto cmddone;
					}
				}
				(*cmds[i].func)(tag,args);
				if(args)
					freestrs(args);
				goto cmddone;
			}
			i++;
		}
badcommand: /* We eat the rest of the line */
		writetagstr(tag,"BAD command");
		freestr(tag);
		while(cmd) {
			freestr(cmd);
			cmd=getword();
		}
		continue;
cmddone:
		freestr(cmd);
		freestr(tag);
	}
}

/*
 * Strategy: We set a timeout alarm of 30 seconds, after which we die.
 *           The alarm is cancelled by cmd_login() just before calling
 *           login() to protect against unsafe operations on the part of
 *           library functions.  The alarm is reinstated by cmd_login() if
 *           login() returns non-zero.
 */
int main() {
   alarm(30);
	writeallstdout("* OK IMAP4 server ready\r\n",25);
	doloop();
	return(0);
}

