ipop3d.c
上传用户:ycwykj01
上传日期:2007-01-04
资源大小:1819k
文件大小:27k
源码类别:

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Program: IPOP3D - IMAP to POP3 conversion server
  3.  *
  4.  * Author: Mark Crispin
  5.  * Networks and Distributed Computing
  6.  * Computing & Communications
  7.  * University of Washington
  8.  * Administration Building, AG-44
  9.  * Seattle, WA  98195
  10.  * Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date: 1 November 1990
  13.  * Last Edited: 16 November 1999
  14.  *
  15.  * Copyright 1999 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35. #define PBIN getchar
  36. #define PSIN(s,n) fgets (s,n,stdin)
  37. #define PBOUT(c) putchar (c)
  38. #define PSOUT(s) fputs (s,stdout)
  39. #define PFLUSH fflush (stdout)
  40. #define CRLF PSOUT ("1512")
  41. /* Parameter files */
  42. #include "mail.h"
  43. #include "osdep.h"
  44. #include "rfc822.h"
  45. #include <stdio.h>
  46. #include <ctype.h>
  47. #include <errno.h>
  48. extern int errno; /* just in case */
  49. #include <signal.h>
  50. #include "misc.h"
  51. /* Autologout timer */
  52. #define KODTIMEOUT 60*5
  53. #define LOGINTIMEOUT 60*3
  54. #define TIMEOUT 60*30
  55. /* Size of temporary buffers */
  56. #define TMPLEN 1024
  57. /* Server states */
  58. #define AUTHORIZATION 0
  59. #define TRANSACTION 1
  60. #define UPDATE 2
  61. #define LOGOUT 3
  62. /* Eudora food */
  63. #define STATUS "Status: %s%s1512"
  64. #define SLEN (sizeof (STATUS)-3)
  65. /* Global storage */
  66. char *version = "7.64"; /* server version */
  67. short state = AUTHORIZATION; /* server state */
  68. short critical = NIL; /* non-zero if in critical code */
  69. MAILSTREAM *stream = NIL; /* mailbox stream */
  70. long idletime = 0; /* time we went idle */
  71. unsigned long nmsgs = 0; /* current number of messages */
  72. unsigned long ndele = 0; /* number of deletes */
  73. unsigned long last = 0; /* highest message accessed */
  74. unsigned long il = 0; /* initial last message */
  75. char challenge[128]; /* challenge */
  76. #ifndef DISABLE_POP_PROXY
  77. char *host = NIL; /* remote host name */
  78. #endif
  79. char *user = NIL; /* user name */
  80. char *pass = NIL; /* password */
  81. char *initial = NIL; /* initial response */
  82. long *msg = NIL; /* message translation vector */
  83. char *sayonara = "+OK Sayonara1512";
  84. /* Function prototypes */
  85. int main (int argc,char *argv[]);
  86. void clkint ();
  87. void kodint ();
  88. void hupint ();
  89. void trmint ();
  90. int login (char *t,int argc,char *argv[]);
  91. char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
  92. char *responder (void *challenge,unsigned long clen,unsigned long *rlen);
  93. int mbxopen (char *mailbox);
  94. long blat (char *text,long lines,unsigned long size);
  95. void rset ();
  96. /* Main program */
  97. int main (int argc,char *argv[])
  98. {
  99.   unsigned long i,j,k;
  100.   char *s,*t;
  101.   char tmp[TMPLEN];
  102.   time_t autologouttime;
  103. #include "linkage.c"
  104. /* initialize server */
  105.   server_init (argv[0],"pop3","pop3s","pop",clkint,kodint,hupint,trmint);
  106.   challenge[0] = ''; /* find the CRAM-MD5 authenticator */
  107.   if (i = mail_lookup_auth_name ("CRAM-MD5",NIL)) {
  108.     AUTHENTICATOR *a = mail_lookup_auth (i);
  109.     if (a->server) { /* have an MD5 enable file? */
  110. /* build challenge -- less than 128 chars */
  111.       sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (),
  112.        (unsigned long) time (0),tcp_serverhost ());
  113.     }
  114.   }
  115.   /* There are reports of POP3 clients which get upset if anything appears
  116.    * between the "+OK" and the "POP3" in the greeting.
  117.    */
  118.   PSOUT ("+OK POP3");
  119.   if (!challenge[0]) { /* if no MD5 enable, output host name */
  120.     PBOUT (' ');
  121.     PSOUT (tcp_serverhost ());
  122.   }
  123.   PSOUT (" v");
  124.   PSOUT (version);
  125.   PSOUT (" server ready");
  126.   if (challenge[0]) { /* if MD5 enable, output challenge here */
  127.     PBOUT (' ');
  128.     PSOUT (challenge);
  129.   }
  130.   CRLF;
  131.   PFLUSH; /* dump output buffer */
  132.   autologouttime = time (0) + LOGINTIMEOUT;
  133. /* command processing loop */
  134.   while ((state != UPDATE) && (state != LOGOUT)) {
  135.     idletime = time (0); /* get a command under timeout */
  136.     alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT);
  137.     clearerr (stdin); /* clear stdin errors */
  138.     while (!PSIN (tmp,TMPLEN)){ /* read command line */
  139. /* ignore if some interrupt */
  140.       if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
  141.       else {
  142. char *e = ferror (stdin) ?
  143.   strerror (errno) : "Command stream end of file";
  144. alarm (0); /* disable all interrupts */
  145. syslog (LOG_INFO,"%s while reading line user=%.80s host=%.80s",
  146. e,user ? user : "???",tcp_clienthost ());
  147. rset (); /* try to gracefully close the stream */
  148. if (state == TRANSACTION) mail_close (stream);
  149. stream = NIL;
  150. state = LOGOUT;
  151. _exit (1);
  152.       }
  153.     }
  154.     alarm (0); /* make sure timeout disabled */
  155.     idletime = 0; /* no longer idle */
  156.     if (!strchr (tmp,'12')) /* find end of line */
  157.       PSOUT ("-ERR Command line too long1512");
  158.     else if (!(s = strtok (tmp," 1512")))
  159.       PSOUT ("-ERR Null command1512");
  160.     else { /* dispatch based on command */
  161.       ucase (s); /* canonicalize case */
  162. /* snarf argument */
  163.       t = strtok (NIL,"1512");
  164. /* QUIT command always valid */
  165.       if (!strcmp (s,"QUIT")) state = UPDATE;
  166.       else switch (state) { /* else dispatch based on state */
  167.       case AUTHORIZATION: /* waiting to get logged in */
  168. if (!strcmp (s,"USER")) {
  169. #ifndef DISABLE_POP_PROXY
  170.   if (host) fs_give ((void **) &host);
  171. #endif
  172.   if (user) fs_give ((void **) &user);
  173.   if (pass) fs_give ((void **) &pass);
  174.   if (t && *t) { /* if user name given */
  175. /* skip leading whitespace (bogus clients!) */
  176.     while (*t == ' ') ++t;
  177. #ifndef DISABLE_POP_PROXY
  178. /* remote user name? */
  179.     if (s = strchr (t,':')) {
  180.       *s++ = ''; /* tie off host name */
  181.       host = cpystr (t);/* copy host name */
  182.       user = cpystr (s);/* copy user name */
  183.     }
  184. /* local user name */
  185.     else user = cpystr (t);
  186. #else
  187.     user = cpystr (t); /* local user name */
  188. #endif
  189.     PSOUT ("+OK User name accepted, password please1512");
  190.   }
  191.   else PSOUT ("-ERR Missing username argument1512");
  192. }
  193. else if (user && *user && !strcmp (s,"PASS")) {
  194.   if ((state = login (t,argc,argv)) == TRANSACTION)
  195.     syslog (LOG_INFO,"Login user=%.80s host=%.80s nmsgs=%ld/%ld",
  196.     user,tcp_clienthost (),nmsgs,stream->nmsgs);
  197. }
  198. else if (!strcmp (s,"AUTH")) {
  199.   if (t && *t) { /* mechanism given? */
  200. #ifndef DISABLE_POP_PROXY
  201.     if (host) fs_give ((void **) &host);
  202. #endif
  203.     if (user) fs_give ((void **) &user);
  204.     if (pass) fs_give ((void **) &pass);
  205.     s = strtok (t," "); /* get mechanism name */
  206. /* get initial response */
  207.     initial = strtok (NIL,"1512");
  208.     if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) {
  209.       PSOUT ("-ERR Bad authentication1512");
  210.       syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s,
  211.       tcp_clienthost ());
  212.     }
  213.     else if ((state = mbxopen ("INBOX")) == TRANSACTION)
  214.       syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%ld/%ld",
  215.       user,tcp_clienthost (),nmsgs,stream->nmsgs);
  216.   }
  217.   else {
  218.     AUTHENTICATOR *auth = mail_lookup_auth (1);
  219.     PSOUT ("+OK Supported authentication mechanisms:1512");
  220.     while (auth) {
  221. #ifdef PLAINTEXT_DISABLED
  222. /* disable insecure authenticators */
  223.       if (!auth_secflag) auth->server = NIL;
  224. #endif
  225.       if (auth->server) {
  226. PSOUT (auth->name);
  227. CRLF;
  228.       }
  229.       auth = auth->next;
  230.     }
  231.     PBOUT ('.');
  232.     CRLF;
  233.   }
  234. }
  235. else if (!strcmp (s,"APOP")) {
  236.   if (challenge[0]) { /* can do it if have an MD5 challenge */
  237. #ifndef DISABLE_POP_PROXY
  238.     if (host) fs_give ((void **) &host);
  239. #endif
  240.     if (user) fs_give ((void **) &user);
  241.     if (pass) fs_give ((void **) &pass);
  242. /* get user name */
  243.     if (!(t && *t && (s = strtok (t," ")) && (t = strtok(NIL,"12"))))
  244.       PSOUT ("-ERR Missing APOP argument1512");
  245.     else if (!(user = apop_login (challenge,s,t,argc,argv)))
  246.       PSOUT ("-ERR Bad APOP1512");
  247.     else if ((state = mbxopen ("INBOX")) == TRANSACTION)
  248.       syslog (LOG_INFO,"APOP user=%.80s host=%.80s nmsgs=%ld/%ld",
  249.       user,tcp_clienthost (),nmsgs,stream->nmsgs);
  250.   }
  251.   else PSOUT ("-ERR Not supported1512");
  252. }
  253. /* (chuckle) */
  254. else if (!strcmp (s,"RPOP"))
  255.   PSOUT ("-ERR Nice try, bunkie1512");
  256. else PSOUT ("-ERR Unknown AUTHORIZATION state command1512");
  257. break;
  258.       case TRANSACTION: /* logged in */
  259. if (!strcmp (s,"STAT")) {
  260.   for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
  261.     if (msg[i] > 0) { /* message still exists? */
  262.       j++; /* count one more undeleted message */
  263.       k += mail_elt (stream,msg[i])->rfc822_size + SLEN;
  264.     }
  265.   sprintf (tmp,"+OK %lu %lu1512",j,k);
  266.   PSOUT (tmp);
  267. }
  268. else if (!strcmp (s,"LIST")) {
  269.   if (t && *t) { /* argument do single message */
  270.     if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && (msg[i] > 0)) {
  271.       sprintf (tmp,"+OK %lu %lu1512",i,
  272.        mail_elt(stream,msg[i])->rfc822_size + SLEN);
  273.       PSOUT (tmp);
  274.     }
  275.     else PSOUT ("-ERR No such message1512");
  276.   }
  277.   else { /* entire mailbox */
  278.     PSOUT ("+OK Mailbox scan listing follows1512");
  279.     for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0) {
  280.       sprintf (tmp,"%lu %lu1512",i,
  281.        mail_elt (stream,msg[i])->rfc822_size + SLEN);
  282.       PSOUT (tmp);
  283.     }
  284.     PBOUT ('.'); /* end of list */
  285.     CRLF;
  286.   }
  287. }
  288. else if (!strcmp (s,"UIDL")) {
  289.   if (t && *t) { /* argument do single message */
  290.     if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && (msg[i] > 0)) {
  291.       sprintf (tmp,"+OK %lu %08lx%08lx1512",i,stream->uid_validity,
  292.        mail_uid (stream,msg[i]));
  293.       PSOUT (tmp);
  294.     }
  295.     else PSOUT ("-ERR No such message1512");
  296.   }
  297.   else { /* entire mailbox */
  298.     PSOUT ("+OK Unique-ID listing follows1512");
  299.     for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0) {
  300.       sprintf (tmp,"%lu %08lx%08lx1512",i,stream->uid_validity,
  301.        mail_uid (stream,msg[i]));
  302.       PSOUT (tmp);
  303.     }
  304.     PBOUT ('.'); /* end of list */
  305.     CRLF;
  306.   }
  307. }
  308. else if (!strcmp (s,"RETR")) {
  309.   if (t && *t) { /* must have an argument */
  310.     if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && (msg[i] > 0)) {
  311.       MESSAGECACHE *elt;
  312. /* update highest message accessed */
  313.       if (i > last) last = i;
  314.       sprintf (tmp,"+OK %lu octets1512",
  315.        (elt = mail_elt (stream,msg[i]))->rfc822_size + SLEN);
  316.       PSOUT (tmp);
  317. /* output header */
  318.       t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
  319.       blat (t,-1,k);
  320. /* output status */
  321.       sprintf (tmp,STATUS,elt->seen ? "R" : " ",
  322.        elt->recent ? " " : "O");
  323.       PSOUT (tmp);
  324.       CRLF; /* delimit header and text */
  325. /* output text */
  326.       t = mail_fetch_text (stream,msg[i],NIL,&k,NIL);
  327.       blat (t,-1,k);
  328.       CRLF; /* end of list */
  329.       PBOUT ('.');
  330.       CRLF;
  331.     }
  332.     else PSOUT ("-ERR No such message1512");
  333.   }
  334.   else PSOUT ("-ERR Missing message number argument1512");
  335. }
  336. else if (!strcmp (s,"DELE")) {
  337.   if (t && *t) { /* must have an argument */
  338.     if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && (msg[i] > 0)) {
  339. /* update highest message accessed */
  340.       if (i > last) last = i;
  341. /* delete message */
  342.       sprintf (tmp,"%ld",msg[i]);
  343.       mail_setflag (stream,tmp,"\Deleted");
  344.       msg[i] = -msg[i]; /* note that we deleted this message */
  345.       PSOUT ("+OK Message deleted1512");
  346.       ndele++; /* one more message deleted */
  347.     }
  348.     else PSOUT ("-ERR No such message1512");
  349.   }
  350.   else PSOUT ("-ERR Missing message number argument1512");
  351. }
  352. else if (!strcmp (s,"NOOP"))
  353.   PSOUT ("+OK No-op to you too!1512");
  354. else if (!strcmp (s,"LAST")) {
  355.   sprintf (tmp,"+OK %lu1512",last);
  356.   PSOUT (tmp);
  357. }
  358. else if (!strcmp (s,"RSET")) {
  359.   rset (); /* reset the mailbox */
  360.   PSOUT ("+OK Reset state1512");
  361. }
  362. else if (!strcmp (s,"TOP")) {
  363.   if (t && *t && (i =strtoul (t,&s,10)) && (i <= nmsgs) &&
  364.       (msg[i] > 0)) {
  365. /* skip whitespace */
  366.     while (isspace (*s)) s++;
  367.     if (isdigit (*s)) { /* make sure line count argument good */
  368.       MESSAGECACHE *elt = mail_elt (stream,msg[i]);
  369.       j = strtoul (s,NIL,10);
  370. /* update highest message accessed */
  371.       if (i > last) last = i;
  372.       PSOUT ("+OK Top of message follows1512");
  373. /* output header */
  374.       t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
  375.       blat (t,-1,k);
  376. /* output status */
  377.       sprintf (tmp,STATUS,elt->seen ? "R" : " ",
  378.        elt->recent ? " " : "O");
  379.       PSOUT (tmp);
  380.       CRLF; /* delimit header and text */
  381.       if (j) { /* want any text lines? */
  382. /* output text */
  383. t = mail_fetch_text (stream,msg[i],NIL,&k,FT_PEEK);
  384. /* tie off final line if full text output */
  385. if (j -= blat (t,j,k)) CRLF;
  386.       }
  387.       PBOUT ('.'); /* end of list */
  388.       CRLF;
  389.     }
  390.     else PSOUT ("-ERR Bad line count argument1512");
  391.   }
  392.   else PSOUT ("-ERR Bad message number argument1512");
  393. }
  394. else if (!strcmp (s,"XTND"))
  395.   PSOUT ("-ERR Sorry I can't do that1512");
  396. else PSOUT ("-ERR Unknown TRANSACTION state command1512");
  397. break;
  398.       default:
  399.         PSOUT ("-ERR Server in unknown state1512");
  400. break;
  401.       }
  402.     }
  403.     PFLUSH; /* make sure output finished */
  404.     if (autologouttime) { /* have an autologout in effect? */
  405. /* cancel if no longer waiting for login */
  406.       if (state != AUTHORIZATION) autologouttime = 0;
  407. /* took too long to login */
  408.       else if (autologouttime < time (0)) {
  409. PSOUT ("-ERR Autologout1512");
  410. syslog (LOG_INFO,"Autologout host=%.80s",tcp_clienthost ());
  411. PFLUSH; /* make sure output blatted */
  412. state = LOGOUT; /* sayonara */
  413.       }
  414.     }
  415.   }
  416.   if (stream && (state == UPDATE)) {
  417.     mail_expunge (stream);
  418.     syslog (LOG_INFO,"Logout user=%.80s host=%.80s nmsgs=%ld ndele=%ld",
  419.     user,tcp_clienthost (),stream->nmsgs,ndele);
  420.     mail_close (stream);
  421.   }
  422.   else syslog (LOG_INFO,"Logout user=%.80s host=%.80s",user ? user : "???",
  423.        tcp_clienthost ());
  424.   PSOUT (sayonara); /* "now it's time to say sayonara..." */
  425.   PFLUSH; /* make sure output finished */
  426.   return 0; /* all done */
  427. }
  428. /* Clock interrupt
  429.  */
  430. void clkint ()
  431. {
  432.   PSOUT ("-ERR Autologout; idle for too long1512");
  433.   syslog (LOG_INFO,"Autologout user=%.80s host=%.80s",user ? user : "???",
  434.   tcp_clienthost ());
  435.   PFLUSH; /* make sure output blatted */
  436.   if (critical) state = LOGOUT; /* badly hosed if in critical code */
  437.   else { /* try to gracefully close the stream */
  438.     if ((state == TRANSACTION) && !stream->lock) {
  439.       rset ();
  440.       mail_close (stream);
  441.     }
  442.     state = LOGOUT;
  443.     stream = NIL;
  444.     _exit (1); /* die die die */
  445.   }
  446. }
  447. /* Kiss Of Death interrupt
  448.  */
  449. void kodint ()
  450. {
  451. /* only if idle */
  452.   if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
  453.     alarm (0); /* disable all interrupts */
  454.     server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
  455.     PSOUT ("-ERR Received Kiss of Death1512");
  456.     syslog (LOG_INFO,"Killed (lost mailbox lock) user=%.80s host=%.80s",
  457.     user ? user : "???",tcp_clienthost ());
  458.     if (critical) state =LOGOUT;/* must defer if in critical code */
  459.     else { /* try to gracefully close the stream */
  460.       if ((state == TRANSACTION) && !stream->lock) {
  461. rset ();
  462. mail_close (stream);
  463.       }
  464.       state = LOGOUT;
  465.       stream = NIL;
  466.       _exit (1); /* die die die */
  467.     }
  468.   }
  469. }
  470. /* Hangup interrupt
  471.  */
  472. void hupint ()
  473. {
  474.   alarm (0); /* disable all interrupts */
  475.   server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
  476.   syslog (LOG_INFO,"Hangup user=%.80s host=%.80s",user ? user : "???",
  477.   tcp_clienthost ());
  478.   if (critical) state = LOGOUT; /* must defer if in critical code */
  479.   else { /* try to gracefully close the stream */
  480.     if ((state == TRANSACTION) && !stream->lock) {
  481.       rset ();
  482.       mail_close (stream);
  483.     }
  484.     state = LOGOUT;
  485.     stream = NIL;
  486.     _exit (1); /* die die die */
  487.   }
  488. }
  489. /* Termination interrupt
  490.  */
  491. void trmint ()
  492. {
  493.   alarm (0); /* disable all interrupts */
  494.   server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
  495.   PSOUT ("-ERR Killed1512");
  496.   syslog (LOG_INFO,"Killed user=%.80s host=%.80s",user ? user : "???",
  497.   tcp_clienthost ());
  498.   if (critical) state = LOGOUT; /* must defer if in critical code */
  499.   else { /* try to gracefully close the stream */
  500.     if ((state == TRANSACTION) && !stream->lock) {
  501.       rset ();
  502.       mail_close (stream);
  503.     }
  504.     state = LOGOUT;
  505.     stream = NIL;
  506.     _exit (1); /* die die die */
  507.   }
  508. }
  509. /* Parse PASS command
  510.  * Accepts: pointer to command argument
  511.  * Returns: new state
  512.  */
  513. int login (char *t,int argc,char *argv[])
  514. {
  515.   char tmp[TMPLEN];
  516. /* flush old passowrd */
  517.   if (pass) fs_give ((void **) &pass);
  518.   if (!(t && *t)) { /* if no password given */
  519.     PSOUT ("-ERR Missing password argument1512");
  520.     return AUTHORIZATION;
  521.   }
  522.   pass = cpystr (t); /* copy password argument */
  523. #ifndef DISABLE_POP_PROXY
  524. /* remote; build remote INBOX */
  525.   if (host && anonymous_login (argc,argv)) {
  526.     syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",host,
  527.     user,tcp_clienthost ());
  528.     sprintf (tmp,"{%.128s/user=%.128s}INBOX",host,user);
  529. /* disable rimap just in case */
  530.     mail_parameters (NIL,SET_RSHTIMEOUT,0);
  531.   }
  532. /* local; attempt login, select INBOX */
  533.   else if (!host && server_login (user,pass,argc,argv)) strcpy (tmp,"INBOX");
  534. #else
  535.   if (server_login (user,pass,argc,argv)) strcpy (tmp,"INBOX");
  536. #endif
  537.   else { /* vague error message to confuse crackers */
  538.     PSOUT ("-ERR Bad login1512");
  539.     return AUTHORIZATION;
  540.   }
  541.   return mbxopen (tmp);
  542. }
  543. /* Authentication responder
  544.  * Accepts: challenge
  545.  *     length of challenge
  546.  *     pointer to response length return location if non-NIL
  547.  * Returns: response
  548.  */
  549. #define RESPBUFLEN 8*MAILTMPLEN
  550. char *responder (void *challenge,unsigned long clen,unsigned long *rlen)
  551. {
  552.   unsigned long i,j;
  553.   unsigned char *t,resp[RESPBUFLEN];
  554.   if (initial) { /* initial response given? */
  555.     if (clen) return NIL; /* not permitted */
  556. /* set up response */
  557.     t = (unsigned char *) initial;
  558.     initial = NIL; /* no more initial response */
  559.     return (char *) rfc822_base64 (t,strlen (t),rlen ? rlen : &i);
  560.   }
  561.   PSOUT ("+ ");
  562.   for (t = rfc822_binary (challenge,clen,&i),j = 0; j < i; j++)
  563.     if (t[j] > ' ') PBOUT (t[j]);
  564.   fs_give ((void **) &t);
  565.   CRLF;
  566.   PFLUSH; /* dump output buffer */
  567.   resp[RESPBUFLEN-1] = ''; /* last buffer character is guaranteed NUL */
  568.   alarm (LOGINTIMEOUT); /* get a response under timeout */
  569.   clearerr (stdin); /* clear stdin errors */
  570. /* read buffer */
  571.   while (!PSIN ((char *) resp,RESPBUFLEN)) {
  572. /* ignore if some interrupt */
  573.     if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
  574.     else {
  575.       char *e = ferror (stdin) ?
  576. strerror (errno) : "Command stream end of file";
  577.       alarm (0); /* disable all interrupts */
  578.       server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
  579.       syslog (LOG_INFO,"%s, while reading authentication host=%.80s",
  580.       e,tcp_clienthost ());
  581.       state = UPDATE;
  582.       _exit (1);
  583.     }
  584.   }
  585.   if (!(t = (unsigned char *) strchr ((char *) resp,'12'))) {
  586.     int c;
  587.     while ((c = PBIN ()) != '12') if (c == EOF) {
  588. /* ignore if some interrupt */
  589.       if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
  590.       else {
  591. char *e = ferror (stdin) ?
  592.   strerror (errno) : "Command stream end of file";
  593. alarm (0); /* disable all interrupts */
  594. server_init (NIL,NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
  595. syslog (LOG_INFO,"%s, while reading auth char user=%.80s host=%.80s",
  596. e,user ? user : "???",tcp_clienthost ());
  597. state = UPDATE;
  598. _exit (1);
  599.       }
  600.     }
  601.     return NIL;
  602.   }
  603.   alarm (0); /* make sure timeout disabled */
  604.   if (t[-1] == '15') --t; /* remove CR */
  605.   *t = ''; /* tie off buffer */
  606.   return (resp[0] != '*') ?
  607.     (char *) rfc822_base64 (resp,t-resp,rlen ? rlen : &i) : NIL;
  608. }
  609. /* Select mailbox
  610.  * Accepts: mailbox name
  611.  * Returns: new state
  612.  */
  613. int mbxopen (char *mailbox)
  614. {
  615.   unsigned long i,j;
  616.   char tmp[TMPLEN];
  617.   MESSAGECACHE *elt;
  618.   nmsgs = 0; /* no messages yet */
  619.   if (msg) fs_give ((void **) &msg);
  620. /* open mailbox */
  621.   if (stream = mail_open (stream,mailbox,NIL)) {
  622.     if (!stream->rdonly) { /* make sure not readonly */
  623.       if (j = stream->nmsgs) { /* if mailbox non-empty */
  624. sprintf (tmp,"1:%lu",j);/* fetch fast information for all messages */
  625. mail_fetch_fast (stream,tmp,NIL);
  626. msg = (long *) fs_get ((stream->nmsgs + 1) * sizeof (long));
  627. for (i = 1; i <= j; i++) if (!(elt = mail_elt (stream,i))->deleted) {
  628.   msg[++nmsgs] = i; /* note the presence of this message */
  629.   if (elt->seen) il = last = nmsgs;
  630. }
  631.       }
  632.       sprintf (tmp,"+OK Mailbox open, %lu messages1512",nmsgs);
  633.       PSOUT (tmp);
  634.       return TRANSACTION;
  635.     }
  636.     else sayonara = "-ERR Can't get lock.  Mailbox in use1512";
  637.   }
  638.   else sayonara = "-ERR Unable to open user's INBOX1512";
  639.   syslog (LOG_INFO,"Error opening or locking INBOX user=%.80s host=%.80s",
  640.   user,tcp_clienthost ());
  641.   return UPDATE;
  642. }
  643. /* Blat a string with dot checking
  644.  * Accepts: string
  645.  *     maximum number of lines if greater than zero
  646.  *     maximum number of bytes to output
  647.  * Returns: number of lines output
  648.  *
  649.  * This routine is uglier and kludgier than it should be, just to be robust
  650.  * in the case of a message which doesn't end in a newline.  Yes, this routine
  651.  * does truncate the last two bytes from the text.  Since it is normally a
  652.  * newline and the main routine adds it back, it usually does not make a
  653.  * difference.  But if it isn't, since the newline is required and the octet
  654.  * counts have to match, there's no choice but to truncate.
  655.  */
  656. long blat (char *text,long lines,unsigned long size)
  657. {
  658.   char c,d,e;
  659.   long ret = 0;
  660. /* no-op if zero lines or empty string */
  661.   if (!(lines && (size-- > 2))) return 0;
  662.   c = *text++; d = *text++; /* collect first two bytes */
  663.   if (c == '.') PBOUT ('.'); /* double string-leading dot if necessary */
  664.   while (lines && --size) { /* copy loop */
  665.     e = *text++; /* get next byte */
  666.     PBOUT (c); /* output character */
  667.     if (c == '12') { /* end of line? */
  668.       ret++; --lines; /* count another line */
  669. /* double leading dot as necessary */
  670.       if (lines && size && (d == '.')) PBOUT ('.');
  671.     }
  672.     c = d; d = e; /* move to next character */
  673.   }
  674.   return ret;
  675. }
  676. /* Reset mailbox
  677.  */
  678. void rset ()
  679. {
  680.   unsigned long i;
  681.   char tmp[20];
  682.   if (nmsgs) { /* undelete and unmark all of our messages */
  683.     for (i = 1; i <= nmsgs; i++) { /*  */
  684.       if (msg[i] < 0) { /* ugly and inefficient, but trustworthy */
  685. sprintf (tmp,"%ld",msg[i] = -msg[i]);
  686. mail_clearflag (stream,tmp,i <= il ? "\Deleted" : "\Deleted \Seen");
  687.       }
  688.       else if (i > il) {
  689. sprintf (tmp,"%ld",msg[i]);
  690. mail_clearflag (stream,tmp,"\Seen");
  691.       }
  692.     }
  693.     last = il;
  694.   }
  695.   ndele = 0; /* no more deleted messages */
  696. }
  697. /* Co-routines from MAIL library */
  698. /* Message matches a search
  699.  * Accepts: MAIL stream
  700.  *     message number
  701.  */
  702. void mm_searched (MAILSTREAM *stream,unsigned long msgno)
  703. {
  704.   /* Never called */
  705. }
  706. /* Message exists (i.e. there are that many messages in the mailbox)
  707.  * Accepts: MAIL stream
  708.  *     message number
  709.  */
  710. void mm_exists (MAILSTREAM *stream,unsigned long number)
  711. {
  712.   /* Can't use this mechanism.  POP has no means of notifying the client of
  713.      new mail during the session. */
  714. }
  715. /* Message expunged
  716.  * Accepts: MAIL stream
  717.  *     message number
  718.  */
  719. void mm_expunged (MAILSTREAM *stream,unsigned long number)
  720. {
  721.   unsigned long i = number + 1;
  722.   msg[number] = 0; /* I bet that this will annoy someone */
  723.   while (i <= nmsgs) --msg[i++];
  724. }
  725. /* Message flag status change
  726.  * Accepts: MAIL stream
  727.  *     message number
  728.  */
  729. void mm_flags (MAILSTREAM *stream,unsigned long number)
  730. {
  731.   /* This isn't used */
  732. }
  733. /* Mailbox found
  734.  * Accepts: MAIL stream
  735.  *     hierarchy delimiter
  736.  *     mailbox name
  737.  *     mailbox attributes
  738.  */
  739. void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
  740. {
  741.   /* This isn't used */
  742. }
  743. /* Subscribe mailbox found
  744.  * Accepts: MAIL stream
  745.  *     hierarchy delimiter
  746.  *     mailbox name
  747.  *     mailbox attributes
  748.  */
  749. void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
  750. {
  751.   /* This isn't used */
  752. }
  753. /* Mailbox status
  754.  * Accepts: MAIL stream
  755.  *     mailbox name
  756.  *     mailbox status
  757.  */
  758. void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
  759. {
  760.   /* This isn't used */
  761. }
  762. /* Notification event
  763.  * Accepts: MAIL stream
  764.  *     string to log
  765.  *     error flag
  766.  */
  767. void mm_notify (MAILSTREAM *stream,char *string,long errflg)
  768. {
  769.   mm_log (string,errflg); /* just do mm_log action */
  770. }
  771. /* Log an event for the user to see
  772.  * Accepts: string to log
  773.  *     error flag
  774.  */
  775. void mm_log (char *string,long errflg)
  776. {
  777.   switch (errflg) {
  778.   case NIL: /* information message */
  779.   case PARSE: /* parse glitch */
  780.     break; /* too many of these to log */
  781.   case WARN: /* warning */
  782.     syslog (LOG_DEBUG,"%s",string);
  783.     break;
  784.   case ERROR: /* error that broke command */
  785.   default: /* default should never happen */
  786.     syslog (LOG_NOTICE,"%s",string);
  787.     break;
  788.   }
  789. }
  790. /* Log an event to debugging telemetry
  791.  * Accepts: string to log
  792.  */
  793. void mm_dlog (char *string)
  794. {
  795.   /* Not doing anything here for now */
  796. }
  797. /* Get user name and password for this host
  798.  * Accepts: parse of network mailbox name
  799.  *     where to return user name
  800.  *     where to return password
  801.  *     trial count
  802.  */
  803. void mm_login (NETMBX *mb,char *username,char *password,long trial)
  804. {
  805. /* set user name */
  806.   strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
  807.   strncpy (password,pass,255); /* and password */
  808.   username[NETMAXUSER] = password[255] = '';
  809. }
  810. /* About to enter critical code
  811.  * Accepts: stream
  812.  */
  813. void mm_critical (MAILSTREAM *stream)
  814. {
  815.   critical = T;
  816. }
  817. /* About to exit critical code
  818.  * Accepts: stream
  819.  */
  820. void mm_nocritical (MAILSTREAM *stream)
  821. {
  822.   critical = NIL;
  823. }
  824. /* Disk error found
  825.  * Accepts: stream
  826.  *     system error code
  827.  *     flag indicating that mailbox may be clobbered
  828.  * Returns: abort flag
  829.  */
  830. long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
  831. {
  832.   if (serious) { /* try your damnest if clobberage likely */
  833.     syslog (LOG_ALERT,
  834.     "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
  835.     user,tcp_clienthost (),
  836.     (stream && stream->mailbox) ? stream->mailbox : "???",
  837.     strerror (errcode));
  838.     alarm (0); /* make damn sure timeout disabled */
  839.     sleep (60); /* give it some time to clear up */
  840.     return NIL;
  841.   }
  842.   syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
  843.   user,tcp_clienthost (),
  844.   (stream && stream->mailbox) ? stream->mailbox : "???",
  845.   strerror (errcode));
  846.   return T;
  847. }
  848. /* Log a fatal error event
  849.  * Accepts: string to log
  850.  */
  851. void mm_fatal (char *string)
  852. {
  853.   mm_log (string,ERROR); /* shouldn't happen normally */
  854. }