home *** CD-ROM | disk | FTP | other *** search
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <time.h>
- #include <ctype.h>
- #include <string.h>
- #include "global.h"
- #include "timer.h"
- #include "cmdparse.h"
- #include "netuser.h"
- #include "pop.h"
- #include "smtp.h"
- #include "domain.h"
- #include "misc.h"
- #include "tcp.h"
- #include "mbuf.h"
- #include "Terminal.h"
- #include "vterm.h"
-
- #include "os.h"
- #include "swis.h"
-
- typedef enum {
- state_IDLE,
- state_RECM,
- state_USER,
- state_PASS,
- state_QUIT,
- state_LIST,
- state_LISTANS,
- state_LISTREC,
- state_RETR,
- state_RETRANS,
- state_RETRREC,
- state_DELETE
- };
-
-
- struct messages {
- struct messages *next;
- int msg_id;
- int msg_size;
- };
-
- static struct popservers {
- struct timer pop_t;
- char *name;
- char *abbr;
- char *user;
- char *pwd;
- int lowtime, hightime; /* for connect window */
- struct popservers *next;
- struct tcb *tcb; /* tcp task control buffer */
- int32 ipdest; /* address of forwarding system */
- char state; /* state machine placeholder */
- char stage; /* another state machine placeholder */
- char buf[LINELEN]; /* Input buffer */
- int cnt; /* Length of input buffer */
- char locked;
- long msgstart; /* Place holder for writing mail separator */
- FILE *mail;
- char ismulti;
- char quit;
- struct messages *msgs;
- Terminal *window;
- };
-
- extern int16 lport; /* local port placeholder */
-
- struct popservers *POPservers = NULL;
- int trace = 0;
-
- static char *seps[] = {"From", "Ctrl-A", "#! rnews", "#! rmail"};
- static int pop_sep = sep_UNIX;
-
- static void poptick( void * );
- static void pop_rec(struct tcb *, int16);
- static void pop_cts(struct tcb *, int16);
- static void pop_state(struct tcb *, char, char);
- static void pop_transaction( struct popservers * );
- static int lock_spoolfile( struct popservers * );
- static int dosep(int argc, char *argv[]);
-
-
- static void pop_cts(struct tcb *tcb, int16 cnt)
- {
- tcb = tcb;
- cnt = cnt;
- /* we actually don't use it */
- }
-
-
- static void pop_state(register struct tcb *tcb, char old, char new)
- {
- register struct popservers *cb;
- extern char *tcpstates[];
-
- old = old;
-
- cb = (struct popservers *)tcb->user;
- if (trace > 4)
- cwprintf(cb->window, "pop_state called: %s\n",tcpstates[new]);
-
- switch(new)
- {
- case ESTABLISHED:
- cb->state = state_USER; /* shouldn't be needed */
- cb->cnt = 0;
- cb->ismulti = 0;
- cb->quit = 1;
- cb->msgs = NULL;
- if (lock_spoolfile(cb))
- close_tcp(tcb);
- break;
- case CLOSE_WAIT:
- close_tcp(tcb); /* shut things down */
- break;
- case CLOSED:
- if (cb->locked )
- rmlock( mailspool, cb->user );
- if (cb->mail )
- {
- long len;
- char mailbox[200];
- fseek( cb->mail, 0, SEEK_END); /* check for 0 length file */
- len = ftell(cb->mail);
- fclose( cb->mail );
- if (!len) /* dispose of 0 length file */
- {
- sprintf(mailbox,"%s.text.%s",mailspool,cb->user);
- remove(mailbox);
- }
- }
-
- /* if this close was not done by us ie. a RST */
- del_tcp(tcb);
- if (cb->window)
- {
- cb->window->Attr = ATTR_REVERSE;
- cb->window->Flags.flags.dont_destroy = FALSE;
- Window_Close(cb->window);
- cb->window = NULL;
- }
- start_timer(&cb->pop_t);
- break;
- }
- }
-
- static void pop_rec(struct tcb *tcb, int16 cnt)
- {
- register struct popservers *cb;
- char c;
- struct mbuf *bp;
-
- if (trace > 4)
- {
- cwprintf(cb->window, "pop_rec called\n");
- }
-
- if((cb = (struct popservers *)tcb->user) == NULL) /* point to our struct */
- {
- close_tcp(tcb);
- return;
- }
- recv_tcp(tcb,&bp,cnt); /* suck up chars from low level routine */
-
- /* Assemble input line in buffer, return if incomplete */
- while(pullone(&bp,&c) == 1)
- {
- switch(c)
- {
- case '\r': /* strip cr's */
- continue;
- case '\n': /* line is finished, go do it! */
- cb->buf[cb->cnt] = '\0';
- pop_transaction(cb);
- cb->cnt = 0;
- break;
- default: /* other chars get added to buffer */
- cb->buf[cb->cnt++] = c;
- if(cb->cnt > LINELEN - 2)
- {
- cb->buf[cb->cnt] = '\0';
- pop_transaction(cb);
- cb->cnt = 0;
- }
- break;
- }
- }
- }
-
-
- /* Send message back to server */
- static void sendit(struct popservers *cb, char *fmt, ...)
- {
- va_list argptr;
- struct mbuf *bp;
- char tmpstring[256];
-
- va_start(argptr,fmt);
- vsprintf(tmpstring,fmt,argptr);
- va_end(argptr);
-
- if (trace > 3)
- {
- cwprintf(cb->window, ">>> %s\n", tmpstring);
- }
- bp = qdata(tmpstring,(int16)strlen(tmpstring));
- send_tcp(cb->tcb,bp);
- }
-
-
- static void clear_msglist( struct popservers *cb )
- {
- struct messages *msg;
- struct messages *msgnext;
-
- for (msg = cb->msgs; msg; msg = msgnext)
- {
- msgnext = msg->next;
- free(msg);
- }
- }
-
-
- static int eof( struct popservers *cb )
- {
- return(!strcmp( cb->buf, "." ));
- }
-
-
- static void pop_transaction( struct popservers *cb )
- {
- char error = 0;
- int cont = 1;
- time_t t;
- int fail = 0;
-
- if (trace > 5 || (trace > 3 && !cb->ismulti))
- cwprintf(cb->window, "<<< %s\n", cb->buf );
- if (!cb->ismulti)
- error = cb->buf[0] == '-';
- if (error)
- {
- cwprintf(cb->window, "POP error: %s\n", cb->buf);
- if (cb->quit)
- cb->state = state_QUIT;
- }
-
- while( cont )
- {
- cont = 0;
- switch( cb->state )
- {
-
- case state_QUIT:
- clear_msglist( cb );
- if (!cb->quit)
- break;
- sendit( cb, "QUIT\r\n" );
- if (! --(cb->quit))
- cb->state = state_IDLE;
- break;
-
- case state_USER:
- sendit( cb, "USER %s\r\n", cb->user );
- cb->state = state_PASS;
- break;
-
- case state_PASS:
- sendit( cb, "PASS %s\r\n", cb->pwd );
- cb->state = state_LIST;
- break;
-
- case state_LIST:
- cb->quit = 2; /* we need double quit to quit here */
- sendit( cb, "LIST\r\n" );
- cb->state = state_LISTANS;
- break;
-
- case state_LISTANS:
- cb->state = state_LISTREC;
- cb->ismulti = 1;
- break;
-
- case state_LISTREC:
- if (eof(cb))
- {
- if (trace>4 )
- cwprintf(cb->window, "end of list\n" );
- cb->ismulti = 0, cb->state = state_RETR;
- cont = 1;
- }
- else
- {
- struct messages *msg;
-
- if (trace > 4)
- cwprintf(cb->window, "adding to list: %s\n", cb->buf );
- msg = malloc( sizeof(*msg) );
- if (!msg)
- cwprintf(cb->window, "POP: fatal error: memory overflow\n" );
- msg->next = cb->msgs;
- cb->msgs = msg;
- sscanf( cb->buf, "%d %d", &msg->msg_id, &msg->msg_size );
- }
- break;
-
- case state_RETR:
- if ( !cb->msgs )
- {
- cb->state = state_QUIT;
- cont = 1;
- }
- else
- {
- if (trace )
- cwprintf(cb->window, "retrieving message %d\n", cb->msgs->msg_id );
- sendit( cb, "RETR %d\r\n", cb->msgs->msg_id );
- cb->state = state_RETRANS;
- }
- break;
-
- case state_RETRANS:
- cb->state = state_RETRREC;
- cb->ismulti = 1;
- time(&t);
- if (pop_sep==sep_UNIX)
- fprintf(cb->mail,"From %s",ctime(&t));
- else if (pop_sep==sep_RMAIL)
- fprintf(cb->mail,"#! rmail \n");
- else if (pop_sep==sep_RNEWS)
- fprintf(cb->mail,"#! rnews \n");
- else if (pop_sep==sep_CTLA)
- fprintf(cb->mail, "%c\n", 0x01);
- if (ferror( cb->mail ) )
- fail = 1;
- cb->msgstart = ftell(cb->mail);
- break;
-
- case state_RETRREC:
- if (eof(cb) )
- {
- fprintf( cb->mail, "\n" );
- if (ferror( cb->mail ) )
- fail=1;
- else
- {
- if (pop_sep==sep_RMAIL || pop_sep==sep_RNEWS)
- {
- long p = ftell(cb->mail);
- fseek(cb->mail, cb->msgstart+9, SEEK_SET);
- fprintf(cb->mail,"%.8ld",p-cb->msgstart);
- fseek(cb->mail, p, SEEK_SET);
- }
- }
- cb->ismulti = 0, cb->state = state_DELETE;
- cont=1;
- }
- else
- {
- /* '.' unescaping and "From " escaping */
- if (*cb->buf=='.')
- fprintf( cb->mail, "%s\n", cb->buf+1 );
- else if (pop_sep==sep_UNIX && !strncmp(cb->buf, "From ", 5))
- fprintf( cb->mail, ">%s\n", cb->buf );
- else
- fprintf( cb->mail, "%s\n", cb->buf );
- if (ferror( cb->mail ) )
- fail=1;
- }
- break;
-
- case state_DELETE:
- if (fail )
- {
- cwprintf(cb->window, "POP: fatal error - mail left on pop server\n" );
- cb->state = state_QUIT;
- cont = 1;
- break;
- }
- sendit( cb, "DELE %d\r\n", cb->msgs->msg_id );
- cb->state = state_RETR;
- {
- struct messages *msg;
- msg = cb->msgs;
- cb->msgs = cb->msgs->next;
- free(msg);
- }
- break;
- }
- }
- }
-
- static int lock_spoolfile( struct popservers * cb )
- {
- char mailbox[200];
-
- if (mlock(mailspool,cb->user))
- {
- cwprintf(cb->window, "POP: error: spool file locked - try later\n" );
- return 1;
- }
- else
- {
- sprintf(mailbox,"%s.text.%s",mailspool,cb->user);
- if((cb->mail = fopen(mailbox,"a+")) != NULLFILE)
- {
- cb->locked = 1;
- return 0;
- }
- else rmlock(mailspool,cb->user);
- }
- return 1;
- }
-
-
- static int doadds(int argc, char *argv[])
- {
- struct popservers *pop;
- int i;
-
- for(pop = POPservers; pop != NULL; pop = pop->next)
- if(stricmp(pop->abbr,argv[5]) == 0) /* ought to be stricmp */
- break;
- if (pop == NULL)
- {
- pop = (struct popservers *) calloc(1,sizeof(struct popservers));
- pop->name = strdup(argv[1]);
- pop->abbr = strdup(argv[5]);
- pop->ipdest = resolve(argv[1]);
- pop->user = strdup(argv[3]);
- pop->pwd = strdup(argv[4]);
- pop->next = POPservers;
- POPservers = pop;
- pop->lowtime = pop->hightime = -1;
- pop->pop_t.func = poptick; /* what to call on timeout */
- pop->pop_t.arg = (void *)pop;
- pop->state = state_IDLE;
- }
- for (i = 5; i < argc; ++i)
- {
- if (isdigit(*argv[i]))
- {
- int lh, ll, hh, hl;
- sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
- pop->lowtime = lh * 100 + ll;
- pop->hightime = hh * 100 + hl;
- }
- }
- /* set timer duration */
- set_timer(&pop->pop_t,atol(argv[2])*1000L);
- start_timer(&pop->pop_t); /* and fire it up */
-
- return 0;
- }
-
- static int dodrops(int argc, char *argv[])
- {
- struct popservers *pop, *popprev = NULL;
-
- for(pop = POPservers; pop != NULL; popprev = pop, pop = pop->next)
- {
- if (stricmp(pop->name, argv[1]) == 0 || stricmp(pop->abbr, argv[1]) == 0)
- if (pop->state == state_IDLE )
- {
- stop_timer(&pop->pop_t);
- free(pop->name);
- free(pop->abbr);
- free(pop->user);
- free(pop->pwd);
- if(popprev != NULL)
- popprev->next = pop->next;
- else
- POPservers = pop->next;
- free((char *)pop);
- return 0;
- }
- }
- cwprintf(NULL, "POP - No such server enabled.\n");
- return 0;
- }
-
- static int dokicks(int argc, char *argv[])
- {
- struct popservers *pop;
-
- for (pop = POPservers; pop != NULL; pop = pop->next)
- {
- if (stricmp(pop->name, argv[1]) == 0 || stricmp(pop->abbr, argv[1]) == 0)
- {
- /* If the timer is not running, the timeout function has
- * already been called and we don't want to call it again.
- */
- if(run_timer(&pop->pop_t))
- {
- stop_timer(&pop->pop_t);
- poptick((void *)pop);
- }
- else
- {
- cwprintf(NULL, "POP - Can't restart\n");
- }
- return 0;
- }
- }
- cwprintf(NULL, "POP - No such server enabled.\n");
- return 0;
- }
-
-
-
- static int dolists(int argc, char *argv[])
- {
- struct popservers *pop;
-
- for (pop = POPservers; pop != NULL; pop = pop->next)
- {
- char tbuf[80];
-
- if (pop->lowtime != -1 && pop->hightime != -1)
- sprintf(tbuf, " -- %02d:%02d-%02d:%02d", pop->lowtime/100, pop->lowtime%100, pop->hightime/100, pop->hightime%100);
- else
- tbuf[0] = '\0';
- cwprintf(NULL, "%-32s (%lu/%lu%s)\n", pop->name,
- read_timer(&pop->pop_t) /1000L,
- dur_timer(&pop->pop_t) /1000L,
- tbuf);
- }
- return 0;
- }
-
-
-
- static int dopoptrace(int argc, char **argv)
- {
- if (argc < 2)
- cwprintf(NULL, "%d\n",trace);
- else
- trace = atoi(argv[1]);
- return 0;
- }
-
-
- static void poptick(void *tp)
- {
- char title[80];
- struct socket lsocket, fsocket;
- register struct popservers *cb;
-
- cb = (struct popservers *) tp;
- if (cb == NULL)
- return;
- if(cb->state != state_IDLE)
- return;
-
- sprintf(title, "POP - %s", cb->name);
- cb->window = Window_Open(NULL, title, term_NO_INPUT);
- vterm_visible(cb->window->vt, 40, 8);
- vterm_setflags(cb->window->vt, VTSW_WRAP, VTSW_WRAP);
- /* setup the socket */
- fsocket.address = cb->ipdest;
- fsocket.port = POP_PORT;
- lsocket.address = ip_addr; /* our ip address */
- lsocket.port = lport++; /* next unused port */
-
- if (trace)
- {
- cwprintf(cb->window, "POP daemon entered\n",inet_ntoa(fsocket.address));
- }
-
- if (trace > 1)
- {
- cwprintf(cb->window, "POP trying Connection to %s\n",inet_ntoa(fsocket.address));
- }
- stop_timer(&cb->pop_t);
-
- /* open pop connection */
- cb->state = state_USER; /* init state placeholder */
- cb->tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, tcp_window,
- (void(*)())pop_rec, (void(*)())pop_cts, (void(*)())pop_state, 0, (char *)cb);
- cb->tcb->user = (char *)cb; /* Upward pointer */
- }
-
-
-
- struct cmds popcmds[] = {
- "addserver", doadds, 4, "pop addserver <name> <time> <user> <password> <abbr>", NULLCHAR,
- "dropserver", dodrops, 2, "pop dropserver <name|abbr>", NULLCHAR,
- "kick", dokicks, 2, "pop kick <name|abbr>", NULLCHAR,
- "listserver", dolists, 0, NULLCHAR, NULLCHAR,
- "separator", dosep, 1, "pop separator A|U|RN|RM", NULLCHAR,
- "trace", dopoptrace, 0, NULLCHAR, NULLCHAR,
- NULLCHAR
- };
-
- int dopop(int argc, char **argv)
- {
- return subcmd(popcmds,argc,argv);
- }
-
- static int dosep(int argc, char *argv[])
- {
- if (argc < 2)
- {
- cwprintf(NULL, "pop separator: %s\r\n", seps[pop_sep]);
- }
- else
- {
- switch(tolower(*argv[1]))
- {
- case 'a':
- case '^':
- pop_sep = sep_CTLA;
- break;
- case 'r':
- if (tolower(*(argv[1]+1))=='m')
- pop_sep = sep_RMAIL;
- else
- pop_sep = sep_RNEWS;
- break;
- default:
- pop_sep = sep_UNIX;
- break;
- }
- }
- return 0;
- }
-
-