/* POP3 Server state machine - see RFC 1225
 *
 *      Jan 92  Erik Olson olson@phys.washington.edu
 *              Taken from POP2 server code in NOS 910618
 *              Rewritten/converted to POP3
 *      Feb 92  William Allen Simpson
 *              integrated with current work
 *      Aug-Oct 92      Mike Bilow, N1BEE, mikebw@ids.net
 *              Extensive bug fixes; changed uses of Borland stat()
 *              to fsize() in order to fix intermittent crashes;
 *              corrected confusion of sockmode()
 *	November 93	KO4KS/Brian A. Lantz
 *		Modified close_folder() for TNOS control files
 *
 *  "Need-to" list: XTND XMIT (to get WinQVTnet to work)
 */

#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#ifdef UNIX
#include <sys/types.h>
#endif
#if     defined(__STDC__) || defined(__TURBOC__)
#include <stdarg.h>
#endif
#include <ctype.h>
#include <setjmp.h>
#include "global.h"
#include "mbuf.h"
#include "commands.h"
#include "socket.h"
#include "proc.h"
#include "files.h"
#include "mailbox.h"
#include "bm.h"
#include "smtp.h"
#include "dirutil.h"

#ifdef POP3SERVER

/* ---------------- common server data structures ---------------- */
/* POP message pointer element */

struct pop_msg {
        long len;
        long pos;
        int deleted;
        struct pop_msg *next;
};

/* POP server control block */

struct pop_scb {
        int socket;             /* socket number for this connection */
        char state;             /* server state */
#define      LSTN       0
#define      AUTH       1
#define      TRANS      2
#define      UPDATE     3
#define      DONE       5

        char    buf[TLINELEN];   /* input line buffer */
        char    count;          /* line buffer length */
        char    username[64];   /* user/folder name */
        FILE    *wf;            /* work folder file pointer */
        int     folder_len;     /* number of msgs in current folder */
        int     high_num;       /* highest message number accessed */
        long    folder_file_size; /* length of the current folder file, in bytes */
        char    folder_modified; /* mail folder contents modified flag */
        struct pop_msg *msg;    /* message database link-list */
};

#define NULLSCB  (struct pop_scb *)0

/* Response messages -- '\n' is converted to '\r\n' by the socket code */

static char     count_rsp[]     = "+OK you have %d messages\n",
                error_rsp[]     = "-ERR %s\n",
                greeting_msg[]  = "+OK %s POP3 ready\n",
                user_rsp[]      = "+OK user\n",
#ifdef notdef
                pass_rsp[]      = "+OK password\n",
#endif
                stat_rsp[]      = "+OK %d %ld\n",
                list_single_rsp[]       = "+OK %d %d\n",
                list_multi_rsp[]        = "+OK %d messages (%ld octets)\n",
                retr_rsp[]      = "+OK %ld octets\n",
                multi_end_rsp[] = ".\n",
                msg_line[]      = "%s\n",
                dele_rsp[]      = "+OK message %d deleted\n",
                noop_rsp[]      = "+OK\n",
                last_rsp[]      = "+OK %d\n",
                signoff_msg[]   = "+OK Bye, bye-bye, bye now, goodbye\n";

static void rrip __ARGS((char *s));
static struct pop_scb *create_scb __ARGS((void));
static void delete_scb __ARGS((struct pop_scb *scb));
static void popserv __ARGS((int s,void *unused,void *p));
static int poplogin __ARGS((char *pass,char *username));
static void open_folder __ARGS((struct pop_scb *));
static void stat_message __ARGS((struct pop_scb *));
static void list_message __ARGS((struct pop_scb *));
static void retr_message __ARGS((struct pop_scb *));
static void dele_message __ARGS((struct pop_scb *));
static void noop_message __ARGS((struct pop_scb *));
static void last_message __ARGS((struct pop_scb *));
static void rset_message __ARGS((struct pop_scb *));
static void top_message __ARGS((struct pop_scb *));
static void close_folder __ARGS((struct pop_scb *));
static void state_error __ARGS((struct pop_scb *,char *));
static void fatal_error __ARGS((struct pop_scb *,char *));
static void do_cleanup __ARGS((struct pop_scb *));
static int newmail __ARGS((struct pop_scb *));
static struct pop_msg *goto_msg __ARGS((struct pop_scb *,int ));
static void delete_msglist __ARGS((struct pop_msg *b_msg));
extern void updateCtl __ARGS((char *who,struct let *info));

