📄 ipop3d.c
字号:
/* * Program: IPOP3D - IMAP to POP3 conversion server * * Author: Mark Crispin * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 1 November 1990 * Last Edited: 3 August 2000 * * Copyright 2000 by the University of Washington * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appears in all copies and that both the * above copyright notice and this permission notice appear in supporting * documentation, and that the name of the University of Washington not be * used in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. This software is made * available "as is", and * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */#define PBIN getchar#define PSIN(s,n) fgets (s,n,stdin)#define PBOUT(c) putchar (c)#define PSOUT(s) fputs (s,stdout)#define PFLUSH fflush (stdout)#define CRLF PSOUT ("\015\012")/* Parameter files */#include <stdio.h>#include <ctype.h>#include <errno.h>extern int errno; /* just in case */#include <signal.h>#include <time.h>#include "c-client.h"/* Autologout timer */#define KODTIMEOUT 60*5#define LOGINTIMEOUT 60*3#define TIMEOUT 60*10/* Size of temporary buffers */#define TMPLEN 1024/* Server states */#define AUTHORIZATION 0#define TRANSACTION 1#define UPDATE 2#define LOGOUT 3/* Eudora food */#define STATUS "Status: %s%s\015\012"#define SLEN (sizeof (STATUS)-3)/* Global storage */char *version = "2000.68"; /* server version */short state = AUTHORIZATION; /* server state */short critical = NIL; /* non-zero if in critical code */MAILSTREAM *stream = NIL; /* mailbox stream */long idletime = 0; /* time we went idle */unsigned long nmsgs = 0; /* current number of messages */unsigned long ndele = 0; /* number of deletes */unsigned long last = 0; /* highest message accessed */unsigned long il = 0; /* initial last message */char challenge[128]; /* challenge */char *host = NIL; /* remote host name */char *user = NIL; /* user name */char *pass = NIL; /* password */char *initial = NIL; /* initial response */long *msg = NIL; /* message translation vector */char *sayonara = "+OK Sayonara\015\012";/* Function prototypes */int main (int argc,char *argv[]);void clkint ();void kodint ();void hupint ();void trmint ();int login (char *t,int argc,char *argv[]);char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);char *responder (void *challenge,unsigned long clen,unsigned long *rlen);int mbxopen (char *mailbox);long blat (char *text,long lines,unsigned long size);void rset ();/* Main program */int main (int argc,char *argv[]){ unsigned long i,j,k; char *s,*t; char tmp[TMPLEN]; time_t autologouttime;#include "linkage.c" /* initialize server */ server_init (argv[0],"pop3","pop3s","pop",clkint,kodint,hupint,trmint); challenge[0] = '\0'; /* find the CRAM-MD5 authenticator */ if (i = mail_lookup_auth_name ("CRAM-MD5",NIL)) { AUTHENTICATOR *a = mail_lookup_auth (i); if (a->server) { /* have an MD5 enable file? */ /* build challenge -- less than 128 chars */ sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (), (unsigned long) time (0),tcp_serverhost ()); } } /* There are reports of POP3 clients which get upset if anything appears * between the "+OK" and the "POP3" in the greeting. */ PSOUT ("+OK POP3"); if (!challenge[0]) { /* if no MD5 enable, output host name */ PBOUT (' '); PSOUT (tcp_serverhost ()); } PSOUT (" v"); PSOUT (version); PSOUT (" server ready"); if (challenge[0]) { /* if MD5 enable, output challenge here */ PBOUT (' '); PSOUT (challenge); } CRLF; PFLUSH; /* dump output buffer */ autologouttime = time (0) + LOGINTIMEOUT; /* command processing loop */ while ((state != UPDATE) && (state != LOGOUT)) { idletime = time (0); /* get a command under timeout */ alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT); clearerr (stdin); /* clear stdin errors */ while (!PSIN (tmp,TMPLEN)){ /* read command line */ /* ignore if some interrupt */ if (ferror (stdin) && (errno == EINTR)) clearerr (stdin); else { char *e = ferror (stdin) ? strerror (errno) : "Command stream end of file"; alarm (0); /* disable all interrupts */ syslog (LOG_INFO,"%s while reading line user=%.80s host=%.80s", e,user ? user : "???",tcp_clienthost ()); rset (); /* try to gracefully close the stream */ if (state == TRANSACTION) mail_close (stream); stream = NIL; state = LOGOUT; _exit (1); } } alarm (0); /* make sure timeout disabled */ idletime = 0; /* no longer idle */ if (!strchr (tmp,'\012')) /* find end of line */ PSOUT ("-ERR Command line too long\015\012"); else if (!(s = strtok (tmp," \015\012"))) PSOUT ("-ERR Null command\015\012"); else { /* dispatch based on command */ ucase (s); /* canonicalize case */ /* snarf argument */ t = strtok (NIL,"\015\012"); /* QUIT command always valid */ if (!strcmp (s,"QUIT")) state = UPDATE; else if (!strcmp (s,"CAPA")) { AUTHENTICATOR *auth = mail_lookup_auth (1); PSOUT ("+OK Capability list follows:\015\012"); PSOUT ("TOP\015\012LOGIN-DELAY 180\015\012UIDL\015\012");#ifdef POP3SPECIALCAP PSOUT (POP3SPECIALCAP); CRLF;#endif#ifndef PLAINTEXT_DISABLED PSOUT ("USER\015\012");#endif PSOUT ("SASL"); while (auth) {#ifdef PLAINTEXT_DISABLED /* disable insecure authenticators */ if (!auth->secflag) auth->server = NIL;#endif if (auth->server) { PBOUT (' '); PSOUT (auth->name); } auth = auth->next; } CRLF; PSOUT (".\015\012"); } else switch (state) { /* else dispatch based on state */ case AUTHORIZATION: /* waiting to get logged in */ if (!strcmp (s,"USER")) { if (host) fs_give ((void **) &host); if (user) fs_give ((void **) &user); if (pass) fs_give ((void **) &pass); if (t && *t) { /* if user name given */ /* skip leading whitespace (bogus clients!) */ while (*t == ' ') ++t; /* remote user name? */ if (s = strchr (t,':')) { *s++ = '\0'; /* tie off host name */ host = cpystr (t);/* copy host name */ user = cpystr (s);/* copy user name */ } /* local user name */ else user = cpystr (t); PSOUT ("+OK User name accepted, password please\015\012"); } else PSOUT ("-ERR Missing username argument\015\012"); } else if (user && *user && !strcmp (s,"PASS")) state = login (t,argc,argv); else if (!strcmp (s,"AUTH")) { if (t && *t) { /* mechanism given? */ if (host) fs_give ((void **) &host); if (user) fs_give ((void **) &user); if (pass) fs_give ((void **) &pass); s = strtok (t," "); /* get mechanism name */ /* get initial response */ initial = strtok (NIL,"\015\012"); if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) { PSOUT ("-ERR Bad authentication\015\012"); syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s, tcp_clienthost ()); } else if ((state = mbxopen ("INBOX")) == TRANSACTION) syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%ld/%ld", user,tcp_clienthost (),nmsgs,stream->nmsgs); else syslog (LOG_INFO,"Auth user=%.80s host=%.80s no mailbox", user,tcp_clienthost ()); } else { AUTHENTICATOR *auth = mail_lookup_auth (1); PSOUT ("+OK Supported authentication mechanisms:\015\012"); while (auth) {#ifdef PLAINTEXT_DISABLED /* disable insecure authenticators */ if (!auth_secflag) auth->server = NIL;#endif if (auth->server) { PSOUT (auth->name); CRLF; } auth = auth->next; } PBOUT ('.'); CRLF; } } else if (!strcmp (s,"APOP")) { if (challenge[0]) { /* can do it if have an MD5 challenge */ if (host) fs_give ((void **) &host); if (user) fs_give ((void **) &user); if (pass) fs_give ((void **) &pass); /* get user name */ if (!(t && *t && (s = strtok (t," ")) && (t = strtok(NIL,"\012")))) PSOUT ("-ERR Missing APOP argument\015\012"); else if (!(user = apop_login (challenge,s,t,argc,argv))) PSOUT ("-ERR Bad APOP\015\012"); else if ((state = mbxopen ("INBOX")) == TRANSACTION) syslog (LOG_INFO,"APOP user=%.80s host=%.80s nmsgs=%ld/%ld", user,tcp_clienthost (),nmsgs,stream->nmsgs); else syslog (LOG_INFO,"APOP user=%.80s host=%.80s no mailbox", user,tcp_clienthost ()); } else PSOUT ("-ERR Not supported\015\012"); } /* (chuckle) */ else if (!strcmp (s,"RPOP")) PSOUT ("-ERR Nice try, bunkie\015\012");#ifdef IMAPSPECIALCAP else if (!strcmp (s,POP3SPECIALCAP)) { char rsp[TMPLEN]; if (t = SPECIALCAP (argv[0])) sprintf (rsp,"-ERR %s failed: %.100s\015\012",POP3SPECIALCAP,t); else sprintf (rsp,"+OK %s completed\015\012",POP3SPECIALCAP); PSOUT (rsp); }#endif else PSOUT ("-ERR Unknown AUTHORIZATION state command\015\012"); break; case TRANSACTION: /* logged in */ if (!strcmp (s,"STAT")) { for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0) { /* message still exists? */ j++; /* count one more undeleted message */ k += mail_elt (stream,msg[i])->rfc822_size + SLEN; } sprintf (tmp,"+OK %lu %lu\015\012",j,k); PSOUT (tmp); } else if (!strcmp (s,"LIST")) { if (t && *t) { /* argument do single message */ if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && (msg[i] > 0)) { sprintf (tmp,"+OK %lu %lu\015\012",i, mail_elt(stream,msg[i])->rfc822_size + SLEN); PSOUT (tmp); } else PSOUT ("-ERR No such message\015\012"); } else { /* entire mailbox */ PSOUT ("+OK Mailbox scan listing follows\015\012"); for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0) { sprintf (tmp,"%lu %lu\015\012",i, mail_elt (stream,msg[i])->rfc822_size + SLEN); PSOUT (tmp); } PBOUT ('.'); /* end of list */ CRLF; } } else if (!strcmp (s,"UIDL")) { if (t && *t) { /* argument do single message */ if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && (msg[i] > 0)) { sprintf (tmp,"+OK %lu %08lx%08lx\015\012",i,stream->uid_validity, mail_uid (stream,msg[i])); PSOUT (tmp); } else PSOUT ("-ERR No such message\015\012"); } else { /* entire mailbox */ PSOUT ("+OK Unique-ID listing follows\015\012"); for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0) { sprintf (tmp,"%lu %08lx%08lx\015\012",i,stream->uid_validity, mail_uid (stream,msg[i])); PSOUT (tmp); } PBOUT ('.'); /* end of list */ CRLF; } } else if (!strcmp (s,"RETR")) { if (t && *t) { /* must have an argument */ if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && (msg[i] > 0)) { MESSAGECACHE *elt; /* update highest message accessed */ if (i > last) last = i; sprintf (tmp,"+OK %lu octets\015\012", (elt = mail_elt (stream,msg[i]))->rfc822_size + SLEN); PSOUT (tmp); /* output header */ t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK); blat (t,-1,k); /* output status */ sprintf (tmp,STATUS,elt->seen ? "R" : " ", elt->recent ? " " : "O"); PSOUT (tmp); CRLF; /* delimit header and text */ /* output text */ t = mail_fetch_text (stream,msg[i],NIL,&k,NIL); blat (t,-1,k); CRLF; /* end of list */ PBOUT ('.'); CRLF; } else PSOUT ("-ERR No such message\015\012"); } else PSOUT ("-ERR Missing message number argument\015\012"); } else if (!strcmp (s,"DELE")) { if (t && *t) { /* must have an argument */ if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && (msg[i] > 0)) { /* update highest message accessed */ if (i > last) last = i; /* delete message */ sprintf (tmp,"%ld",msg[i]); mail_setflag (stream,tmp,"\\Deleted"); msg[i] = -msg[i]; /* note that we deleted this message */ PSOUT ("+OK Message deleted\015\012"); ndele++; /* one more message deleted */ } else PSOUT ("-ERR No such message\015\012"); } else PSOUT ("-ERR Missing message number argument\015\012"); } else if (!strcmp (s,"NOOP")) PSOUT ("+OK No-op to you too!\015\012"); else if (!strcmp (s,"LAST")) { sprintf (tmp,"+OK %lu\015\012",last); PSOUT (tmp); } else if (!strcmp (s,"RSET")) { rset (); /* reset the mailbox */ PSOUT ("+OK Reset state\015\012"); } else if (!strcmp (s,"TOP")) { if (t && *t && (i =strtoul (t,&s,10)) && (i <= nmsgs) && (msg[i] > 0)) { /* skip whitespace */ while (isspace (*s)) s++; if (isdigit (*s)) { /* make sure line count argument good */ MESSAGECACHE *elt = mail_elt (stream,msg[i]); j = strtoul (s,NIL,10); /* update highest message accessed */ if (i > last) last = i; PSOUT ("+OK Top of message follows\015\012"); /* output header */ t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK); blat (t,-1,k); /* output status */ sprintf (tmp,STATUS,elt->seen ? "R" : " ", elt->recent ? " " : "O"); PSOUT (tmp); CRLF; /* delimit header and text */ if (j) { /* want any text lines? */ /* output text */ t = mail_fetch_text (stream,msg[i],NIL,&k,FT_PEEK); /* tie off final line if full text output */ if (j -= blat (t,j,k)) CRLF; } PBOUT ('.'); /* end of list */ CRLF; } else PSOUT ("-ERR Bad line count argument\015\012"); } else PSOUT ("-ERR Bad message number argument\015\012"); } else if (!strcmp (s,"XTND")) PSOUT ("-ERR Sorry I can't do that\015\012"); else PSOUT ("-ERR Unknown TRANSACTION state command\015\012"); break; default: PSOUT ("-ERR Server in unknown state\015\012"); break; } } PFLUSH; /* make sure output finished */ if (autologouttime) { /* have an autologout in effect? */ /* cancel if no longer waiting for login */ if (state != AUTHORIZATION) autologouttime = 0; /* took too long to login */ else if (autologouttime < time (0)) { PSOUT ("-ERR Autologout\015\012"); syslog (LOG_INFO,"Autologout host=%.80s",tcp_clienthost ()); PFLUSH; /* make sure output blatted */ state = LOGOUT; /* sayonara */ } } } if (stream && (state == UPDATE)) { mail_expunge (stream); syslog (LOG_INFO,"Logout user=%.80s host=%.80s nmsgs=%ld ndele=%ld", user,tcp_clienthost (),stream->nmsgs,ndele); mail_close (stream); } else syslog (LOG_INFO,"Logout user=%.80s host=%.80s",user ? user : "???", tcp_clienthost ()); PSOUT (sayonara); /* "now it's time to say sayonara..." */ PFLUSH; /* make sure output finished */ return 0; /* all done */}/* Clock interrupt */void clkint (){ PSOUT ("-ERR Autologout; idle for too long\015\012"); syslog (LOG_INFO,"Autologout user=%.80s host=%.80s",user ? user : "???", tcp_clienthost ()); PFLUSH; /* make sure output blatted */ if (critical) state = LOGOUT; /* badly hosed if in critical code */ else { /* try to gracefully close the stream */ if ((state == TRANSACTION) && !stream->lock) { rset (); mail_close (stream);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -