ipop3d.c
上传用户:ycwykj01
上传日期:2007-01-04
资源大小:1819k
文件大小:27k
- /*
- * 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: 16 November 1999
- *
- * Copyright 1999 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 ("1512")
- /* Parameter files */
- #include "mail.h"
- #include "osdep.h"
- #include "rfc822.h"
- #include <stdio.h>
- #include <ctype.h>
- #include <errno.h>
- extern int errno; /* just in case */
- #include <signal.h>
- #include "misc.h"
- /* Autologout timer */
- #define KODTIMEOUT 60*5
- #define LOGINTIMEOUT 60*3
- #define TIMEOUT 60*30
- /* 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%s1512"
- #define SLEN (sizeof (STATUS)-3)
- /* Global storage */
- char *version = "7.64"; /* 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 */
- #ifndef DISABLE_POP_PROXY
- char *host = NIL; /* remote host name */
- #endif
- char *user = NIL; /* user name */
- char *pass = NIL; /* password */
- char *initial = NIL; /* initial response */
- long *msg = NIL; /* message translation vector */
- char *sayonara = "+OK Sayonara1512";
- /* 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] = ''; /* 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,'12')) /* find end of line */
- PSOUT ("-ERR Command line too long1512");
- else if (!(s = strtok (tmp," 1512")))
- PSOUT ("-ERR Null command1512");
- else { /* dispatch based on command */
- ucase (s); /* canonicalize case */
- /* snarf argument */
- t = strtok (NIL,"1512");
- /* QUIT command always valid */
- if (!strcmp (s,"QUIT")) state = UPDATE;
- else switch (state) { /* else dispatch based on state */
- case AUTHORIZATION: /* waiting to get logged in */
- if (!strcmp (s,"USER")) {
- #ifndef DISABLE_POP_PROXY
- if (host) fs_give ((void **) &host);
- #endif
- 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;
- #ifndef DISABLE_POP_PROXY
- /* remote user name? */
- if (s = strchr (t,':')) {
- *s++ = ''; /* tie off host name */
- host = cpystr (t);/* copy host name */
- user = cpystr (s);/* copy user name */
- }
- /* local user name */
- else user = cpystr (t);
- #else
- user = cpystr (t); /* local user name */
- #endif
- PSOUT ("+OK User name accepted, password please1512");
- }
- else PSOUT ("-ERR Missing username argument1512");
- }
- else if (user && *user && !strcmp (s,"PASS")) {
- if ((state = login (t,argc,argv)) == TRANSACTION)
- syslog (LOG_INFO,"Login user=%.80s host=%.80s nmsgs=%ld/%ld",
- user,tcp_clienthost (),nmsgs,stream->nmsgs);
- }
- else if (!strcmp (s,"AUTH")) {
- if (t && *t) { /* mechanism given? */
- #ifndef DISABLE_POP_PROXY
- if (host) fs_give ((void **) &host);
- #endif
- if (user) fs_give ((void **) &user);
- if (pass) fs_give ((void **) &pass);
- s = strtok (t," "); /* get mechanism name */
- /* get initial response */
- initial = strtok (NIL,"1512");
- if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) {
- PSOUT ("-ERR Bad authentication1512");
- 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 {
- AUTHENTICATOR *auth = mail_lookup_auth (1);
- PSOUT ("+OK Supported authentication mechanisms:1512");
- 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 */
- #ifndef DISABLE_POP_PROXY
- if (host) fs_give ((void **) &host);
- #endif
- if (user) fs_give ((void **) &user);
- if (pass) fs_give ((void **) &pass);
- /* get user name */
- if (!(t && *t && (s = strtok (t," ")) && (t = strtok(NIL,"12"))))
- PSOUT ("-ERR Missing APOP argument1512");
- else if (!(user = apop_login (challenge,s,t,argc,argv)))
- PSOUT ("-ERR Bad APOP1512");
- else if ((state = mbxopen ("INBOX")) == TRANSACTION)
- syslog (LOG_INFO,"APOP user=%.80s host=%.80s nmsgs=%ld/%ld",
- user,tcp_clienthost (),nmsgs,stream->nmsgs);
- }
- else PSOUT ("-ERR Not supported1512");
- }
- /* (chuckle) */
- else if (!strcmp (s,"RPOP"))
- PSOUT ("-ERR Nice try, bunkie1512");
- else PSOUT ("-ERR Unknown AUTHORIZATION state command1512");
- 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 %lu1512",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 %lu1512",i,
- mail_elt(stream,msg[i])->rfc822_size + SLEN);
- PSOUT (tmp);
- }
- else PSOUT ("-ERR No such message1512");
- }
- else { /* entire mailbox */
- PSOUT ("+OK Mailbox scan listing follows1512");
- for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0) {
- sprintf (tmp,"%lu %lu1512",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%08lx1512",i,stream->uid_validity,
- mail_uid (stream,msg[i]));
- PSOUT (tmp);
- }
- else PSOUT ("-ERR No such message1512");
- }
- else { /* entire mailbox */
- PSOUT ("+OK Unique-ID listing follows1512");
- for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0) {
- sprintf (tmp,"%lu %08lx%08lx1512",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 octets1512",
- (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 message1512");
- }
- else PSOUT ("-ERR Missing message number argument1512");
- }
- 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 deleted1512");
- ndele++; /* one more message deleted */
- }
- else PSOUT ("-ERR No such message1512");
- }
- else PSOUT ("-ERR Missing message number argument1512");
- }
- else if (!strcmp (s,"NOOP"))
- PSOUT ("+OK No-op to you too!1512");
- else if (!strcmp (s,"LAST")) {
- sprintf (tmp,"+OK %lu1512",last);
- PSOUT (tmp);
- }
- else if (!strcmp (s,"RSET")) {
- rset (); /* reset the mailbox */
- PSOUT ("+OK Reset state1512");
- }
- 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 follows1512");
- /* 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 argument1512");
- }
- else PSOUT ("-ERR Bad message number argument1512");
- }
- else if (!strcmp (s,"XTND"))
- PSOUT ("-ERR Sorry I can't do that1512");
- else PSOUT ("-ERR Unknown TRANSACTION state command1512");
- break;
- default:
- PSOUT ("-ERR Server in unknown state1512");
- 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 Autologout1512");
- 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 long1512");
- 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);
- }
- state = LOGOUT;
- stream = NIL;
- _exit (1); /* die die die */
- }
- }
- /* Kiss Of Death interrupt
- */
- void kodint ()
- {
- /* only if idle */
- if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
- alarm (0); /* disable all interrupts */
- server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
- PSOUT ("-ERR Received Kiss of Death1512");
- syslog (LOG_INFO,"Killed (lost mailbox lock) user=%.80s host=%.80s",
- user ? user : "???",tcp_clienthost ());
- if (critical) state =LOGOUT;/* must defer if in critical code */
- else { /* try to gracefully close the stream */
- if ((state == TRANSACTION) && !stream->lock) {
- rset ();
- mail_close (stream);
- }
- state = LOGOUT;
- stream = NIL;
- _exit (1); /* die die die */
- }
- }
- }
- /* Hangup interrupt
- */
- void hupint ()
- {
- alarm (0); /* disable all interrupts */
- server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
- syslog (LOG_INFO,"Hangup user=%.80s host=%.80s",user ? user : "???",
- tcp_clienthost ());
- if (critical) state = LOGOUT; /* must defer if in critical code */
- else { /* try to gracefully close the stream */
- if ((state == TRANSACTION) && !stream->lock) {
- rset ();
- mail_close (stream);
- }
- state = LOGOUT;
- stream = NIL;
- _exit (1); /* die die die */
- }
- }
- /* Termination interrupt
- */
- void trmint ()
- {
- alarm (0); /* disable all interrupts */
- server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
- PSOUT ("-ERR Killed1512");
- syslog (LOG_INFO,"Killed user=%.80s host=%.80s",user ? user : "???",
- tcp_clienthost ());
- if (critical) state = LOGOUT; /* must defer if in critical code */
- else { /* try to gracefully close the stream */
- if ((state == TRANSACTION) && !stream->lock) {
- rset ();
- mail_close (stream);
- }
- state = LOGOUT;
- stream = NIL;
- _exit (1); /* die die die */
- }
- }
- /* Parse PASS command
- * Accepts: pointer to command argument
- * Returns: new state
- */
- int login (char *t,int argc,char *argv[])
- {
- char tmp[TMPLEN];
- /* flush old passowrd */
- if (pass) fs_give ((void **) &pass);
- if (!(t && *t)) { /* if no password given */
- PSOUT ("-ERR Missing password argument1512");
- return AUTHORIZATION;
- }
- pass = cpystr (t); /* copy password argument */
- #ifndef DISABLE_POP_PROXY
- /* remote; build remote INBOX */
- if (host && anonymous_login (argc,argv)) {
- syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",host,
- user,tcp_clienthost ());
- sprintf (tmp,"{%.128s/user=%.128s}INBOX",host,user);
- /* disable rimap just in case */
- mail_parameters (NIL,SET_RSHTIMEOUT,0);
- }
- /* local; attempt login, select INBOX */
- else if (!host && server_login (user,pass,argc,argv)) strcpy (tmp,"INBOX");
- #else
- if (server_login (user,pass,argc,argv)) strcpy (tmp,"INBOX");
- #endif
- else { /* vague error message to confuse crackers */
- PSOUT ("-ERR Bad login1512");
- return AUTHORIZATION;
- }
- return mbxopen (tmp);
- }
- /* Authentication responder
- * Accepts: challenge
- * length of challenge
- * pointer to response length return location if non-NIL
- * Returns: response
- */
- #define RESPBUFLEN 8*MAILTMPLEN
- char *responder (void *challenge,unsigned long clen,unsigned long *rlen)
- {
- unsigned long i,j;
- unsigned char *t,resp[RESPBUFLEN];
- if (initial) { /* initial response given? */
- if (clen) return NIL; /* not permitted */
- /* set up response */
- t = (unsigned char *) initial;
- initial = NIL; /* no more initial response */
- return (char *) rfc822_base64 (t,strlen (t),rlen ? rlen : &i);
- }
- PSOUT ("+ ");
- for (t = rfc822_binary (challenge,clen,&i),j = 0; j < i; j++)
- if (t[j] > ' ') PBOUT (t[j]);
- fs_give ((void **) &t);
- CRLF;
- PFLUSH; /* dump output buffer */
- resp[RESPBUFLEN-1] = ''; /* last buffer character is guaranteed NUL */
- alarm (LOGINTIMEOUT); /* get a response under timeout */
- clearerr (stdin); /* clear stdin errors */
- /* read buffer */
- while (!PSIN ((char *) resp,RESPBUFLEN)) {
- /* 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 */
- server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
- syslog (LOG_INFO,"%s, while reading authentication host=%.80s",
- e,tcp_clienthost ());
- state = UPDATE;
- _exit (1);
- }
- }
- if (!(t = (unsigned char *) strchr ((char *) resp,'12'))) {
- int c;
- while ((c = PBIN ()) != '12') if (c == EOF) {
- /* 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 */
- server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
- syslog (LOG_INFO,"%s, while reading auth char user=%.80s host=%.80s",
- e,user ? user : "???",tcp_clienthost ());
- state = UPDATE;
- _exit (1);
- }
- }
- return NIL;
- }
- alarm (0); /* make sure timeout disabled */
- if (t[-1] == '15') --t; /* remove CR */
- *t = ''; /* tie off buffer */
- return (resp[0] != '*') ?
- (char *) rfc822_base64 (resp,t-resp,rlen ? rlen : &i) : NIL;
- }
- /* Select mailbox
- * Accepts: mailbox name
- * Returns: new state
- */
- int mbxopen (char *mailbox)
- {
- unsigned long i,j;
- char tmp[TMPLEN];
- MESSAGECACHE *elt;
- nmsgs = 0; /* no messages yet */
- if (msg) fs_give ((void **) &msg);
- /* open mailbox */
- if (stream = mail_open (stream,mailbox,NIL)) {
- if (!stream->rdonly) { /* make sure not readonly */
- if (j = stream->nmsgs) { /* if mailbox non-empty */
- sprintf (tmp,"1:%lu",j);/* fetch fast information for all messages */
- mail_fetch_fast (stream,tmp,NIL);
- msg = (long *) fs_get ((stream->nmsgs + 1) * sizeof (long));
- for (i = 1; i <= j; i++) if (!(elt = mail_elt (stream,i))->deleted) {
- msg[++nmsgs] = i; /* note the presence of this message */
- if (elt->seen) il = last = nmsgs;
- }
- }
- sprintf (tmp,"+OK Mailbox open, %lu messages1512",nmsgs);
- PSOUT (tmp);
- return TRANSACTION;
- }
- else sayonara = "-ERR Can't get lock. Mailbox in use1512";
- }
- else sayonara = "-ERR Unable to open user's INBOX1512";
- syslog (LOG_INFO,"Error opening or locking INBOX user=%.80s host=%.80s",
- user,tcp_clienthost ());
- return UPDATE;
- }
- /* Blat a string with dot checking
- * Accepts: string
- * maximum number of lines if greater than zero
- * maximum number of bytes to output
- * Returns: number of lines output
- *
- * This routine is uglier and kludgier than it should be, just to be robust
- * in the case of a message which doesn't end in a newline. Yes, this routine
- * does truncate the last two bytes from the text. Since it is normally a
- * newline and the main routine adds it back, it usually does not make a
- * difference. But if it isn't, since the newline is required and the octet
- * counts have to match, there's no choice but to truncate.
- */
- long blat (char *text,long lines,unsigned long size)
- {
- char c,d,e;
- long ret = 0;
- /* no-op if zero lines or empty string */
- if (!(lines && (size-- > 2))) return 0;
- c = *text++; d = *text++; /* collect first two bytes */
- if (c == '.') PBOUT ('.'); /* double string-leading dot if necessary */
- while (lines && --size) { /* copy loop */
- e = *text++; /* get next byte */
- PBOUT (c); /* output character */
- if (c == '12') { /* end of line? */
- ret++; --lines; /* count another line */
- /* double leading dot as necessary */
- if (lines && size && (d == '.')) PBOUT ('.');
- }
- c = d; d = e; /* move to next character */
- }
- return ret;
- }
- /* Reset mailbox
- */
- void rset ()
- {
- unsigned long i;
- char tmp[20];
- if (nmsgs) { /* undelete and unmark all of our messages */
- for (i = 1; i <= nmsgs; i++) { /* */
- if (msg[i] < 0) { /* ugly and inefficient, but trustworthy */
- sprintf (tmp,"%ld",msg[i] = -msg[i]);
- mail_clearflag (stream,tmp,i <= il ? "\Deleted" : "\Deleted \Seen");
- }
- else if (i > il) {
- sprintf (tmp,"%ld",msg[i]);
- mail_clearflag (stream,tmp,"\Seen");
- }
- }
- last = il;
- }
- ndele = 0; /* no more deleted messages */
- }
- /* Co-routines from MAIL library */
- /* Message matches a search
- * Accepts: MAIL stream
- * message number
- */
- void mm_searched (MAILSTREAM *stream,unsigned long msgno)
- {
- /* Never called */
- }
- /* Message exists (i.e. there are that many messages in the mailbox)
- * Accepts: MAIL stream
- * message number
- */
- void mm_exists (MAILSTREAM *stream,unsigned long number)
- {
- /* Can't use this mechanism. POP has no means of notifying the client of
- new mail during the session. */
- }
- /* Message expunged
- * Accepts: MAIL stream
- * message number
- */
- void mm_expunged (MAILSTREAM *stream,unsigned long number)
- {
- unsigned long i = number + 1;
- msg[number] = 0; /* I bet that this will annoy someone */
- while (i <= nmsgs) --msg[i++];
- }
- /* Message flag status change
- * Accepts: MAIL stream
- * message number
- */
- void mm_flags (MAILSTREAM *stream,unsigned long number)
- {
- /* This isn't used */
- }
- /* Mailbox found
- * Accepts: MAIL stream
- * hierarchy delimiter
- * mailbox name
- * mailbox attributes
- */
- void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
- {
- /* This isn't used */
- }
- /* Subscribe mailbox found
- * Accepts: MAIL stream
- * hierarchy delimiter
- * mailbox name
- * mailbox attributes
- */
- void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
- {
- /* This isn't used */
- }
- /* Mailbox status
- * Accepts: MAIL stream
- * mailbox name
- * mailbox status
- */
- void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
- {
- /* This isn't used */
- }
- /* Notification event
- * Accepts: MAIL stream
- * string to log
- * error flag
- */
- void mm_notify (MAILSTREAM *stream,char *string,long errflg)
- {
- mm_log (string,errflg); /* just do mm_log action */
- }
- /* Log an event for the user to see
- * Accepts: string to log
- * error flag
- */
- void mm_log (char *string,long errflg)
- {
- switch (errflg) {
- case NIL: /* information message */
- case PARSE: /* parse glitch */
- break; /* too many of these to log */
- case WARN: /* warning */
- syslog (LOG_DEBUG,"%s",string);
- break;
- case ERROR: /* error that broke command */
- default: /* default should never happen */
- syslog (LOG_NOTICE,"%s",string);
- break;
- }
- }
- /* Log an event to debugging telemetry
- * Accepts: string to log
- */
- void mm_dlog (char *string)
- {
- /* Not doing anything here for now */
- }
- /* Get user name and password for this host
- * Accepts: parse of network mailbox name
- * where to return user name
- * where to return password
- * trial count
- */
- void mm_login (NETMBX *mb,char *username,char *password,long trial)
- {
- /* set user name */
- strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
- strncpy (password,pass,255); /* and password */
- username[NETMAXUSER] = password[255] = '';
- }
- /* About to enter critical code
- * Accepts: stream
- */
- void mm_critical (MAILSTREAM *stream)
- {
- critical = T;
- }
- /* About to exit critical code
- * Accepts: stream
- */
- void mm_nocritical (MAILSTREAM *stream)
- {
- critical = NIL;
- }
- /* Disk error found
- * Accepts: stream
- * system error code
- * flag indicating that mailbox may be clobbered
- * Returns: abort flag
- */
- long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
- {
- if (serious) { /* try your damnest if clobberage likely */
- syslog (LOG_ALERT,
- "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
- user,tcp_clienthost (),
- (stream && stream->mailbox) ? stream->mailbox : "???",
- strerror (errcode));
- alarm (0); /* make damn sure timeout disabled */
- sleep (60); /* give it some time to clear up */
- return NIL;
- }
- syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
- user,tcp_clienthost (),
- (stream && stream->mailbox) ? stream->mailbox : "???",
- strerror (errcode));
- return T;
- }
- /* Log a fatal error event
- * Accepts: string to log
- */
- void mm_fatal (char *string)
- {
- mm_log (string,ERROR); /* shouldn't happen normally */
- }