static void pop_sm __ARGS((struct pop_scb *scb));

static int Spop = -1; /* prototype socket for service */


/* Start up POP receiver service */
int
#ifdef PROTOTYPES
pop3start(int argc,char **argv,void *p)
#else
pop3start(argc,argv,p)
int argc;
char *argv[];
void *p;
#endif
{
	return (installserver (argc, argv, &Spop, "POP3 listener", IPPORT_POP3,
		"POP3 server", popserv, 2048, NULL));
}

/* Shutdown POP3 service (existing connections are allowed to finish) */

int
#ifdef PROTOTYPES
pop3stop(int argc,char **argv,void *p)
#else
pop3stop(argc,argv,p)
int argc;
char *argv[];
void *p;
#endif
{
	return (deleteserver (&Spop));
}

static void
popserv(s,unused,p)
int s;
void *unused;
void *p;
{
        struct pop_scb *scb;
	char *cp;

        sockowner(s,Curproc);           /* We own it now */
        log(s,"open POP3");

        if((scb = create_scb()) == NULLSCB) {
                tprintf(Nospace);
                log(s,"close POP3 - no space");
                close_s(s);
                return;
        }

        scb->socket = s;
        scb->state  = AUTH;

        sockmode(s,SOCK_ASCII);         /* N1BEE */
        (void) usprintf(s,greeting_msg,Hostname);

loop:   if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
                /* He closed on us */

                goto quit;
        }

        rip(scb->buf);
        if (strlen(scb->buf) == 0)      /* Ignore blank cmd lines */
                goto loop;

	/* Convert lower, and mixed case commands to UPPER case - Ashok */
	for(cp = scb->buf;*cp != ' ' && *cp != '\0';cp++)
	    *cp = toupper(*cp);

        pop_sm(scb);
        if (scb->state == DONE)
                goto quit;

        goto loop;

quit:
        log(scb->socket,"close POP3");
        close_s(scb->socket);
        delete_scb(scb);
}


/* Create control block, initialize */

static struct
pop_scb *create_scb()
{
        register struct pop_scb *scb;

        if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
                return NULLSCB;

        scb->username[0] = '\0';
        scb->msg = NULL;
        scb->wf = NULL;

        scb->count = scb->folder_file_size = 0;

        scb->folder_modified = FALSE;
        return scb;
}


/* Free msg link-list */
static void
delete_msglist(b_msg)
struct pop_msg *b_msg;
{
        struct pop_msg *msg,*msg2;
        msg=b_msg;
        while(msg!=NULL) {msg2=msg->next; free(msg); msg=msg2;}
}

/* Free resources, delete control block */

static void
delete_scb(scb)
register struct pop_scb *scb;
{
        if (scb == NULLSCB)
                return;
        if (scb->wf != NULL)
                fclose(scb->wf);
        if (scb->msg  != NULL)
                delete_msglist(scb->msg);

        free((char *)scb);
}

/* replace terminating end of line marker(s) (\r and \n) with null,
                        and change . to .. */
static void
rrip(s)
register char *s;
{
        register char *cp;

        if((cp = strchr(s,'\r')) != NULLCHAR)
                *cp = '\0';
#ifndef TNOS_68K
	if((cp = strchr(s,'\n')) != NULLCHAR)
#else
	if((cp = strchr(s,'\l')) != NULLCHAR)
#endif
                *cp = '\0';
}

/* --------------------- start of POP server code ------------------------ */

#define BITS_PER_WORD   16

#define isSOM(x)        ((strncmp(x,"From ",5) == 0))

/* Command string specifications */

static char
                user_cmd[] = "USER ",
                pass_cmd[] = "PASS ",
                quit_cmd[] = "QUIT",
                stat_cmd[] = "STAT",
                list_cmd[] = "LIST",
                retr_cmd[] = "RETR",
                dele_cmd[] = "DELE",
                noop_cmd[] = "NOOP",
                rset_cmd[] = "RSET",
                top_cmd[]  = "TOP",
                last_cmd[] = "LAST";

static void
pop_sm(scb)
struct pop_scb *scb;
{
        char password[40];


        if (scb == NULLSCB) /* be certain it is good -- wa6smn */
                return;

