imapext-2007

diff src/ipopd/ipop3d.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children 28a55bc1110c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/ipopd/ipop3d.c	Mon Sep 14 15:17:45 2009 +0900
     1.3 @@ -0,0 +1,1082 @@
     1.4 +/* ========================================================================
     1.5 + * Copyright 1988-2008 University of Washington
     1.6 + *
     1.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.8 + * you may not use this file except in compliance with the License.
     1.9 + * You may obtain a copy of the License at
    1.10 + *
    1.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    1.12 + *
    1.13 + * 
    1.14 + * ========================================================================
    1.15 + */
    1.16 +
    1.17 +/*
    1.18 + * Program:	IPOP3D - IMAP to POP3 conversion server
    1.19 + *
    1.20 + * Author:	Mark Crispin
    1.21 + *		UW Technology
    1.22 + *		University of Washington
    1.23 + *		Seattle, WA  98195
    1.24 + *		Internet: MRC@Washington.EDU
    1.25 + *
    1.26 + * Date:	1 November 1990
    1.27 + * Last Edited:	19 February 2008
    1.28 + */
    1.29 +
    1.30 +/* Parameter files */
    1.31 +
    1.32 +#include <stdio.h>
    1.33 +#include <ctype.h>
    1.34 +#include <errno.h>
    1.35 +extern int errno;		/* just in case */
    1.36 +#include <signal.h>
    1.37 +#include <time.h>
    1.38 +#include "c-client.h"
    1.39 +
    1.40 +
    1.41 +#define CRLF PSOUT ("\015\012")	/* primary output terpri */
    1.42 +
    1.43 +
    1.44 +/* Autologout timer */
    1.45 +#define KODTIMEOUT 60*5
    1.46 +#define LOGINTIMEOUT 60*3
    1.47 +#define TIMEOUT 60*10
    1.48 +
    1.49 +
    1.50 +/* Server states */
    1.51 +
    1.52 +#define AUTHORIZATION 0
    1.53 +#define TRANSACTION 1
    1.54 +#define UPDATE 2
    1.55 +#define LOGOUT 3
    1.56 +
    1.57 +/* Eudora food */
    1.58 +
    1.59 +#define STATUS "Status: %s%s\015\012"
    1.60 +#define SLEN (sizeof (STATUS)-3)
    1.61 +
    1.62 +
    1.63 +/* Global storage */
    1.64 +
    1.65 +char *version = "104";		/* edit number of this server */
    1.66 +short state = AUTHORIZATION;	/* server state */
    1.67 +short critical = NIL;		/* non-zero if in critical code */
    1.68 +MAILSTREAM *stream = NIL;	/* mailbox stream */
    1.69 +time_t idletime = 0;		/* time we went idle */
    1.70 +unsigned long nmsgs = 0;	/* current number of messages */
    1.71 +unsigned long ndele = 0;	/* number of deletes */
    1.72 +unsigned long nseen = 0;	/* number of mark-seens */
    1.73 +unsigned long last = 0;		/* highest message accessed */
    1.74 +unsigned long il = 0;		/* initial last message */
    1.75 +char challenge[128];		/* challenge */
    1.76 +char *host = NIL;		/* remote host name */
    1.77 +char *user = NIL;		/* user name */
    1.78 +char *pass = NIL;		/* password */
    1.79 +char *initial = NIL;		/* initial response */
    1.80 +long *msg = NIL;		/* message translation vector */
    1.81 +short *flags = NIL;		/* flags */
    1.82 +char *logout = "Logout";
    1.83 +char *goodbye = "+OK Sayonara\015\012";
    1.84 +
    1.85 +
    1.86 +/* POP3 flags */
    1.87 +
    1.88 +#define DELE 0x1
    1.89 +#define SEEN 0x2
    1.90 +
    1.91 +
    1.92 +/* Function prototypes */
    1.93 +
    1.94 +int main (int argc,char *argv[]);
    1.95 +void sayonara (int status);
    1.96 +void clkint ();
    1.97 +void kodint ();
    1.98 +void hupint ();
    1.99 +void trmint ();
   1.100 +int pass_login (char *t,int argc,char *argv[]);
   1.101 +char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
   1.102 +char *responder (void *challenge,unsigned long clen,unsigned long *rlen);
   1.103 +int mbxopen (char *mailbox);
   1.104 +long blat (char *text,long lines,unsigned long size,STRING *st);
   1.105 +void rset ();
   1.106 +
   1.107 +/* Main program */
   1.108 +
   1.109 +int main (int argc,char *argv[])
   1.110 +{
   1.111 +  unsigned long i,j,k;
   1.112 +  char *s,*t;
   1.113 +  char tmp[MAILTMPLEN];
   1.114 +  time_t autologouttime;
   1.115 +  char *pgmname = (argc && argv[0]) ?
   1.116 +    (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
   1.117 +     s+1 : argv[0]) : "ipop3d";
   1.118 +				/* set service name before linkage */
   1.119 +  mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
   1.120 +#include "linkage.c"
   1.121 +				/* initialize server */
   1.122 +  server_init (pgmname,"pop3","pop3s",clkint,kodint,hupint,trmint,NIL);
   1.123 +  mail_parameters (NIL,SET_BLOCKENVINIT,VOIDT);
   1.124 +  s = myusername_full (&i);	/* get user name and flags */
   1.125 +  mail_parameters (NIL,SET_BLOCKENVINIT,NIL);
   1.126 +  if (i == MU_LOGGEDIN) {	/* allow EXTERNAL if logged in already */
   1.127 +    mail_parameters (NIL,UNHIDE_AUTHENTICATOR,(void *) "EXTERNAL");
   1.128 +    mail_parameters (NIL,SET_EXTERNALAUTHID,(void *) s);
   1.129 +  }
   1.130 +  {				/* set up MD5 challenge */
   1.131 +    AUTHENTICATOR *auth = mail_lookup_auth (1);
   1.132 +    while (auth && compare_cstring (auth->name,"CRAM-MD5")) auth = auth->next;
   1.133 +				/* build challenge -- less than 128 chars */
   1.134 +    if (auth && auth->server && !(auth->flags & AU_DISABLE))
   1.135 +      sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (),
   1.136 +	       (unsigned long) time (0),tcp_serverhost ());
   1.137 +    else challenge[0] = '\0';	/* no MD5 authentication */
   1.138 +  }
   1.139 +  /* There are reports of POP3 clients which get upset if anything appears
   1.140 +   * between the "+OK" and the "POP3" in the greeting.
   1.141 +   */
   1.142 +  PSOUT ("+OK POP3 ");
   1.143 +  if (!challenge[0]) {		/* if no MD5 enable, output host name */
   1.144 +    PSOUT (tcp_serverhost ());
   1.145 +    PBOUT (' ');
   1.146 +  }
   1.147 +  PSOUT (CCLIENTVERSION);
   1.148 +  PBOUT ('.');
   1.149 +  PSOUT (version);
   1.150 +  PSOUT (" server ready");
   1.151 +  if (challenge[0]) {		/* if MD5 enable, output challenge here */
   1.152 +    PBOUT (' ');
   1.153 +    PSOUT (challenge);
   1.154 +  }
   1.155 +  CRLF;
   1.156 +  PFLUSH ();			/* dump output buffer */
   1.157 +  autologouttime = time (0) + LOGINTIMEOUT;
   1.158 +				/* command processing loop */
   1.159 +  while ((state != UPDATE) && (state != LOGOUT)) {
   1.160 +    idletime = time (0);	/* get a command under timeout */
   1.161 +    alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT);
   1.162 +    clearerr (stdin);		/* clear stdin errors */
   1.163 +				/* read command line */
   1.164 +    while (!PSIN (tmp,MAILTMPLEN)) {
   1.165 +				/* ignore if some interrupt */
   1.166 +      if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
   1.167 +      else {
   1.168 +	char *e = ferror (stdin) ?
   1.169 +	  strerror (errno) : "Unexpected client disconnect";
   1.170 +	alarm (0);		/* disable all interrupts */
   1.171 +	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
   1.172 +	sprintf (logout = tmp,"%.80s, while reading line",e);
   1.173 +	goodbye = NIL;
   1.174 +	rset ();		/* try to gracefully close the stream */
   1.175 +	if (state == TRANSACTION) mail_close (stream);
   1.176 +	stream = NIL;
   1.177 +	state = LOGOUT;
   1.178 +	sayonara (1);
   1.179 +      }
   1.180 +    }
   1.181 +    alarm (0);			/* make sure timeout disabled */
   1.182 +    idletime = 0;		/* no longer idle */
   1.183 +
   1.184 +    if (!strchr (tmp,'\012'))	/* find end of line */
   1.185 +      PSOUT ("-ERR Command line too long\015\012");
   1.186 +    else if (!(s = strtok (tmp," \015\012")))
   1.187 +      PSOUT ("-ERR Null command\015\012");
   1.188 +    else {			/* dispatch based on command */
   1.189 +      ucase (s);		/* canonicalize case */
   1.190 +				/* snarf argument */
   1.191 +      t = strtok (NIL,"\015\012");
   1.192 +				/* QUIT command always valid */
   1.193 +      if (!strcmp (s,"QUIT")) state = UPDATE;
   1.194 +      else if (!strcmp (s,"CAPA")) {
   1.195 +	AUTHENTICATOR *auth;
   1.196 +	PSOUT ("+OK Capability list follows:\015\012");
   1.197 +	PSOUT ("TOP\015\012LOGIN-DELAY 180\015\012UIDL\015\012");
   1.198 +	if (s = ssl_start_tls (NIL)) fs_give ((void **) &s);
   1.199 +	else PSOUT ("STLS\015\012");
   1.200 +	if (i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))
   1.201 +	  PSOUT ("USER\015\012");
   1.202 +				/* display secure server authenticators */
   1.203 +	for (auth = mail_lookup_auth (1), s = "SASL"; auth; auth = auth->next)
   1.204 +	  if (auth->server && !(auth->flags & AU_DISABLE) &&
   1.205 +	      !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) {
   1.206 +	    if (s) {
   1.207 +	      PSOUT (s);
   1.208 +	      s = NIL;
   1.209 +	    }
   1.210 +	    PBOUT (' ');
   1.211 +	    PSOUT (auth->name);
   1.212 +	  }
   1.213 +	PSOUT (s ? ".\015\012" : "\015\012.\015\012");
   1.214 +      }
   1.215 +
   1.216 +      else switch (state) {	/* else dispatch based on state */
   1.217 +      case AUTHORIZATION:	/* waiting to get logged in */
   1.218 +	if (!strcmp (s,"AUTH")) {
   1.219 +	  if (t && *t) {	/* mechanism given? */
   1.220 +	    if (host) fs_give ((void **) &host);
   1.221 +	    if (user) fs_give ((void **) &user);
   1.222 +	    if (pass) fs_give ((void **) &pass);
   1.223 +	    s = strtok (t," ");	/* get mechanism name */
   1.224 +				/* get initial response */
   1.225 +	    if (initial = strtok (NIL,"\015\012")) {
   1.226 +	      if ((*initial == '=') && !initial[1]) ++initial;
   1.227 +	      else if (!*initial) initial = NIL;
   1.228 +	    }
   1.229 +	    if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) {
   1.230 +	      PSOUT ("-ERR Bad authentication\015\012");
   1.231 +	      syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s,
   1.232 +		      tcp_clienthost ());
   1.233 +	    }
   1.234 +	    else if ((state = mbxopen ("INBOX")) == TRANSACTION)
   1.235 +	      syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%lu/%lu",
   1.236 +		      user,tcp_clienthost (),nmsgs,stream->nmsgs);
   1.237 +	    else syslog (LOG_INFO,"Auth user=%.80s host=%.80s no mailbox",
   1.238 +			 user,tcp_clienthost ());
   1.239 +	  }
   1.240 +	  else {
   1.241 +	    AUTHENTICATOR *auth;
   1.242 +	    PSOUT ("+OK Supported authentication mechanisms:\015\012");
   1.243 +	    i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL);
   1.244 +	    for (auth = mail_lookup_auth (1); auth; auth = auth->next)
   1.245 +	      if (auth->server && !(auth->flags & AU_DISABLE) &&
   1.246 +		  !(auth->flags & AU_HIDE) &&
   1.247 +		  (i || (auth->flags & AU_SECURE))) {
   1.248 +		PSOUT (auth->name);
   1.249 +		CRLF;
   1.250 +	      }
   1.251 +	    PBOUT ('.');
   1.252 +	    CRLF;
   1.253 +	  }
   1.254 +	}
   1.255 +
   1.256 +	else if (!strcmp (s,"APOP")) {
   1.257 +	  if (challenge[0]) {	/* can do it if have an MD5 challenge */
   1.258 +	    if (host) fs_give ((void **) &host);
   1.259 +	    if (user) fs_give ((void **) &user);
   1.260 +	    if (pass) fs_give ((void **) &pass);
   1.261 +				/* get user name */
   1.262 +	    if (!(t && *t && (s = strtok (t," ")) && (t = strtok(NIL,"\012"))))
   1.263 +	      PSOUT ("-ERR Missing APOP argument\015\012");
   1.264 +	    else if (!(user = apop_login (challenge,s,t,argc,argv)))
   1.265 +	      PSOUT ("-ERR Bad APOP\015\012");
   1.266 +	    else if ((state = mbxopen ("INBOX")) == TRANSACTION)
   1.267 +	      syslog (LOG_INFO,"APOP user=%.80s host=%.80s nmsgs=%lu/%lu",
   1.268 +		      user,tcp_clienthost (),nmsgs,stream->nmsgs);
   1.269 +	    else syslog (LOG_INFO,"APOP user=%.80s host=%.80s no mailbox",
   1.270 +			 user,tcp_clienthost ());
   1.271 +	  }
   1.272 +	  else PSOUT ("-ERR Not supported\015\012");
   1.273 +	}
   1.274 +				/* (chuckle) */
   1.275 +	else if (!strcmp (s,"RPOP"))
   1.276 +	  PSOUT ("-ERR Nice try, bunkie\015\012");
   1.277 +	else if (!strcmp (s,"STLS")) {
   1.278 +	  if (t = ssl_start_tls (pgmname)) {
   1.279 +	    PSOUT ("-ERR STLS failed: ");
   1.280 +	    PSOUT (t);
   1.281 +	    CRLF;
   1.282 +	  }
   1.283 +	  else PSOUT ("+OK STLS completed\015\012");
   1.284 +	}
   1.285 +	else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) &&
   1.286 +		 !strcmp (s,"USER")) {
   1.287 +	  if (host) fs_give ((void **) &host);
   1.288 +	  if (user) fs_give ((void **) &user);
   1.289 +	  if (pass) fs_give ((void **) &pass);
   1.290 +	  if (t && *t) {	/* if user name given */
   1.291 +				/* skip leading whitespace (bogus clients!) */
   1.292 +	    while (*t == ' ') ++t;
   1.293 +				/* remote user name? */
   1.294 +	    if (s = strchr (t,':')) {
   1.295 +	      *s++ = '\0';	/* tie off host name */
   1.296 +	      host = cpystr (t);/* copy host name */
   1.297 +	      user = cpystr (s);/* copy user name */
   1.298 +	    }
   1.299 +				/* local user name */
   1.300 +	    else user = cpystr (t);
   1.301 +	    PSOUT ("+OK User name accepted, password please\015\012");
   1.302 +	  }
   1.303 +	  else PSOUT ("-ERR Missing username argument\015\012");
   1.304 +	}
   1.305 +	else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) &&
   1.306 +		 user && *user && !strcmp (s,"PASS"))
   1.307 +	  state = pass_login (t,argc,argv);
   1.308 +	else PSOUT ("-ERR Unknown AUTHORIZATION state command\015\012");
   1.309 +	break;
   1.310 +
   1.311 +      case TRANSACTION:		/* logged in */
   1.312 +	if (!strcmp (s,"STAT")) {
   1.313 +	  for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
   1.314 +				/* message still exists? */
   1.315 +	    if (msg[i] && !(flags[i] & DELE)) {
   1.316 +	      j++;		/* count one more undeleted message */
   1.317 +	      k += mail_elt (stream,msg[i])->rfc822_size + SLEN;
   1.318 +	    }
   1.319 +	  sprintf (tmp,"+OK %lu %lu\015\012",j,k);
   1.320 +	  PSOUT (tmp);
   1.321 +	}
   1.322 +	else if (!strcmp (s,"LIST")) {
   1.323 +	  if (t && *t) {	/* argument do single message */
   1.324 +	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
   1.325 +		!(flags[i] & DELE)) {
   1.326 +	      sprintf (tmp,"+OK %lu %lu\015\012",i,
   1.327 +		       mail_elt(stream,msg[i])->rfc822_size + SLEN);
   1.328 +	      PSOUT (tmp);
   1.329 +	    }
   1.330 +	    else PSOUT ("-ERR No such message\015\012");
   1.331 +	  }
   1.332 +	  else {		/* entire mailbox */
   1.333 +	    PSOUT ("+OK Mailbox scan listing follows\015\012");
   1.334 +	    for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
   1.335 +	      if (msg[i] && !(flags[i] & DELE)) {
   1.336 +		sprintf (tmp,"%lu %lu\015\012",i,
   1.337 +			 mail_elt (stream,msg[i])->rfc822_size + SLEN);
   1.338 +		PSOUT (tmp);
   1.339 +	      }
   1.340 +	    PBOUT ('.');	/* end of list */
   1.341 +	    CRLF;
   1.342 +	  }
   1.343 +	}
   1.344 +	else if (!strcmp (s,"UIDL")) {
   1.345 +	  if (t && *t) {	/* argument do single message */
   1.346 +	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
   1.347 +		!(flags[i] & DELE)) {
   1.348 +	      sprintf (tmp,"+OK %lu %08lx%08lx\015\012",i,stream->uid_validity,
   1.349 +		       mail_uid (stream,msg[i]));
   1.350 +	      PSOUT (tmp);
   1.351 +	    }
   1.352 +	    else PSOUT ("-ERR No such message\015\012");
   1.353 +	  }
   1.354 +	  else {		/* entire mailbox */
   1.355 +	    PSOUT ("+OK Unique-ID listing follows\015\012");
   1.356 +	    for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
   1.357 +	      if (msg[i] && !(flags[i] & DELE)) {
   1.358 +		sprintf (tmp,"%lu %08lx%08lx\015\012",i,stream->uid_validity,
   1.359 +			 mail_uid (stream,msg[i]));
   1.360 +		PSOUT (tmp);
   1.361 +	      }
   1.362 +	    PBOUT ('.');	/* end of list */
   1.363 +	    CRLF;
   1.364 +	  }
   1.365 +	}
   1.366 +
   1.367 +	else if (!strcmp (s,"RETR")) {
   1.368 +	  if (t && *t) {	/* must have an argument */
   1.369 +	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
   1.370 +		!(flags[i] & DELE)) {
   1.371 +	      MESSAGECACHE *elt;
   1.372 +				/* update highest message accessed */
   1.373 +	      if (i > last) last = i;
   1.374 +	      sprintf (tmp,"+OK %lu octets\015\012",
   1.375 +		       (elt = mail_elt (stream,msg[i]))->rfc822_size + SLEN);
   1.376 +	      PSOUT (tmp);
   1.377 +				/* if not marked seen or noted to be marked */
   1.378 +	      if (!(elt->seen || (flags[i] & SEEN))) {
   1.379 +		++nseen;	/* note that we need to mark it seen */
   1.380 +		flags[i] |= SEEN;
   1.381 +	      }
   1.382 +				/* get header */
   1.383 +	      t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
   1.384 +	      blat (t,-1,k,NIL);/* write up to trailing CRLF */
   1.385 +				/* build status */
   1.386 +	      sprintf (tmp,STATUS,elt->seen ? "R" : " ",
   1.387 +		       elt->recent ? " " : "O");
   1.388 +	      if (k < 4) CRLF;	/* don't write Status: if no header */
   1.389 +				/* normal header ending with CRLF CRLF? */
   1.390 +	      else if (t[k-3] == '\012') {
   1.391 +		PSOUT (tmp);	/* write status */
   1.392 +		CRLF;		/* then write second CRLF */
   1.393 +	      }
   1.394 +	      else {		/* abnormal - no blank line at end of header */
   1.395 +		CRLF;		/* write CRLF first then */
   1.396 +		PSOUT (tmp);
   1.397 +	      }
   1.398 +				/* output text */
   1.399 +	      t = mail_fetch_text (stream,msg[i],NIL,&k,
   1.400 +				   FT_RETURNSTRINGSTRUCT | FT_PEEK);
   1.401 +	      if (k) {		/* only if there is a text body */
   1.402 +		blat (t,-1,k,&stream->private.string);
   1.403 +		CRLF;		/* end of list */
   1.404 +	      }
   1.405 +	      PBOUT ('.');
   1.406 +	      CRLF;
   1.407 +	    }
   1.408 +	    else PSOUT ("-ERR No such message\015\012");
   1.409 +	  }
   1.410 +	  else PSOUT ("-ERR Missing message number argument\015\012");
   1.411 +	}
   1.412 +
   1.413 +	else if (!strcmp (s,"DELE")) {
   1.414 +	  if (t && *t) {	/* must have an argument */
   1.415 +	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
   1.416 +		!(flags[i] & DELE)) {
   1.417 +				/* update highest message accessed */
   1.418 +	      if (i > last) last = i;
   1.419 +	      flags[i] |= DELE;	/* note that deletion is requested */
   1.420 +	      PSOUT ("+OK Message deleted\015\012");
   1.421 +	      ++ndele;		/* one more message deleted */
   1.422 +	    }
   1.423 +	    else PSOUT ("-ERR No such message\015\012");
   1.424 +	  }
   1.425 +	  else PSOUT ("-ERR Missing message number argument\015\012");
   1.426 +	}
   1.427 +	else if (!strcmp (s,"NOOP"))
   1.428 +	  PSOUT ("+OK No-op to you too!\015\012");
   1.429 +	else if (!strcmp (s,"LAST")) {
   1.430 +	  sprintf (tmp,"+OK %lu\015\012",last);
   1.431 +	  PSOUT (tmp);
   1.432 +	}
   1.433 +	else if (!strcmp (s,"RSET")) {
   1.434 +	  rset ();		/* reset the mailbox */
   1.435 +	  PSOUT ("+OK Reset state\015\012");
   1.436 +	}
   1.437 +
   1.438 +	else if (!strcmp (s,"TOP")) {
   1.439 +	  if (t && *t && (i =strtoul (t,&s,10)) && (i <= nmsgs) && msg[i] &&
   1.440 +	      !(flags[i] & DELE)) {
   1.441 +				/* skip whitespace */
   1.442 +	    while (*s == ' ') s++;
   1.443 +				/* make sure line count argument good */
   1.444 +	    if ((*s >= '0') && (*s <= '9')) {
   1.445 +	      MESSAGECACHE *elt = mail_elt (stream,msg[i]);
   1.446 +	      j = strtoul (s,NIL,10);
   1.447 +				/* update highest message accessed */
   1.448 +	      if (i > last) last = i;
   1.449 +	      PSOUT ("+OK Top of message follows\015\012");
   1.450 +				/* get header */
   1.451 +	      t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
   1.452 +	      blat (t,-1,k,NIL);/* write up to trailing CRLF */
   1.453 +				/* build status */
   1.454 +	      sprintf (tmp,STATUS,elt->seen ? "R" : " ",
   1.455 +		       elt->recent ? " " : "O");
   1.456 +	      if (k < 4) CRLF;	/* don't write Status: if no header */
   1.457 +				/* normal header ending with CRLF CRLF? */
   1.458 +	      else if (t[k-3] == '\012') {
   1.459 +		PSOUT (tmp);	/* write status */
   1.460 +		CRLF;		/* then write second CRLF */
   1.461 +	      }
   1.462 +	      else {		/* abnormal - no blank line at end of header */
   1.463 +		CRLF;		/* write CRLF first then */
   1.464 +		PSOUT (tmp);
   1.465 +	      }
   1.466 +	      if (j) {		/* want any text lines? */
   1.467 +				/* output text */
   1.468 +		t = mail_fetch_text (stream,msg[i],NIL,&k,
   1.469 +				     FT_PEEK | FT_RETURNSTRINGSTRUCT);
   1.470 +				/* tie off final line if full text output */
   1.471 +		if (k && (j -= blat (t,j,k,&stream->private.string))) CRLF;
   1.472 +	      }
   1.473 +	      PBOUT ('.');	/* end of list */
   1.474 +	      CRLF;
   1.475 +	    }
   1.476 +	    else PSOUT ("-ERR Bad line count argument\015\012");
   1.477 +	  }
   1.478 +	  else PSOUT ("-ERR Bad message number argument\015\012");
   1.479 +	}
   1.480 +
   1.481 +	else if (!strcmp (s,"XTND"))
   1.482 +	  PSOUT ("-ERR Sorry I can't do that\015\012");
   1.483 +	else PSOUT ("-ERR Unknown TRANSACTION state command\015\012");
   1.484 +	break;
   1.485 +      default:
   1.486 +        PSOUT ("-ERR Server in unknown state\015\012");
   1.487 +	break;
   1.488 +      }
   1.489 +    }
   1.490 +    PFLUSH ();			/* make sure output finished */
   1.491 +    if (autologouttime) {	/* have an autologout in effect? */
   1.492 +				/* cancel if no longer waiting for login */
   1.493 +      if (state != AUTHORIZATION) autologouttime = 0;
   1.494 +				/* took too long to login */
   1.495 +      else if (autologouttime < time (0)) {
   1.496 +	goodbye = "-ERR Autologout\015\012";
   1.497 +	logout = "Autologout";
   1.498 +	state = LOGOUT;		/* sayonara */
   1.499 +      }
   1.500 +    }
   1.501 +  }
   1.502 +
   1.503 +				/* open and need to update? */
   1.504 +  if (stream && (state == UPDATE)) {
   1.505 +    if (nseen) {		/* only bother if messages need marking seen */
   1.506 +      *(s = tmp) = '\0';	/* clear sequence */
   1.507 +      for (i = 1; i <= nmsgs; ++i) if (flags[i] & SEEN) {
   1.508 +	for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & SEEN); ++j) k = j;
   1.509 +	if (k) sprintf (s,",%lu:%lu",i,k);
   1.510 +	else sprintf (s,",%lu",i);
   1.511 +	s += strlen (s);		/* point to end of string */
   1.512 +	if ((s - tmp) > (MAILTMPLEN - 30)) {
   1.513 +	  mail_setflag (stream,tmp + 1,"\\Seen");
   1.514 +	  *(s = tmp) = '\0';	/* restart sequence */
   1.515 +	}
   1.516 +	i = j;			/* continue after the range */
   1.517 +      }
   1.518 +      if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Seen");
   1.519 +    }
   1.520 +    if (ndele) {		/* any messages to delete? */
   1.521 +      *(s = tmp) = '\0';	/* clear sequence */
   1.522 +      for (i = 1; i <= nmsgs; ++i) if (flags[i] & DELE) {
   1.523 +	for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & DELE); ++j) k = j;
   1.524 +	if (k) sprintf (s,",%lu:%lu",i,k);
   1.525 +	else sprintf (s,",%lu",i);
   1.526 +	s += strlen (s);	/* point to end of string */
   1.527 +	if ((s - tmp) > (MAILTMPLEN - 30)) {
   1.528 +	  mail_setflag (stream,tmp + 1,"\\Deleted");
   1.529 +	  *(s = tmp) = '\0';	/* restart sequence */
   1.530 +	}
   1.531 +	i = j;			/* continue after the range */
   1.532 +      }
   1.533 +      if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Deleted");
   1.534 +      mail_expunge (stream);
   1.535 +    }
   1.536 +    syslog (LOG_INFO,"Update user=%.80s host=%.80s nmsgs=%lu ndele=%lu nseen=%lu",
   1.537 +	    user,tcp_clienthost (),stream->nmsgs,ndele,nseen);
   1.538 +    mail_close (stream);
   1.539 +  }
   1.540 +  sayonara (0);
   1.541 +  return 0;			/* stupid compilers */
   1.542 +}
   1.543 +
   1.544 +
   1.545 +/* Say goodbye
   1.546 + * Accepts: exit status
   1.547 + *
   1.548 + * Does not return
   1.549 + */
   1.550 +
   1.551 +void sayonara (int status)
   1.552 +{
   1.553 +  logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL);
   1.554 +  if (goodbye) {		/* have a goodbye message? */
   1.555 +    PSOUT (goodbye);
   1.556 +    PFLUSH ();			/* make sure blatted */
   1.557 +  }
   1.558 +  syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
   1.559 +	  user ? (char *) user : "???",tcp_clienthost ());
   1.560 +				/* do logout hook if needed */
   1.561 +  if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
   1.562 +  _exit (status);		/* all done */
   1.563 +}
   1.564 +
   1.565 +/* Clock interrupt
   1.566 + */
   1.567 +
   1.568 +void clkint ()
   1.569 +{
   1.570 +  alarm (0);			/* disable all interrupts */
   1.571 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
   1.572 +  goodbye = "-ERR Autologout; idle for too long\015\012";
   1.573 +  logout = "Autologout";
   1.574 +  if (critical) state = LOGOUT;	/* badly hosed if in critical code */
   1.575 +  else {			/* try to gracefully close the stream */
   1.576 +    if ((state == TRANSACTION) && !stream->lock) {
   1.577 +      rset ();
   1.578 +      mail_close (stream);
   1.579 +    }
   1.580 +    state = LOGOUT;
   1.581 +    stream = NIL;
   1.582 +    sayonara (1);
   1.583 +  }
   1.584 +}
   1.585 +
   1.586 +
   1.587 +/* Kiss Of Death interrupt
   1.588 + */
   1.589 +
   1.590 +void kodint ()
   1.591 +{
   1.592 +				/* only if idle */
   1.593 +  if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
   1.594 +    alarm (0);			/* disable all interrupts */
   1.595 +    server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
   1.596 +    goodbye = "-ERR Received Kiss of Death\015\012";
   1.597 +    logout = "Killed (lost mailbox lock)";
   1.598 +    if (critical) state =LOGOUT;/* must defer if in critical code */
   1.599 +    else {			/* try to gracefully close the stream */
   1.600 +      if ((state == TRANSACTION) && !stream->lock) {
   1.601 +	rset ();
   1.602 +	mail_close (stream);
   1.603 +      }
   1.604 +      state = LOGOUT;
   1.605 +      stream = NIL;
   1.606 +      sayonara (1);		/* die die die */
   1.607 +    }
   1.608 +  }
   1.609 +}
   1.610 +
   1.611 +
   1.612 +/* Hangup interrupt
   1.613 + */
   1.614 +
   1.615 +void hupint ()
   1.616 +{
   1.617 +  alarm (0);			/* disable all interrupts */
   1.618 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
   1.619 +  goodbye = NIL;		/* nobody left to talk to */
   1.620 +  logout = "Hangup";
   1.621 +  if (critical) state = LOGOUT;	/* must defer if in critical code */
   1.622 +  else {			/* try to gracefully close the stream */
   1.623 +    if ((state == TRANSACTION) && !stream->lock) {
   1.624 +      rset ();
   1.625 +      mail_close (stream);
   1.626 +    }
   1.627 +    state = LOGOUT;
   1.628 +    stream = NIL;
   1.629 +    sayonara (1);		/* die die die */
   1.630 +  }
   1.631 +}
   1.632 +
   1.633 +
   1.634 +/* Termination interrupt
   1.635 + */
   1.636 +
   1.637 +void trmint ()
   1.638 +{
   1.639 +  alarm (0);			/* disable all interrupts */
   1.640 +  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
   1.641 +  goodbye = "-ERR Killed\015\012";
   1.642 +  logout = "Killed";
   1.643 +  if (critical) state = LOGOUT;	/* must defer if in critical code */
   1.644 +  /* Make no attempt at graceful closure since a shutdown may be in
   1.645 +   * progress, and we won't have any time to do mail_close() actions.
   1.646 +   */
   1.647 +  else sayonara (1);		/* die die die */
   1.648 +}
   1.649 +
   1.650 +/* Parse PASS command
   1.651 + * Accepts: pointer to command argument
   1.652 + * Returns: new state
   1.653 + */
   1.654 +
   1.655 +int pass_login (char *t,int argc,char *argv[])
   1.656 +{
   1.657 +  char tmp[MAILTMPLEN];
   1.658 +				/* flush old passowrd */
   1.659 +  if (pass) fs_give ((void **) &pass);
   1.660 +  if (!(t && *t)) {		/* if no password given */
   1.661 +    PSOUT ("-ERR Missing password argument\015\012");
   1.662 +    return AUTHORIZATION;
   1.663 +  }
   1.664 +  pass = cpystr (t);		/* copy password argument */
   1.665 +  if (!host) {			/* want remote mailbox? */
   1.666 +				/* no, delimit user from possible admin */
   1.667 +    if (t = strchr (user,'*')) *t++ ='\0';
   1.668 +				/* attempt the login */
   1.669 +    if (server_login (user,pass,t,argc,argv)) {
   1.670 +      int ret = mbxopen ("INBOX");
   1.671 +      if (ret == TRANSACTION)	/* mailbox opened OK? */
   1.672 +	syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s nmsgs=%lu/%lu",
   1.673 +		t ? "Admin " : "",user,tcp_clienthost (),nmsgs,stream->nmsgs);
   1.674 +      else syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s no mailbox",
   1.675 +		   t ? "Admin " : "",user,tcp_clienthost ());
   1.676 +      return ret;
   1.677 +    }
   1.678 +  }
   1.679 +#ifndef DISABLE_POP_PROXY
   1.680 +				/* remote; build remote INBOX */
   1.681 +  else if (anonymous_login (argc,argv)) {
   1.682 +    syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",host,
   1.683 +	    user,tcp_clienthost ());
   1.684 +    sprintf (tmp,"{%.128s/user=%.128s}INBOX",host,user);
   1.685 +				/* disable rimap just in case */
   1.686 +    mail_parameters (NIL,SET_RSHTIMEOUT,0);
   1.687 +    return mbxopen (tmp);
   1.688 +  }
   1.689 +#endif
   1.690 +				/* vague error message to confuse crackers */
   1.691 +  PSOUT ("-ERR Bad login\015\012");
   1.692 +  return AUTHORIZATION;
   1.693 +}
   1.694 +
   1.695 +/* Authentication responder
   1.696 + * Accepts: challenge
   1.697 + *	    length of challenge
   1.698 + *	    pointer to response length return location if non-NIL
   1.699 + * Returns: response
   1.700 + */
   1.701 +
   1.702 +#define RESPBUFLEN 8*MAILTMPLEN
   1.703 +
   1.704 +char *responder (void *challenge,unsigned long clen,unsigned long *rlen)
   1.705 +{
   1.706 +  unsigned long i,j;
   1.707 +  unsigned char *t,resp[RESPBUFLEN];
   1.708 +  char tmp[MAILTMPLEN];
   1.709 +  if (initial) {		/* initial response given? */
   1.710 +    if (clen) return NIL;	/* not permitted */
   1.711 +				/* set up response */
   1.712 +    t = (unsigned char *) initial;
   1.713 +    initial = NIL;		/* no more initial response */
   1.714 +    return (char *) rfc822_base64 (t,strlen ((char *) t),rlen ? rlen : &i);
   1.715 +  }
   1.716 +  PSOUT ("+ ");
   1.717 +  for (t = rfc822_binary (challenge,clen,&i),j = 0; j < i; j++)
   1.718 +    if (t[j] > ' ') PBOUT (t[j]);
   1.719 +  fs_give ((void **) &t);
   1.720 +  CRLF;
   1.721 +  PFLUSH ();			/* dump output buffer */
   1.722 +  resp[RESPBUFLEN-1] = '\0';	/* last buffer character is guaranteed NUL */
   1.723 +  alarm (LOGINTIMEOUT);		/* get a response under timeout */
   1.724 +  clearerr (stdin);		/* clear stdin errors */
   1.725 +				/* read buffer */
   1.726 +  while (!PSIN ((char *) resp,RESPBUFLEN)) {
   1.727 +				/* ignore if some interrupt */
   1.728 +    if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
   1.729 +    else {
   1.730 +      char *e = ferror (stdin) ?
   1.731 +	strerror (errno) : "Command stream end of file";
   1.732 +      alarm (0);		/* disable all interrupts */
   1.733 +      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
   1.734 +      sprintf (logout = tmp,"%.80s, while reading authentication",e);
   1.735 +      goodbye = NIL;
   1.736 +      state = LOGOUT;
   1.737 +      sayonara (1);
   1.738 +    }
   1.739 +  }
   1.740 +  if (!(t = (unsigned char *) strchr ((char *) resp,'\012'))) {
   1.741 +    int c;
   1.742 +    while ((c = PBIN ()) != '\012') if (c == EOF) {
   1.743 +				/* ignore if some interrupt */
   1.744 +      if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
   1.745 +      else {
   1.746 +	char *e = ferror (stdin) ?
   1.747 +	  strerror (errno) : "Command stream end of file";
   1.748 +	alarm (0);		/* disable all interrupts */
   1.749 +	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
   1.750 +	sprintf (logout = tmp,"%.80s, while reading auth char",e);
   1.751 +	goodbye = NIL;
   1.752 +	state = LOGOUT;
   1.753 +	sayonara (1);
   1.754 +      }
   1.755 +    }
   1.756 +    return NIL;
   1.757 +  }
   1.758 +  alarm (0);			/* make sure timeout disabled */
   1.759 +  if (t[-1] == '\015') --t;	/* remove CR */
   1.760 +  *t = '\0';			/* tie off buffer */
   1.761 +  return (resp[0] != '*') ?
   1.762 +    (char *) rfc822_base64 (resp,t-resp,rlen ? rlen : &i) : NIL;
   1.763 +}
   1.764 +
   1.765 +/* Select mailbox
   1.766 + * Accepts: mailbox name
   1.767 + * Returns: new state
   1.768 + */
   1.769 +
   1.770 +int mbxopen (char *mailbox)
   1.771 +{
   1.772 +  unsigned long i,j;
   1.773 +  char tmp[MAILTMPLEN];
   1.774 +  MESSAGECACHE *elt;
   1.775 +  if (msg) fs_give ((void **) &msg);
   1.776 +				/* open mailbox */
   1.777 +  if (!(stream = mail_open (stream,mailbox,NIL)))
   1.778 +    goodbye = "-ERR Unable to open user's INBOX\015\012";
   1.779 +  else if (stream->rdonly)	/* make sure not readonly */
   1.780 +    goodbye = "-ERR Can't get lock.  Mailbox in use\015\012";
   1.781 +  else {
   1.782 +    nmsgs = 0;			/* no messages yet */
   1.783 +    if (j = stream->nmsgs) {	/* if mailbox non-empty */
   1.784 +      sprintf (tmp,"1:%lu",j);	/* fetch fast information for all messages */
   1.785 +      mail_fetch_fast (stream,tmp,NIL);
   1.786 +    }
   1.787 +				/* create 1-origin tables */
   1.788 +    msg = (long *) fs_get (++j * sizeof (long));
   1.789 +    flags = (short *) fs_get (j * sizeof (short));
   1.790 +				/* build map */
   1.791 +    for (i = 1; i < j; ++i) if (!(elt = mail_elt (stream,i))->deleted) {
   1.792 +      msg[++nmsgs] = i;		/* note the presence of this message */
   1.793 +      if (elt->seen) il = nmsgs;/* and set up initial LAST */
   1.794 +    }
   1.795 +				/* make sure unused map entries are zero */
   1.796 +    for (i = nmsgs + 1; i < j; ++i) msg[i] = 0;
   1.797 +    rset ();			/* do implicit RSET */
   1.798 +    sprintf (tmp,"+OK Mailbox open, %lu messages\015\012",nmsgs);
   1.799 +    PSOUT (tmp);
   1.800 +    return TRANSACTION;
   1.801 +  }
   1.802 +  syslog (LOG_INFO,"Error opening or locking INBOX user=%.80s host=%.80s",
   1.803 +	  user,tcp_clienthost ());
   1.804 +  return UPDATE;
   1.805 +}
   1.806 +
   1.807 +/* Blat a string with dot checking
   1.808 + * Accepts: string
   1.809 + *	    maximum number of lines if greater than zero
   1.810 + *	    maximum number of bytes to output
   1.811 + *	    alternative stringstruct
   1.812 + * Returns: number of lines output
   1.813 + *
   1.814 + * This routine is uglier and kludgier than it should be, just to be robust
   1.815 + * in the case of a message which doesn't end in a newline.  Yes, this routine
   1.816 + * does truncate the last two bytes from the text.  Since it is normally a
   1.817 + * newline and the main routine adds it back, it usually does not make a
   1.818 + * difference.  But if it isn't, since the newline is required and the octet
   1.819 + * counts have to match, there's no choice but to truncate.
   1.820 + */
   1.821 +
   1.822 +long blat (char *text,long lines,unsigned long size,STRING *st)
   1.823 +{
   1.824 +  char c,d,e;
   1.825 +  long ret = 0;
   1.826 +				/* no-op if zero lines or empty string */
   1.827 +  if (!(lines && (size-- > 2))) return 0;
   1.828 +  if (text) {
   1.829 +    c = *text++; d = *text++;	/* collect first two bytes */
   1.830 +    if (c == '.') PBOUT ('.');	/* double string-leading dot if necessary */
   1.831 +    while (lines && --size) {	/* copy loop */
   1.832 +      e = *text++;		/* get next byte */
   1.833 +      PBOUT (c);		/* output character */
   1.834 +      if (c == '\012') {	/* end of line? */
   1.835 +	ret++; --lines;		/* count another line */
   1.836 +				/* double leading dot as necessary */
   1.837 +	if (lines && size && (d == '.')) PBOUT ('.');
   1.838 +      }
   1.839 +      c = d; d = e;		/* move to next character */
   1.840 +    }
   1.841 +  }
   1.842 +  else {
   1.843 +    c = SNX (st); d = SNX (st);	/* collect first two bytes */
   1.844 +    if (c == '.') PBOUT ('.');	/* double string-leading dot if necessary */
   1.845 +    while (lines && --size) {	/* copy loop */
   1.846 +      e = SNX (st);		/* get next byte */
   1.847 +      PBOUT (c);		/* output character */
   1.848 +      if (c == '\012') {	/* end of line? */
   1.849 +	ret++; --lines;		/* count another line */
   1.850 +				/* double leading dot as necessary */
   1.851 +	if (lines && size && (d == '.')) PBOUT ('.');
   1.852 +      }
   1.853 +      c = d; d = e;		/* move to next character */
   1.854 +    }
   1.855 +  }
   1.856 +  return ret;
   1.857 +}
   1.858 +
   1.859 +/* Reset mailbox
   1.860 + */
   1.861 +
   1.862 +void rset ()
   1.863 +{
   1.864 +				/* clear all flags */
   1.865 +  if (flags) memset ((void *) flags,0,(nmsgs + 1) * sizeof (short));
   1.866 +  ndele = nseen = 0;		/* no more deleted or seen messages */
   1.867 +  last = il;			/* restore previous LAST value */
   1.868 +}
   1.869 +
   1.870 +/* Co-routines from MAIL library */
   1.871 +
   1.872 +
   1.873 +/* Message matches a search
   1.874 + * Accepts: MAIL stream
   1.875 + *	    message number
   1.876 + */
   1.877 +
   1.878 +void mm_searched (MAILSTREAM *stream,unsigned long msgno)
   1.879 +{
   1.880 +  /* Never called */
   1.881 +}
   1.882 +
   1.883 +
   1.884 +/* Message exists (i.e. there are that many messages in the mailbox)
   1.885 + * Accepts: MAIL stream
   1.886 + *	    message number
   1.887 + */
   1.888 +
   1.889 +void mm_exists (MAILSTREAM *stream,unsigned long number)
   1.890 +{
   1.891 +  /* Can't use this mechanism.  POP has no means of notifying the client of
   1.892 +     new mail during the session. */
   1.893 +}
   1.894 +
   1.895 +
   1.896 +/* Message expunged
   1.897 + * Accepts: MAIL stream
   1.898 + *	    message number
   1.899 + */
   1.900 +
   1.901 +void mm_expunged (MAILSTREAM *stream,unsigned long number)
   1.902 +{
   1.903 +  unsigned long i = number + 1;
   1.904 +  msg[number] = 0;		/* I bet that this will annoy someone */
   1.905 +  while (i <= nmsgs) --msg[i++];
   1.906 +}
   1.907 +
   1.908 +
   1.909 +/* Message flag status change
   1.910 + * Accepts: MAIL stream
   1.911 + *	    message number
   1.912 + */
   1.913 +
   1.914 +void mm_flags (MAILSTREAM *stream,unsigned long number)
   1.915 +{
   1.916 +  /* This isn't used */
   1.917 +}
   1.918 +
   1.919 +
   1.920 +/* Mailbox found
   1.921 + * Accepts: MAIL stream
   1.922 + *	    hierarchy delimiter
   1.923 + *	    mailbox name
   1.924 + *	    mailbox attributes
   1.925 + */
   1.926 +
   1.927 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
   1.928 +{
   1.929 +  /* This isn't used */
   1.930 +}
   1.931 +
   1.932 +
   1.933 +/* Subscribe mailbox found
   1.934 + * Accepts: MAIL stream
   1.935 + *	    hierarchy delimiter
   1.936 + *	    mailbox name
   1.937 + *	    mailbox attributes
   1.938 + */
   1.939 +
   1.940 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
   1.941 +{
   1.942 +  /* This isn't used */
   1.943 +}
   1.944 +
   1.945 +
   1.946 +/* Mailbox status
   1.947 + * Accepts: MAIL stream
   1.948 + *	    mailbox name
   1.949 + *	    mailbox status
   1.950 + */
   1.951 +
   1.952 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
   1.953 +{
   1.954 +  /* This isn't used */
   1.955 +}
   1.956 +
   1.957 +/* Notification event
   1.958 + * Accepts: MAIL stream
   1.959 + *	    string to log
   1.960 + *	    error flag
   1.961 + */
   1.962 +
   1.963 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
   1.964 +{
   1.965 +  mm_log (string,errflg);	/* just do mm_log action */
   1.966 +}
   1.967 +
   1.968 +
   1.969 +/* Log an event for the user to see
   1.970 + * Accepts: string to log
   1.971 + *	    error flag
   1.972 + */
   1.973 +
   1.974 +void mm_log (char *string,long errflg)
   1.975 +{
   1.976 +  switch (errflg) {
   1.977 +  case NIL:			/* information message */
   1.978 +  case PARSE:			/* parse glitch */
   1.979 +    break;			/* too many of these to log */
   1.980 +  case WARN:			/* warning */
   1.981 +    syslog (LOG_DEBUG,"%s",string);
   1.982 +    break;
   1.983 +  case BYE:			/* driver broke connection */
   1.984 +    if (state != UPDATE) {
   1.985 +      char tmp[MAILTMPLEN];
   1.986 +      alarm (0);		/* disable all interrupts */
   1.987 +      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
   1.988 +      sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
   1.989 +      goodbye = NIL;
   1.990 +      state = LOGOUT;
   1.991 +      sayonara (1);
   1.992 +    }
   1.993 +    break;
   1.994 +  case ERROR:			/* error that broke command */
   1.995 +  default:			/* default should never happen */
   1.996 +    syslog (LOG_NOTICE,"%s",string);
   1.997 +    break;
   1.998 +  }
   1.999 +}    
  1.1000 +
  1.1001 +
  1.1002 +/* Log an event to debugging telemetry
  1.1003 + * Accepts: string to log
  1.1004 + */
  1.1005 +
  1.1006 +void mm_dlog (char *string)
  1.1007 +{
  1.1008 +  /* Not doing anything here for now */
  1.1009 +}
  1.1010 +
  1.1011 +
  1.1012 +/* Get user name and password for this host
  1.1013 + * Accepts: parse of network mailbox name
  1.1014 + *	    where to return user name
  1.1015 + *	    where to return password
  1.1016 + *	    trial count
  1.1017 + */
  1.1018 +
  1.1019 +void mm_login (NETMBX *mb,char *username,char *password,long trial)
  1.1020 +{
  1.1021 +				/* set user name */
  1.1022 +  strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
  1.1023 +  if (pass) {
  1.1024 +    strncpy (password,pass,255);/* and password */
  1.1025 +    fs_give ((void **) &pass);
  1.1026 +  }
  1.1027 +  else memset (password,0,256);	/* no password to send, abort login */
  1.1028 +  username[NETMAXUSER] = password[255] = '\0';
  1.1029 +}
  1.1030 +
  1.1031 +/* About to enter critical code
  1.1032 + * Accepts: stream
  1.1033 + */
  1.1034 +
  1.1035 +void mm_critical (MAILSTREAM *stream)
  1.1036 +{
  1.1037 +  ++critical;
  1.1038 +}
  1.1039 +
  1.1040 +
  1.1041 +/* About to exit critical code
  1.1042 + * Accepts: stream
  1.1043 + */
  1.1044 +
  1.1045 +void mm_nocritical (MAILSTREAM *stream)
  1.1046 +{
  1.1047 +  --critical;
  1.1048 +}
  1.1049 +
  1.1050 +
  1.1051 +/* Disk error found
  1.1052 + * Accepts: stream
  1.1053 + *	    system error code
  1.1054 + *	    flag indicating that mailbox may be clobbered
  1.1055 + * Returns: abort flag
  1.1056 + */
  1.1057 +
  1.1058 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
  1.1059 +{
  1.1060 +  if (serious) {		/* try your damnest if clobberage likely */
  1.1061 +    syslog (LOG_ALERT,
  1.1062 +	    "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
  1.1063 +	    user,tcp_clienthost (),
  1.1064 +	    (stream && stream->mailbox) ? stream->mailbox : "???",
  1.1065 +	    strerror (errcode));
  1.1066 +    alarm (0);			/* make damn sure timeout disabled */
  1.1067 +    sleep (60);			/* give it some time to clear up */
  1.1068 +    return NIL;
  1.1069 +  }
  1.1070 +  syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
  1.1071 +	  user,tcp_clienthost (),
  1.1072 +	  (stream && stream->mailbox) ? stream->mailbox : "???",
  1.1073 +	  strerror (errcode));
  1.1074 +  return T;
  1.1075 +}
  1.1076 +
  1.1077 +
  1.1078 +/* Log a fatal error event
  1.1079 + * Accepts: string to log
  1.1080 + */
  1.1081 +
  1.1082 +void mm_fatal (char *string)
  1.1083 +{
  1.1084 +  mm_log (string,ERROR);	/* shouldn't happen normally */
  1.1085 +}

UW-IMAP'd extensions by yuuji