        switch(scb->state) {

        case AUTH:
                if (strncmp(scb->buf,user_cmd,strlen(user_cmd)) == 0){
                        sscanf(scb->buf,"USER %s",scb->username);
                        (void) usprintf(scb->socket,user_rsp);

                } else if (strncmp(scb->buf,pass_cmd,strlen(pass_cmd)) == 0){
                        sscanf(scb->buf,"PASS %s",password);

                        if (!poplogin(scb->username,password)) {
                                log(scb->socket,"POP3 access DENIED to %s",
                                                scb->username);
                                state_error(scb,"Access DENIED!!");
                                return;
                        }

                        log(scb->socket,"POP3 access granted to %s",
                                        scb->username);
                        open_folder(scb);
                } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
                        do_cleanup(scb);
                } else
                        state_error(scb,"(AUTH) expected USER, PASS or QUIT");
                break;

        case TRANS:
                if (strncmp(scb->buf,stat_cmd,strlen(stat_cmd)) == 0)
                        stat_message(scb);

                else if (strncmp(scb->buf,list_cmd,strlen(list_cmd)) == 0)
                        list_message(scb);

                else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
                        retr_message(scb);

                else if (strncmp(scb->buf,dele_cmd,strlen(dele_cmd)) == 0)
                        dele_message(scb);

                else if (strncmp(scb->buf,last_cmd,strlen(noop_cmd)) == 0)
                        noop_message(scb);

                else if (strncmp(scb->buf,last_cmd,strlen(last_cmd)) == 0)
                        last_message(scb);

                else if (strncmp(scb->buf,top_cmd,strlen(top_cmd)) == 0)
                        top_message(scb);

                else if (strncmp(scb->buf,rset_cmd,strlen(rset_cmd)) == 0)
                        rset_message(scb);

                else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
                        do_cleanup(scb);

                else
                        state_error(scb,
                                        "(TRANS) unsupported/unrecognized command");
                break;

        case DONE:
                break;

        default:
                fatal_error(scb,"(TOP) State Error!!");
                break;
        }
}

static void
#ifdef PROTOTYPES
do_cleanup(struct pop_scb *scb)
#else
do_cleanup(scb)
struct pop_scb *scb;
#endif
{
        void close_folder __ARGS((struct pop_scb *));

        close_folder(scb);
        (void) usprintf(scb->socket,signoff_msg);
        scb->state = DONE;
}

static void
#ifdef PROTOTYPES
state_error(struct pop_scb *scb,char *msg)
#else
state_error(scb,msg)
struct pop_scb *scb;
char *msg;
#endif
{
        (void) usprintf(scb->socket,error_rsp,msg);
        /* scb->state = DONE; */  /* Don't automatically hang up */
}

static void
#ifdef PROTOTYPES
fatal_error(struct pop_scb *scb,char *msg)
#else
fatal_error(scb,msg)
struct pop_scb *scb;
char *msg;
#endif
{
        (void) usprintf(scb->socket,error_rsp,msg);
        scb->state = DONE;
}

static void
#ifdef PROTOTYPES
close_folder(struct pop_scb *scb)
#else
close_folder(scb)
struct pop_scb *scb;
#endif
{
        char folder_pathname[64];
        char line[TLINELEN+1];
        FILE *fd;
        int deleted = FALSE;
        int msg_no = 0;
        struct pop_msg *msg;
        void state_error __ARGS((struct pop_scb *,char *));
        void fatal_error __ARGS((struct pop_scb *,char *));
	char *cp;
	int firstIDline = 0, nextisBID = 0;
	int lines = 0;
	long last;
	struct let lt;


        if (scb->wf == NULL)
                return;

        if (!scb->folder_modified) {
                /* no need to re-write the folder if we have not modified it */

                fclose(scb->wf);
                scb->wf = NULL;

                delete_msglist(scb->msg);
                scb->msg=NULL;
                return;
        }


        sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);

        if (newmail(scb)) {
                /* copy new mail into the work file and save the
                                        message count for later */

                if ((fd = fopen(folder_pathname,"r")) == NULL) {
                        fatal_error(scb,"Unable to add new mail to folder");
                        return;
                }

                fseek(scb->wf,0,SEEK_END);
                fseek(fd,scb->folder_file_size,SEEK_SET);
                while (!feof(fd)) {
                        fgets(line,TLINELEN,fd);
                        fputs(line,scb->wf);
                }

                fclose(fd);
        }

        /* now create the updated mail folder */

        if ((fd = fopen(folder_pathname,"w")) == NULL){
                fatal_error(scb,"Unable to update mail folder");
                return;
        }

        rewind(scb->wf);

	sprintf(line,"%s/control/%s.ctl",Mailspool,scb->username);
	remove (line);
	lt.start = last = 0;

        msg=scb->msg;
        while (!feof(scb->wf)){
                fgets(line,TLINELEN,scb->wf);
                if (feof(scb->wf))
                	continue;
		pwait(NULL);	/* give other processes time in long copy */

                if (isSOM(line)){
			lt.size = last - lt.start - lines; 
			if (lt.size && (deleted == FALSE))
				updateCtl (scb->username, &lt);
			lines = lt.status = 0;
			lt.start = last;
			firstIDline = 0;

                        if (msg!=NULL) msg=msg->next;
                        msg_no++;
                        if (msg!=NULL)
                                deleted = msg->deleted;
                        else
                                deleted = FALSE;
                }

		lines++;
		if (!firstIDline && nextisBID && (cp=strstr(line,"AA")) != NULLCHAR) {
			/*what follows is the message-number*/
			lt.bid = atol(cp+2);
			nextisBID = 0;
			firstIDline = 1;
			}

		if (!strncmp ("Received: ", line, 10))
			nextisBID = 1;
		if (!strncmp ("Status: R", line, 9))
			lt.status = BM_READ;

                if (deleted)
                        continue;

                fputs(line,fd);
		last = ftell (fd);
        }
	lt.size = last - lt.start - lines;
	if (deleted == FALSE)
		updateCtl (scb->username, &lt);

        fclose(fd);
        fclose(scb->wf);
        scb->wf = NULL;
        delete_msglist(scb->msg);
        scb->msg=NULL;

}

static void
#ifdef PROTOTYPES
open_folder(struct pop_scb *scb)
#else
open_folder(scb)
struct pop_scb *scb;
#endif
{
        char folder_pathname[64];
        char line[TLINELEN];
        long pos;
        FILE *fd;
	FILE *tmpfile __ARGS((void));
        struct stat folder_stat;
        struct pop_msg *msg;

        sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
        scb->folder_len       = 0;
        scb->folder_file_size = 0;
        /* if (stat(folder_pathname,&folder_stat)){ */
        if((folder_stat.st_size = fsize(folder_pathname)) == -1) { /* N1BEE */
                (void) usprintf(scb->socket,count_rsp,scb->folder_len);
                scb->state  = TRANS;
                return;         /* no file = OK */
        }

        scb->folder_file_size = folder_stat.st_size;
        if ((fd = fopen(folder_pathname,"r")) == NULL){
                state_error(scb,"Unable to open mail folder");
                return;
        }

        if ((scb->wf = tmpfile()) == NULL) {
                state_error(scb,"Unable to create work folder");
                return;
        }

        scb->msg=calloc(sizeof(struct pop_msg),1); /* create first element */
        if (scb->msg==NULL)
        {
                fatal_error(scb,"Unable to create pointer list");
                return;
        }
        scb->msg->next=NULL;
        msg=scb->msg;
        msg->len=0;
        msg->deleted=0;

        while(!feof(fd)) {
                pos=ftell(scb->wf);
                fgets(line,TLINELEN,fd);

                /* scan for begining of a message */

                if (isSOM(line))
                {
                        scb->folder_len++;
                        msg->next=calloc(sizeof(struct pop_msg),1);
                        if (msg->next==NULL)
                        {
                                fatal_error(scb,
                                                "Unable to create pointer list")
;
                                return;
                        }
                        msg=msg->next;
                        msg->pos=pos;
                        msg->next=NULL;
                        msg->len=0;
                        msg->deleted=0;

                /* now put  the line in the work file */
                }
                fputs(line,scb->wf);
                rrip(line);
                if ( *line == '.' ) msg->len++;
                msg->len +=strlen(line)+2; /* Add msg len count */
        }

        fclose(fd);
        scb->high_num=0;  /* reset high read */

        (void) usprintf(scb->socket,count_rsp,scb->folder_len);

        scb->state  = TRANS;
}

static void
#ifdef PROTOTYPES
stat_message(struct pop_scb *scb)
#else
stat_message(scb)
struct pop_scb *scb;
#endif
{
        long total=0;
        int count=0;
        struct pop_msg *msg;

        if (scb == NULLSCB) /* check for null -- wa6smn */
                return;

        if (scb->folder_len)    /* add everything up */
                for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
                        if (!msg->deleted)
                                {       total += msg->len; ++count;}

        (void) usprintf(scb->socket,stat_rsp,count,total);
}

static void
#ifdef PROTOTYPES
list_message(struct pop_scb *scb)
#else
list_message(scb)
struct pop_scb *scb;
#endif
{
        struct pop_msg *msg;
        int msg_no=0;
        long total=0;

        if (scb == NULLSCB) /* check for null -- wa6smn */
                return;
        if (scb->buf[sizeof(list_cmd) - 1] == ' ')
        {
                msg_no = atoi(&(scb->buf[sizeof(list_cmd) - 1]));
                msg=goto_msg(scb,msg_no);
                if (msg==NULL || msg->deleted)
                        state_error(scb,"non existent or deleted message");
                else
                        (void) usprintf(scb->socket,list_single_rsp,
                        msg_no,msg->len);
        } else  /* multiline */
        {
                if (scb->folder_len)            /* add everything */
                        for (msg=scb->msg->next; msg!=NULL;msg=msg->next)
                                if (!msg->deleted)
                total += msg->len,++msg_no;

                (void) usprintf(scb->socket,list_multi_rsp,
                                msg_no,total);

                if (scb->folder_len)
                        for (msg=scb->msg->next,msg_no=1; msg!=NULL;
                                        msg=msg->next,msg_no++)
                                if (!msg->deleted) {
                                        (void) usprintf(scb->socket,"%d %ld\n",
                                                msg_no,msg->len);
                                }
                (void) usprintf(scb->socket,multi_end_rsp);
        }
}

static void
#ifdef PROTOTYPES
retr_message(struct pop_scb *scb)
#else
retr_message(scb)
struct pop_scb *scb;
#endif
{
        char line[TLINELEN];
        long cnt;
        int msg_no;
        struct pop_msg *msg;
        struct pop_msg *goto_msg __ARGS((struct pop_scb *,int ));

        if (scb == NULLSCB) /* check for null -- wa6smn */
                return;
        if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
        {
                state_error(scb,"no such message");
                return;
        }
        msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
        msg=goto_msg(scb,msg_no);
        if (msg==NULL || msg->deleted) {
                state_error(scb,"no such message");
                return;
        }

        cnt  = msg->len;
        (void) usprintf(scb->socket,retr_rsp,cnt);
        fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */

        while(!feof(scb->wf) && (cnt > 0)) {
                fgets(line,TLINELEN,scb->wf);
                rrip(line);
                if ( *line == '.' ) {
                        (void) usprintf(scb->socket,".");
                        cnt--;
                }
                (void) usprintf(scb->socket,msg_line,line);
                cnt -= (strlen(line)+2); /* Compensate for CRLF */
        }
        (void) usprintf(scb->socket,".\n");
        if (msg_no >= scb->high_num)
                scb->high_num=msg_no;     /* bump high water mark */
}

static void
#ifdef PROTOTYPES
noop_message(struct pop_scb *scb)
#else
noop_message(scb)
struct pop_scb *scb;
#endif
{
                (void) usprintf(scb->socket,noop_rsp);
}

static void
#ifdef PROTOTYPES
last_message(struct pop_scb *scb)
#else
last_message(scb)
struct pop_scb *scb;
#endif
{
        (void) usprintf(scb->socket,last_rsp,scb->high_num);
}

static void
#ifdef PROTOTYPES
rset_message(struct pop_scb *scb)
#else
rset_message(scb)
struct pop_scb *scb;
#endif
{
        struct pop_msg *msg;
        long total=0;

        if (scb->folder_len)
                for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
                        msg->deleted=FALSE,total+=msg->len;

        scb->high_num=0;  /* reset last */
        scb->folder_modified=FALSE;
        (void) usprintf(scb->socket,list_multi_rsp,scb->folder_len,total);
}

static void
#ifdef PROTOTYPES
top_message(struct pop_scb *scb)
#else
top_message(scb)
struct pop_scb *scb;
#endif
{
        char *ptr;
        char line[TLINELEN];
        struct pop_msg *msg;
        int msg_no=0,lines=0;
        long total=0;

        struct pop_msg *goto_msg __ARGS((struct pop_scb *,int ));

        if (scb == NULLSCB) /* check for null -- wa6smn */
                return;
        if (scb->buf[sizeof(top_cmd) - 1] != ' ')
        {
                state_error(scb,"No message specified");
                return;
        }
        for (ptr=scb->buf+sizeof(top_cmd); *ptr==' ' ; ++ptr);
                /* Space drop */
        for ( ; *ptr!=' ' && *ptr !='\0'; ++ptr);
                /* token drop */
        msg_no = atoi(&(scb->buf[sizeof(top_cmd) - 1]));
        lines = atoi(++ptr);  /* Get # lines to top */
        if (lines < 0) lines=0;

        msg=goto_msg(scb,msg_no);
        if (msg==NULL || msg->deleted)
        {
                state_error(scb,"non existent or deleted message");
                return;
        }
        fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
        total=msg->len;  /* Length of current message */
        (void) usprintf(scb->socket,noop_rsp);  /* Give OK */
        do {
                fgets(line,TLINELEN,scb->wf);
                rrip(line);
                if ( *line == '.' ) {
                        (void) usprintf(scb->socket,".");
                        total--;
                }
                total -= strlen(line)+2;
                (void) usprintf(scb->socket,msg_line,line);
        } while (*line!='\0' && total>0);
        for ( ; total > 0 && lines; --lines) {
                fgets(line,TLINELEN,scb->wf);
                rrip(line);
                if ( *line == '.' ) {
                        (void) usprintf(scb->socket,".");
                        total--;
                }
                total -= strlen(line)+2;
                (void) usprintf(scb->socket,msg_line,line);
        }
        (void) usprintf(scb->socket,multi_end_rsp);
}

static int
poplogin(username,pass)
char *pass;
char *username;
{
        char buf[80];
        char *cp = NULLCHAR;
        char *cp1;
        FILE *fp;

        if((fp = fopen(Popusers,"r")) == NULLFILE) {
                /* User file doesn't exist */
                tprintf("POP users file %s not found\n",Popusers);
                return(FALSE);
        }

        while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
                if(buf[0] == '#')
                        continue; /* Comment */

                if((cp = strchr(buf,':')) == NULLCHAR)
                        /* Bogus entry */
                        continue;

                *cp++ = '\0';  /* Now points to password */
                if(strcmp(username,buf) == 0)
                        break;  /* Found user name */
        }

        if(feof(fp)) {
                /* User name not found in file */

                fclose(fp);
                return(FALSE);
        }
        fclose(fp);

        if ((cp1 = strchr(cp,':')) == NULLCHAR)
                return(FALSE);

        *cp1 = '\0';
        if(strcmp(cp,pass) != 0) {
                /* Password required, but wrong one given */

                return(FALSE);
        }

        /* whew! finally made it!! */

        return(TRUE);
}

static void
#ifdef PROTOTYPES
dele_message(struct pop_scb *scb)
#else
dele_message(scb)
struct pop_scb *scb;
#endif
{
        struct pop_msg *msg;
        int msg_no;
        struct pop_msg *goto_msg __ARGS((struct pop_scb *,int ));

        if (scb == NULLSCB) /* check for null -- wa6smn */
                return;
        if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
        {
                state_error(scb,"no such message");
                return;
        }
        msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
        msg=goto_msg(scb,msg_no);
        if (msg==NULL || msg->deleted) {
                state_error(scb,"attempt to access deleted message");
                return;
        }
        if (msg->deleted) /* Don't bother if already dead */
        {
                        state_error(scb,"message already deleted");
                        return;
        }
        msg->deleted=TRUE;
        scb->folder_modified = TRUE;
        (void) usprintf(scb->socket,dele_rsp,msg_no);
}

static int
#ifdef PROTOTYPES
newmail(struct pop_scb *scb)
#else
newmail(scb)
struct pop_scb *scb;
#endif
{
        char folder_pathname[64];
        struct stat folder_stat;

        sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);

        /* if (stat(folder_pathname,&folder_stat)) { */
        if((folder_stat.st_size = fsize(folder_pathname)) == -1) { /* N1BEE */
                state_error(scb,"Unable to get old mail folder's status");
                return(FALSE);
        } else
                return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
}

static struct pop_msg *
goto_msg(scb,msg_no)
struct pop_scb *scb;
int msg_no;
{
        int msg_num;
        struct pop_msg *msg;

        msg_num=msg_no-1;
        if (scb->folder_len==0 || msg_num < 0)
                        return NULL;
        for (msg=scb->msg->next; msg_num && msg!=NULL; --msg_num) msg=msg->next;
        return msg;
}


#endif
