mail.c   mail.c 
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/* /*
* Program: Mailbox Access routines * Program: Mailbox Access routines
* *
* Author: Mark Crispin * Author: Mark Crispin
* Networks and Distributed Computing * Networks and Distributed Computing
* Computing & Communications * Computing & Communications
* University of Washington * University of Washington
* Administration Building, AG-44 * Administration Building, AG-44
* Seattle, WA 98195 * Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU * Internet: MRC@CAC.Washington.EDU
* *
* Date: 22 November 1989 * Date: 22 November 1989
* Last Edited: 15 September 2005 * Last Edited: 30 August 2006
*
* The IMAP toolkit provided in this Distribution is
* Copyright 1988-2005 University of Washington.
* The full text of our legal notices is contained in the file called
* CPYRIGHT, included with this Distribution.
*/ */
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include "mail.h" #include "mail.h"
#include "osdep.h" #include "osdep.h"
#include <time.h> #include <time.h>
#include "misc.h" #include "misc.h"
#include "rfc822.h" #include "rfc822.h"
#include "utf8.h" #include "utf8.h"
#include "smtp.h" #include "smtp.h"
char *UW_copyright = "The IMAP toolkit provided in this Distribution is\nCo pyright 1988-2005 University of Washington.\nThe full text of our legal not ices is contained in the file called\nCPYRIGHT, included with this Distribu tion.\n"; char *UW_copyright = "Copyright 1988-2006 University of Washington\n\nLicen sed under the Apache License, Version 2.0 (the \"License\");\nyou may not u se this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n";
/* c-client global data */ /* c-client global data */
/* list of mail drivers */ /* list of mail drivers */
static DRIVER *maildrivers = NIL; static DRIVER *maildrivers = NIL;
/* list of authenticators */ /* list of authenticators */
static AUTHENTICATOR *mailauthenticators = NIL; static AUTHENTICATOR *mailauthenticators = NIL;
/* SSL driver pointer */ /* SSL driver pointer */
static NETDRIVER *mailssldriver = NIL; static NETDRIVER *mailssldriver = NIL;
/* pointer to alternate gets function */ /* pointer to alternate gets function */
static mailgets_t mailgets = NIL; static mailgets_t mailgets = NIL;
/* pointer to read progress function */ /* pointer to read progress function */
static readprogress_t mailreadprogress = NIL; static readprogress_t mailreadprogress = NIL;
/* mail cache manipulation function */ /* mail cache manipulation function */
static mailcache_t mailcache = mm_cache; static mailcache_t mailcache = mm_cache;
/* RFC-822 output generator */ /* RFC-822 output generator */
static rfc822out_t mail822out = NIL; static rfc822out_t mail822out = NIL;
/* RFC-822 output generator (new style) */
static rfc822outfull_t mail822outfull = NIL;
/* SMTP verbose callback */ /* SMTP verbose callback */
static smtpverbose_t mailsmtpverbose = mm_dlog; static smtpverbose_t mailsmtpverbose = mm_dlog;
/* proxy copy routine */ /* proxy copy routine */
static mailproxycopy_t mailproxycopy = NIL; static mailproxycopy_t mailproxycopy = NIL;
/* RFC-822 external line parse */ /* RFC-822 external line parse */
static parseline_t mailparseline = NIL; static parseline_t mailparseline = NIL;
/* RFC-822 external phrase parser */ /* RFC-822 external phrase parser */
static parsephrase_t mailparsephrase = NIL; static parsephrase_t mailparsephrase = NIL;
static kinit_t mailkinit = NIL; /* application kinit callback */
/* note network sent command */
static sendcommand_t mailsendcommand = NIL;
/* newsrc file name decision function */ /* newsrc file name decision function */
static newsrcquery_t mailnewsrcquery = NIL; static newsrcquery_t mailnewsrcquery = NIL;
/* ACL results callback */ /* ACL results callback */
static getacl_t mailaclresults = NIL; static getacl_t mailaclresults = NIL;
/* list rights results callback */ /* list rights results callback */
static listrights_t maillistrightsresults = NIL; static listrights_t maillistrightsresults = NIL;
/* my rights results callback */ /* my rights results callback */
static myrights_t mailmyrightsresults = NIL; static myrights_t mailmyrightsresults = NIL;
/* quota results callback */ /* quota results callback */
static quota_t mailquotaresults = NIL; static quota_t mailquotaresults = NIL;
/* quota root results callback */ /* quota root results callback */
static quotaroot_t mailquotarootresults = NIL; static quotaroot_t mailquotarootresults = NIL;
/* sorted results callback */ /* sorted results callback */
static sortresults_t mailsortresults = NIL; static sortresults_t mailsortresults = NIL;
/* threaded results callback */ /* threaded results callback */
static threadresults_t mailthreadresults = NIL; static threadresults_t mailthreadresults = NIL;
/* COPY UID results */
static copyuid_t mailcopyuid = NIL;
/* APPEND UID results */
static appenduid_t mailappenduid = NIL;
/* free elt extra stuff callback */ /* free elt extra stuff callback */
static freeeltsparep_t mailfreeeltsparep = NIL; static freeeltsparep_t mailfreeeltsparep = NIL;
/* free envelope extra stuff callback */ /* free envelope extra stuff callback */
static freeenvelopesparep_t mailfreeenvelopesparep = NIL; static freeenvelopesparep_t mailfreeenvelopesparep = NIL;
/* free body extra stuff callback */ /* free body extra stuff callback */
static freebodysparep_t mailfreebodysparep = NIL; static freebodysparep_t mailfreebodysparep = NIL;
/* free stream extra stuff callback */ /* free stream extra stuff callback */
static freestreamsparep_t mailfreestreamsparep = NIL; static freestreamsparep_t mailfreestreamsparep = NIL;
/* SSL start routine */ /* SSL start routine */
static sslstart_t mailsslstart = NIL; static sslstart_t mailsslstart = NIL;
/* SSL certificate query */ /* SSL certificate query */
static sslcertificatequery_t mailsslcertificatequery = NIL; static sslcertificatequery_t mailsslcertificatequery = NIL;
/* SSL client certificate */
static sslclientcert_t mailsslclientcert = NIL;
/* SSL client private key */
static sslclientkey_t mailsslclientkey = NIL;
/* SSL failure notify */ /* SSL failure notify */
static sslfailure_t mailsslfailure = NIL; static sslfailure_t mailsslfailure = NIL;
static kinit_t mailkinit = NIL; /* application kinit callback */
/* snarf interval */ /* snarf interval */
static long mailsnarfinterval = 60; static long mailsnarfinterval = 60;
/* snarf preservation */ /* snarf preservation */
static long mailsnarfpreserve = NIL; static long mailsnarfpreserve = NIL;
/* newsrc name uses canonical host */ /* newsrc name uses canonical host */
static long mailnewsrccanon = LONGT; static long mailnewsrccanon = LONGT;
/* note network sent command */
static sendcommand_t mailsendcommand = NIL;
/* supported threaders */ /* supported threaders */
static THREADER mailthreadordsub = { static THREADER mailthreadordsub = {
"ORDEREDSUBJECT",mail_thread_orderedsubject,NIL "ORDEREDSUBJECT",mail_thread_orderedsubject,NIL
}; };
static THREADER mailthreadlist = { static THREADER mailthreadlist = {
"REFERENCES",mail_thread_references,&mailthreadordsub "REFERENCES",mail_thread_references,&mailthreadordsub
}; };
/* server name */ /* server name */
static char *servicename = "unknown"; static char *servicename = "unknown";
/* server externally-set authentication ID *
/
static char *externalauthid = NIL;
static int expungeatping = T; /* mail_ping() may call mm_expunged() */ static int expungeatping = T; /* mail_ping() may call mm_expunged() */
static int trysslfirst = NIL; /* always try SSL first */ static int trysslfirst = NIL; /* always try SSL first */
static int notimezones = NIL; /* write timezones in "From " header */ static int notimezones = NIL; /* write timezones in "From " header */
static int trustdns = T; /* do DNS canonicalization */ static int trustdns = T; /* do DNS canonicalization */
static int saslusesptrname = T; /* SASL uses name from DNS PTR looku p */ static int saslusesptrname = T; /* SASL uses name from DNS PTR looku p */
/* trustdns also must be set */ /* trustdns also must be set */
static int debugsensitive = NIL;/* debug telemetry includes sensitive data */ static int debugsensitive = NIL;/* debug telemetry includes sensitive data */
/* Default mail cache handler /* Default mail cache handler
* Accepts: pointer to cache handle * Accepts: pointer to cache handle
* message number * message number
skipping to change at line 180 skipping to change at line 200
case CH_FREESORTCACHE: case CH_FREESORTCACHE:
if (stream->sc[msgno - 1]) { if (stream->sc[msgno - 1]) {
if (stream->sc[msgno - 1]->from) if (stream->sc[msgno - 1]->from)
fs_give ((void **) &stream->sc[msgno - 1]->from); fs_give ((void **) &stream->sc[msgno - 1]->from);
if (stream->sc[msgno - 1]->to) if (stream->sc[msgno - 1]->to)
fs_give ((void **) &stream->sc[msgno - 1]->to); fs_give ((void **) &stream->sc[msgno - 1]->to);
if (stream->sc[msgno - 1]->cc) if (stream->sc[msgno - 1]->cc)
fs_give ((void **) &stream->sc[msgno - 1]->cc); fs_give ((void **) &stream->sc[msgno - 1]->cc);
if (stream->sc[msgno - 1]->subject) if (stream->sc[msgno - 1]->subject)
fs_give ((void **) &stream->sc[msgno - 1]->subject); fs_give ((void **) &stream->sc[msgno - 1]->subject);
if (stream->sc[msgno - 1]->original_subject)
fs_give ((void **) &stream->sc[msgno - 1]->original_subject);
if (stream->sc[msgno - 1]->unique && if (stream->sc[msgno - 1]->unique &&
(stream->sc[msgno - 1]->unique != stream->sc[msgno - 1]->message_i d)) (stream->sc[msgno - 1]->unique != stream->sc[msgno - 1]->message_i d))
fs_give ((void **) &stream->sc[msgno - 1]->unique); fs_give ((void **) &stream->sc[msgno - 1]->unique);
if (stream->sc[msgno - 1]->message_id) if (stream->sc[msgno - 1]->message_id)
fs_give ((void **) &stream->sc[msgno - 1]->message_id); fs_give ((void **) &stream->sc[msgno - 1]->message_id);
if (stream->sc[msgno - 1]->references) if (stream->sc[msgno - 1]->references)
mail_free_stringlist (&stream->sc[msgno - 1]->references); mail_free_stringlist (&stream->sc[msgno - 1]->references);
fs_give ((void **) &stream->sc[msgno - 1]); fs_give ((void **) &stream->sc[msgno - 1]);
} }
break; break;
skipping to change at line 323 skipping to change at line 341
case GET_NEWSRC: /* use stream dtb instead of environment */ case GET_NEWSRC: /* use stream dtb instead of environment */
ret = (stream && stream->dtb) ? ret = (stream && stream->dtb) ?
/* KLUDGE ALERT: note stream passed as value */ /* KLUDGE ALERT: note stream passed as value */
(*stream->dtb->parameters) (function,stream) : (*stream->dtb->parameters) (function,stream) :
env_parameters (function,value); env_parameters (function,value);
break; break;
case ENABLE_DEBUG: case ENABLE_DEBUG:
fatal ("ENABLE_DEBUG not permitted"); fatal ("ENABLE_DEBUG not permitted");
case DISABLE_DEBUG: case DISABLE_DEBUG:
fatal ("DISABLE_DEBUG not permitted"); fatal ("DISABLE_DEBUG not permitted");
case SET_DIRFMTTEST:
fatal ("SET_DIRFMTTEST not permitted");
case GET_DIRFMTTEST:
if (!(stream && (ret = (*stream->dtb->parameters) (function,NIL))))
fatal ("GET_DIRFMTTEST not permitted");
break;
case SET_DRIVERS: case SET_DRIVERS:
fatal ("SET_DRIVERS not permitted"); fatal ("SET_DRIVERS not permitted");
case GET_DRIVERS: /* always return global */ case GET_DRIVERS: /* always return global */
ret = (void *) maildrivers; ret = (void *) maildrivers;
break; break;
case SET_DRIVER: case SET_DRIVER:
fatal ("SET_DRIVER not permitted"); fatal ("SET_DRIVER not permitted");
case GET_DRIVER: case GET_DRIVER:
for (d = maildrivers; d && compare_cstring (d->name,(char *) value); for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
d = d->next); d = d->next);
skipping to change at line 345 skipping to change at line 369
case ENABLE_DRIVER: case ENABLE_DRIVER:
for (d = maildrivers; d && compare_cstring (d->name,(char *) value); for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
d = d->next); d = d->next);
if (ret = (void *) d) d->flags &= ~DR_DISABLE; if (ret = (void *) d) d->flags &= ~DR_DISABLE;
break; break;
case DISABLE_DRIVER: case DISABLE_DRIVER:
for (d = maildrivers; d && compare_cstring (d->name,(char *) value); for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
d = d->next); d = d->next);
if (ret = (void *) d) d->flags |= DR_DISABLE; if (ret = (void *) d) d->flags |= DR_DISABLE;
break; break;
case ENABLE_AUTHENTICATOR: /* punt on this for the nonce */ case ENABLE_AUTHENTICATOR:
fatal ("ENABLE_AUTHENTICATOR not permitted"); for (a = mailauthenticators;/* scan authenticators */
a && compare_cstring (a->name,(char *) value); a = a->next);
if (ret = (void *) a) a->flags &= ~AU_DISABLE;
break;
case DISABLE_AUTHENTICATOR: case DISABLE_AUTHENTICATOR:
for (a = mailauthenticators;/* scan authenticators */ for (a = mailauthenticators;/* scan authenticators */
a && compare_cstring (a->name,(char *) value); a = a->next); a && compare_cstring (a->name,(char *) value); a = a->next);
if (a) { /* if authenticator name found */ if (ret = (void *) a) a->flags |= AU_DISABLE;
a->client = NIL; /* blow it away */ break;
a->server = NIL; case UNHIDE_AUTHENTICATOR:
ret = (void *) a; for (a = mailauthenticators;/* scan authenticators */
a && compare_cstring (a->name,(char *) value); a = a->next);
if (ret = (void *) a) a->flags &= ~AU_HIDE;
break;
case HIDE_AUTHENTICATOR:
for (a = mailauthenticators;/* scan authenticators */
a && compare_cstring (a->name,(char *) value); a = a->next);
if (ret = (void *) a) a->flags |= AU_HIDE;
break;
case SET_EXTERNALAUTHID:
if (value) { /* setting external authentication ID */
externalauthid = cpystr ((char *) value);
mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"EXTERNAL");
}
else { /* clearing external authentication ID */
if (externalauthid) fs_give ((void **) &externalauthid);
mail_parameters (NIL,HIDE_AUTHENTICATOR,"EXTERNAL");
} }
case GET_EXTERNALAUTHID:
ret = (void *) externalauthid;
break; break;
case SET_GETS: case SET_GETS:
mailgets = (mailgets_t) value; mailgets = (mailgets_t) value;
case GET_GETS: case GET_GETS:
ret = (void *) mailgets; ret = (void *) mailgets;
break; break;
case SET_READPROGRESS: case SET_READPROGRESS:
mailreadprogress = (readprogress_t) value; mailreadprogress = (readprogress_t) value;
case GET_READPROGRESS: case GET_READPROGRESS:
ret = (void *) mailreadprogress; ret = (void *) mailreadprogress;
skipping to change at line 376 skipping to change at line 421
case SET_CACHE: case SET_CACHE:
mailcache = (mailcache_t) value; mailcache = (mailcache_t) value;
case GET_CACHE: case GET_CACHE:
ret = (void *) mailcache; ret = (void *) mailcache;
break; break;
case SET_RFC822OUTPUT: case SET_RFC822OUTPUT:
mail822out = (rfc822out_t) value; mail822out = (rfc822out_t) value;
case GET_RFC822OUTPUT: case GET_RFC822OUTPUT:
ret = (void *) mail822out; ret = (void *) mail822out;
break; break;
case SET_RFC822OUTPUTFULL:
mail822outfull = (rfc822outfull_t) value;
case GET_RFC822OUTPUTFULL:
ret = (void *) mail822outfull;
break;
case SET_SMTPVERBOSE: case SET_SMTPVERBOSE:
mailsmtpverbose = (smtpverbose_t) value; mailsmtpverbose = (smtpverbose_t) value;
case GET_SMTPVERBOSE: case GET_SMTPVERBOSE:
ret = (void *) mailsmtpverbose; ret = (void *) mailsmtpverbose;
break; break;
case SET_MAILPROXYCOPY: case SET_MAILPROXYCOPY:
mailproxycopy = (mailproxycopy_t) value; mailproxycopy = (mailproxycopy_t) value;
case GET_MAILPROXYCOPY: case GET_MAILPROXYCOPY:
ret = (void *) mailproxycopy; ret = (void *) mailproxycopy;
break; break;
skipping to change at line 406 skipping to change at line 456
case SET_NEWSRCQUERY: case SET_NEWSRCQUERY:
mailnewsrcquery = (newsrcquery_t) value; mailnewsrcquery = (newsrcquery_t) value;
case GET_NEWSRCQUERY: case GET_NEWSRCQUERY:
ret = (void *) mailnewsrcquery; ret = (void *) mailnewsrcquery;
break; break;
case SET_NEWSRCCANONHOST: case SET_NEWSRCCANONHOST:
mailnewsrccanon = (long) value; mailnewsrccanon = (long) value;
case GET_NEWSRCCANONHOST: case GET_NEWSRCCANONHOST:
ret = (void *) mailnewsrccanon; ret = (void *) mailnewsrccanon;
break; break;
case SET_COPYUID:
mailcopyuid = (copyuid_t) value;
case GET_COPYUID:
ret = (void *) mailcopyuid;
break;
case SET_APPENDUID:
mailappenduid = (appenduid_t) value;
case GET_APPENDUID:
ret = (void *) mailappenduid;
break;
case SET_FREEENVELOPESPAREP: case SET_FREEENVELOPESPAREP:
mailfreeenvelopesparep = (freeenvelopesparep_t) value; mailfreeenvelopesparep = (freeenvelopesparep_t) value;
case GET_FREEENVELOPESPAREP: case GET_FREEENVELOPESPAREP:
ret = (void *) mailfreeenvelopesparep; ret = (void *) mailfreeenvelopesparep;
break; break;
case SET_FREEELTSPAREP: case SET_FREEELTSPAREP:
mailfreeeltsparep = (freeeltsparep_t) value; mailfreeeltsparep = (freeeltsparep_t) value;
case GET_FREEELTSPAREP: case GET_FREEELTSPAREP:
ret = (void *) mailfreeeltsparep; ret = (void *) mailfreeeltsparep;
break; break;
skipping to change at line 436 skipping to change at line 496
case SET_SSLSTART: case SET_SSLSTART:
mailsslstart = (sslstart_t) value; mailsslstart = (sslstart_t) value;
case GET_SSLSTART: case GET_SSLSTART:
ret = (void *) mailsslstart; ret = (void *) mailsslstart;
break; break;
case SET_SSLCERTIFICATEQUERY: case SET_SSLCERTIFICATEQUERY:
mailsslcertificatequery = (sslcertificatequery_t) value; mailsslcertificatequery = (sslcertificatequery_t) value;
case GET_SSLCERTIFICATEQUERY: case GET_SSLCERTIFICATEQUERY:
ret = (void *) mailsslcertificatequery; ret = (void *) mailsslcertificatequery;
break; break;
case SET_SSLCLIENTCERT:
mailsslclientcert = (sslclientcert_t) value;
case GET_SSLCLIENTCERT:
ret = (void *) mailsslclientcert;
break;
case SET_SSLCLIENTKEY:
mailsslclientkey = (sslclientkey_t) value;
case GET_SSLCLIENTKEY:
ret = (void *) mailsslclientkey;
break;
case SET_SSLFAILURE: case SET_SSLFAILURE:
mailsslfailure = (sslfailure_t) value; mailsslfailure = (sslfailure_t) value;
case GET_SSLFAILURE: case GET_SSLFAILURE:
ret = (void *) mailsslfailure; ret = (void *) mailsslfailure;
break; break;
case SET_KINIT: case SET_KINIT:
mailkinit = (kinit_t) value; mailkinit = (kinit_t) value;
case GET_KINIT: case GET_KINIT:
ret = (void *) mailkinit; ret = (void *) mailkinit;
break; break;
skipping to change at line 704 skipping to change at line 774
!*mb->authuser) strcpy (mb->authuser,v); !*mb->authuser) strcpy (mb->authuser,v);
else return NIL; else return NIL;
} }
else { /* non-argument switch */ else { /* non-argument switch */
if (!compare_cstring (s,"anonymous")) mb->anoflag = T; if (!compare_cstring (s,"anonymous")) mb->anoflag = T;
else if (!compare_cstring (s,"debug")) mb->dbgflag = T; else if (!compare_cstring (s,"debug")) mb->dbgflag = T;
else if (!compare_cstring (s,"readonly")) mb->readonlyflag = T; else if (!compare_cstring (s,"readonly")) mb->readonlyflag = T;
else if (!compare_cstring (s,"secure")) mb->secflag = T; else if (!compare_cstring (s,"secure")) mb->secflag = T;
else if (!compare_cstring (s,"norsh")) mb->norsh = T; else if (!compare_cstring (s,"norsh")) mb->norsh = T;
else if (!compare_cstring (s,"loser")) mb->loser = T; else if (!compare_cstring (s,"loser")) mb->loser = T;
else if (!compare_cstring (s,"tls") && !mb->notlsflag) mb->tlsflag = else if (!compare_cstring (s,"tls") && !mb->notlsflag)
T; mb->tlsflag = T;
else if (!compare_cstring (s,"tls-sslv23") && !mb->notlsflag)
mb->tlssslv23 = mb->tlsflag = T;
else if (!compare_cstring (s,"notls") && !mb->tlsflag) else if (!compare_cstring (s,"notls") && !mb->tlsflag)
mb->notlsflag = T; mb->notlsflag = T;
else if (!compare_cstring (s,"tryssl")) else if (!compare_cstring (s,"tryssl"))
mb->trysslflag = mailssldriver? T : NIL; mb->trysslflag = mailssldriver? T : NIL;
else if (mailssldriver && !compare_cstring (s,"ssl")) mb->sslflag = else if (mailssldriver && !compare_cstring (s,"ssl") && !mb->tlsflag
T; )
mb->sslflag = mb->notlsflag = T;
else if (mailssldriver && !compare_cstring (s,"novalidate-cert")) else if (mailssldriver && !compare_cstring (s,"novalidate-cert"))
mb->novalidate = T; mb->novalidate = T;
/* hack for compatibility with the past */ /* hack for compatibility with the past */
else if (mailssldriver && !compare_cstring (s,"validate-cert")); else if (mailssldriver && !compare_cstring (s,"validate-cert"));
/* service switches below here */ /* service switches below here */
else if (*mb->service) return NIL; else if (*mb->service) return NIL;
else if (!compare_cstring (s,"imap") || else if (!compare_cstring (s,"imap") ||
!compare_cstring (s,"nntp") || !compare_cstring (s,"nntp") ||
!compare_cstring (s,"pop3") || !compare_cstring (s,"pop3") ||
!compare_cstring (s,"smtp") || !compare_cstring (s,"smtp") ||
skipping to change at line 1126 skipping to change at line 1200
if (d) return (*d->open) (NIL); if (d) return (*d->open) (NIL);
sprintf (tmp,"Can't resolve mailbox %.80s: unknown driver",name); sprintf (tmp,"Can't resolve mailbox %.80s: unknown driver",name);
MM_LOG (tmp,ERROR); MM_LOG (tmp,ERROR);
return mail_close (stream); return mail_close (stream);
} }
/* fall through to default case */ /* fall through to default case */
default: /* not special hack (but could be # name */ default: /* not special hack (but could be # name */
d = mail_valid (NIL,name,(options & OP_SILENT) ? d = mail_valid (NIL,name,(options & OP_SILENT) ?
(char *) NIL : "open mailbox"); (char *) NIL : "open mailbox");
} }
if (d) { /* must have a factory */ return d ? mail_open_work (d,stream,name,options) : stream;
char *oname = cpystr (name); }
if (options & OP_PROTOTYPE) return (*d->open) (NIL); /* Mail open worker routine
if (stream) { /* recycling requested? */ * Accepts: factory
if ((stream->dtb == d) && (d->flags & DR_RECYCLE) && * candidate stream for recycling
((d->flags & DR_HALFOPEN) || !(options & OP_HALFOPEN)) && * mailbox name
mail_usable_network_stream (stream,name)) { * open options
* Returns: stream to use on success, NIL on failure
*/
MAILSTREAM *mail_open_work (DRIVER *d,MAILSTREAM *stream,char *name,
long options)
{
int i;
char tmp[MAILTMPLEN];
NETMBX mb;
if (options & OP_PROTOTYPE) return (*d->open) (NIL);
/* name is copied here in case the caller does a re-open using
* stream->mailbox or stream->original_mailbox as the argument.
*/
name = cpystr (name); /* make copy of name */
if (stream) { /* recycling requested? */
if ((stream->dtb == d) && (d->flags & DR_RECYCLE) &&
((d->flags & DR_HALFOPEN) || !(options & OP_HALFOPEN)) &&
mail_usable_network_stream (stream,name)) {
/* yes, checkpoint if needed */ /* yes, checkpoint if needed */
if (d->flags & DR_XPOINT) mail_check (stream); if (d->flags & DR_XPOINT) mail_check (stream);
mail_free_cache(stream);/* clean up stream */ mail_free_cache (stream); /* clean up stream */
if (stream->mailbox) fs_give ((void **) &stream->mailbox); if (stream->mailbox) fs_give ((void **) &stream->mailbox);
if (stream->original_mailbox) if (stream->original_mailbox)
fs_give ((void **) &stream->original_mailbox); fs_give ((void **) &stream->original_mailbox);
/* flush user flags */ /* flush user flags */
for (i = 0; i < NUSERFLAGS; i++) for (i = 0; i < NUSERFLAGS; i++)
if (stream->user_flags[i]) fs_give ((void **)&stream->user_flags[i if (stream->user_flags[i]) fs_give ((void **) &stream->user_flags[i]
]); );
}
else { /* stream not recycleable, babble if net */
if (!stream->silent && stream->dtb && !(stream->dtb->flags&DR_LOCAL)
&&
mail_valid_net_parse (stream->mailbox,&mb)) {
sprintf (tmp,"Closing connection to %.80s",mb.host);
MM_LOG (tmp,(long) NIL);
} }
else { /* stream not recycleable, babble if net */
if (!stream->silent && stream->dtb && !(stream->dtb->flags&DR_LOCAL)
&&
mail_valid_net_parse (stream->mailbox,&mb)) {
sprintf (tmp,"Closing connection to %.80s",mb.host);
MM_LOG (tmp,(long) NIL);
}
/* flush the old stream */ /* flush the old stream */
stream = mail_close (stream); stream = mail_close (stream);
}
} }
}
/* check if driver does not support halfopen */ /* check if driver does not support halfopen */
else if ((options & OP_HALFOPEN) && !(d->flags & DR_HALFOPEN)) { else if ((options & OP_HALFOPEN) && !(d->flags & DR_HALFOPEN)) {
fs_give ((void **) &oname); fs_give ((void **) &name);
return NIL; return NIL;
} }
/* instantiate new stream if not recycling * / /* instantiate new stream if not recycling * /
if (!stream) (*mailcache) (stream = (MAILSTREAM *) if (!stream) (*mailcache) (stream = (MAILSTREAM *)
memset (fs_get (sizeof (MAILSTREAM)),0, memset (fs_get (sizeof (MAILSTREAM)),0,
sizeof (MAILSTREAM)),(long) 0,CH_INIT sizeof (MAILSTREAM)),(long) 0,CH_INIT);
); stream->dtb = d; /* set dispatch */
stream->dtb = d; /* set dispatch */
/* set mailbox name */ /* set mailbox name */
stream->mailbox = cpystr (stream->original_mailbox = oname); stream->mailbox = cpystr (stream->original_mailbox = name);
/* initialize stream flags */ /* initialize stream flags */
stream->inbox = stream->lock = NIL; stream->inbox = stream->lock = NIL;
stream->debug = (options & OP_DEBUG) ? T : NIL; stream->debug = (options & OP_DEBUG) ? T : NIL;
stream->rdonly = (options & OP_READONLY) ? T : NIL; stream->rdonly = (options & OP_READONLY) ? T : NIL;
stream->anonymous = (options & OP_ANONYMOUS) ? T : NIL; stream->anonymous = (options & OP_ANONYMOUS) ? T : NIL;
stream->scache = (options & OP_SHORTCACHE) ? T : NIL; stream->scache = (options & OP_SHORTCACHE) ? T : NIL;
stream->silent = (options & OP_SILENT) ? T : NIL; stream->silent = (options & OP_SILENT) ? T : NIL;
stream->halfopen = (options & OP_HALFOPEN) ? T : NIL; stream->halfopen = (options & OP_HALFOPEN) ? T : NIL;
stream->secure = (options & OP_SECURE) ? T : NIL; stream->secure = (options & OP_SECURE) ? T : NIL;
stream->tryssl = (options & OP_TRYSSL) ? T : NIL; stream->tryssl = (options & OP_TRYSSL) ? T : NIL;
stream->mulnewsrc = (options & OP_MULNEWSRC) ? T : NIL; stream->mulnewsrc = (options & OP_MULNEWSRC) ? T : NIL;
stream->perm_seen = stream->perm_deleted = stream->perm_flagged = stream->nokod = (options & OP_NOKOD) ? T : NIL;
stream->perm_answered = stream->perm_draft = stream->kwd_create = NIL stream->sniff = (options & OP_SNIFF) ? T : NIL;
; stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
stream->uid_nosticky = (d->flags & DR_NOSTICKY) ? T : NIL; stream->perm_answered = stream->perm_draft = stream->kwd_create = NIL;
stream->uid_last = 0; /* default UID validity */ stream->uid_nosticky = (d->flags & DR_NOSTICKY) ? T : NIL;
stream->uid_validity = time (0); stream->uid_last = 0; /* default UID validity */
stream->uid_validity = (unsigned long) time (0);
/* have driver open, flush if failed */ /* have driver open, flush if failed */
if (!(*d->open) (stream)) stream = mail_close (stream); return ((*d->open) (stream)) ? stream : mail_close (stream);
}
return stream; /* return the stream */
} }
/* Mail close /* Mail close
* Accepts: mail stream * Accepts: mail stream
* close options * close options
* Returns: NIL, always * Returns: NIL, always
*/ */
MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options) MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options)
{ {
int i; int i;
skipping to change at line 1641 skipping to change at line 1733
unsigned long *len,long flags) unsigned long *len,long flags)
{ {
GETS_DATA md; GETS_DATA md;
PARTTEXT *p; PARTTEXT *p;
STRING bs; STRING bs;
MESSAGECACHE *elt; MESSAGECACHE *elt;
BODY *b = NIL; BODY *b = NIL;
char tmp[MAILTMPLEN]; char tmp[MAILTMPLEN];
unsigned long i; unsigned long i;
if (len) *len = 0; /* default return size */ if (len) *len = 0; /* default return size */
memset (&stream->private.string,NIL,sizeof (STRING));
if (section && (strlen (section) > (MAILTMPLEN - 20))) return ""; if (section && (strlen (section) > (MAILTMPLEN - 20))) return "";
if (flags & FT_UID) { /* UID form of call */ if (flags & FT_UID) { /* UID form of call */
if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID; if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
else return ""; /* must get UID/msgno map first */ else return ""; /* must get UID/msgno map first */
} }
elt = mail_elt (stream,msgno);/* get cache data */ elt = mail_elt (stream,msgno);/* get cache data */
if (section && *section) { /* nested body text wanted? */ if (section && *section) { /* nested body text wanted? */
if (!((b = mail_body (stream,msgno,section)) && if (!((b = mail_body (stream,msgno,section)) &&
(b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822"))) (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822")))
return ""; /* lose if no body or not MESSAGE/RFC822 */ return ""; /* lose if no body or not MESSAGE/RFC822 */
skipping to change at line 1676 skipping to change at line 1769
if (!stream->dtb) return ""; /* not in cache, must have live driver */ if (!stream->dtb) return ""; /* not in cache, must have live driver */
if (stream->dtb->msgdata) return if (stream->dtb->msgdata) return
((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,NIL,flags) && p->text.da ta)? ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,NIL,flags) && p->text.da ta)?
mail_fetch_text_return (&md,&p->text,len) : ""; mail_fetch_text_return (&md,&p->text,len) : "";
if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return ""; if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return "";
if (section && *section) { /* nested is more complex */ if (section && *section) { /* nested is more complex */
SETPOS (&bs,p->offset); SETPOS (&bs,p->offset);
i = p->text.size; /* just want this much */ i = p->text.size; /* just want this much */
} }
else i = SIZE (&bs); /* want entire text */ else i = SIZE (&bs); /* want entire text */
return mail_fetch_string_return (&md,&bs,i,len); return mail_fetch_string_return (&md,&bs,i,len,flags);
} }
/* Mail fetch message body part MIME headers /* Mail fetch message body part MIME headers
* Accepts: mail stream * Accepts: mail stream
* message # to fetch * message # to fetch
* MIME section specifier (#.#.#...#) * MIME section specifier (#.#.#...#)
* pointer to returned length * pointer to returned length
* flags * flags
* Returns: message text * Returns: message text
*/ */
skipping to change at line 1757 skipping to change at line 1850
char *mail_fetch_body (MAILSTREAM *stream,unsigned long msgno,char *section , char *mail_fetch_body (MAILSTREAM *stream,unsigned long msgno,char *section ,
unsigned long *len,long flags) unsigned long *len,long flags)
{ {
GETS_DATA md; GETS_DATA md;
PARTTEXT *p; PARTTEXT *p;
STRING bs; STRING bs;
BODY *b; BODY *b;
SIZEDTEXT *t; SIZEDTEXT *t;
char *s,tmp[MAILTMPLEN]; char *s,tmp[MAILTMPLEN];
memset (&stream->private.string,NIL,sizeof (STRING));
if (!(section && *section)) /* top-level text wanted? */ if (!(section && *section)) /* top-level text wanted? */
return mail_fetch_message (stream,msgno,len,flags); return mail_fetch_message (stream,msgno,len,flags);
else if (strlen (section) > (MAILTMPLEN - 20)) return ""; else if (strlen (section) > (MAILTMPLEN - 20)) return "";
flags &= ~FT_INTERNAL; /* can't win with this set */ flags &= ~FT_INTERNAL; /* can't win with this set */
/* initialize message data identifier */ /* initialize message data identifier */
INIT_GETS (md,stream,msgno,section,0,0); INIT_GETS (md,stream,msgno,section,0,0);
/* kludge for old section 0 header */ /* kludge for old section 0 header */
if (!strcmp (s = strcpy (tmp,section),"0") || if (!strcmp (s = strcpy (tmp,section),"0") ||
((s = strstr (tmp,".0")) && !s[2])) { ((s = strstr (tmp,".0")) && !s[2])) {
SIZEDTEXT ht; SIZEDTEXT ht;
skipping to change at line 1810 skipping to change at line 1904
return stream->private.search.text + p->offset; return stream->private.search.text + p->offset;
if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) { if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) {
if (len) *len = 0; if (len) *len = 0;
return ""; return "";
} }
if (bs.dtb->next == mail_string_next) { if (bs.dtb->next == mail_string_next) {
if (stream->private.search.string) stream->private.search.text = bs.cur pos; if (stream->private.search.string) stream->private.search.text = bs.cur pos;
return bs.curpos + p->offset; return bs.curpos + p->offset;
} }
SETPOS (&bs,p->offset); SETPOS (&bs,p->offset);
return mail_fetch_string_return (&md,&bs,t->size,len); return mail_fetch_string_return (&md,&bs,t->size,len,flags);
} }
/* Mail fetch partial message text /* Mail fetch partial message text
* Accepts: mail stream * Accepts: mail stream
* message # to fetch * message # to fetch
* MIME section specifier (#.#.#...#) * MIME section specifier (#.#.#...#)
* offset of first designed byte or 0 to start at beginning * offset of first designed byte or 0 to start at beginning
* maximum number of bytes or 0 for all bytes * maximum number of bytes or 0 for all bytes
* flags * flags
* Returns: T if successful, else NIL * Returns: T if successful, else NIL
*/ */
skipping to change at line 1963 skipping to change at line 2057
return (*mailgets) (mail_read,&bs,t->size,md); return (*mailgets) (mail_read,&bs,t->size,md);
} }
return t->size ? (char *) t->data : ""; return t->size ? (char *) t->data : "";
} }
/* Mail return message string /* Mail return message string
* Accepts: identifier data * Accepts: identifier data
* stringstruct * stringstruct
* text length * text length
* pointer to returned length * pointer to returned length
* Returns: text * flags
* Returns: text, or NIL if stringstruct returned
*/ */
char *mail_fetch_string_return (GETS_DATA *md,STRING *bs,unsigned long i, char *mail_fetch_string_return (GETS_DATA *md,STRING *bs,unsigned long i,
unsigned long *len) unsigned long *len,long flags)
{ {
char *ret = NIL;
if (len) *len = i; /* return size */ if (len) *len = i; /* return size */
/* return stringstruct hack */
if (flags & FT_RETURNSTRINGSTRUCT) {
memcpy (&md->stream->private.string,bs,sizeof (STRING));
SETPOS (&md->stream->private.string,GETPOS (&md->stream->private.string
));
}
/* have to do the mailgets thing? */ /* have to do the mailgets thing? */
if (mailgets) return (*mailgets) (mail_read,bs,i,md); else if (mailgets) ret = (*mailgets) (mail_read,bs,i,md);
/* special hack to avoid extra copy */ /* special hack to avoid extra copy */
if (bs->dtb->next == mail_string_next) return bs->curpos; else if (bs->dtb->next == mail_string_next) ret = bs->curpos;
/* make string copy in memory */ /* make string copy in memory */
return textcpyoffstring (&md->stream->text,bs,GETPOS (bs),i); else ret = textcpyoffstring (&md->stream->text,bs,GETPOS (bs),i);
return ret;
} }
/* Read data from stringstruct /* Read data from stringstruct
* Accepts: stringstruct * Accepts: stringstruct
* size of data to read * size of data to read
* buffer to read into * buffer to read into
* Returns: T, always, stringstruct updated * Returns: T, always, stringstruct updated
*/ */
long mail_read (void *stream,unsigned long size,char *buffer) long mail_read (void *stream,unsigned long size,char *buffer)
{ {
skipping to change at line 2186 skipping to change at line 2288
* character set * character set
* search program * search program
* option flags * option flags
* Returns: T if successful, NIL if bad charset * Returns: T if successful, NIL if bad charset
*/ */
long mail_search_default (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm, long mail_search_default (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
long flags) long flags)
{ {
unsigned long i; unsigned long i;
if (charset && *charset && /* convert if charset not US-ASCII or UTF-8 char *msg;
*/ /* make sure that charset is good */
!(((charset[0] == 'U') || (charset[0] == 'u')) && if (msg = utf8_badcharset (charset)) {
((((charset[1] == 'S') || (charset[1] == 's')) && MM_LOG (msg,ERROR); /* output error */
(charset[2] == '-') && fs_give ((void **) &msg);
((charset[3] == 'A') || (charset[3] == 'a')) && return NIL;
((charset[4] == 'S') || (charset[4] == 's')) &&
((charset[5] == 'C') || (charset[5] == 'c')) &&
((charset[6] == 'I') || (charset[6] == 'i')) &&
((charset[7] == 'I') || (charset[7] == 'i')) && !charset[8]) ||
(((charset[1] == 'T') || (charset[1] == 't')) &&
((charset[2] == 'F') || (charset[2] == 'f')) &&
(charset[3] == '-') && (charset[4] == '8') && !charset[5])))) {
if (utf8_text (NIL,charset,NIL,T)) utf8_searchpgm (pgm,charset);
else return NIL; /* charset unknown */
}
for (i = 1; i <= stream->nmsgs; ++i) if (mail_search_msg (stream,i,NIL,pg
m)){
if (flags & SE_UID) mm_searched (stream,mail_uid (stream,i));
else { /* mark as searched, notify mail program */
mail_elt (stream,i)->searched = T;
if (!stream->silent) mm_searched (stream,i);
}
} }
return LONGT; utf8_searchpgm (pgm,charset);
for (i = 1; i <= stream->nmsgs; ++i)
if (mail_search_msg (stream,i,NIL,pgm)) {
if (flags & SE_UID) mm_searched (stream,mail_uid (stream,i));
else { /* mark as searched, notify mail program */
mail_elt (stream,i)->searched = T;
if (!stream->silent) mm_searched (stream,i);
}
}
return LONGT; /* search completed */
} }
/* Mail ping mailbox /* Mail ping mailbox
* Accepts: mail stream * Accepts: mail stream
* Returns: stream if still open else NIL * Returns: stream if still open else NIL
*/ */
long mail_ping (MAILSTREAM *stream) long mail_ping (MAILSTREAM *stream)
{ {
unsigned long i,n,uf,len; unsigned long i,n,uf,len;
char *s,*f,tmp[MAILTMPLEN],flags[MAILTMPLEN]; char *s,*f,tmp[MAILTMPLEN],flags[MAILTMPLEN];
skipping to change at line 2282 skipping to change at line 2378
} }
else { /* copy failed */ else { /* copy failed */
sprintf (tmp,"Unable to move message %lu from %s mailbox", sprintf (tmp,"Unable to move message %lu from %s mailbox",
i,snarf->dtb->name); i,snarf->dtb->name);
mm_log (tmp,WARN); mm_log (tmp,WARN);
} }
} }
} }
/* expunge the messages */ /* expunge the messages */
mail_close_full (snarf,n ? CL_EXPUNGE : NIL); mail_close_full (snarf,n ? CL_EXPUNGE : NIL);
stream->snarf.time = time (0); stream->snarf.time = (unsigned long) time (0);
/* Even if the snarf failed, we don't want to return NIL if the stream /* Even if the snarf failed, we don't want to return NIL if the stream
* is still alive. Or at least that's what we currently think. * is still alive. Or at least that's what we currently think.
*/ */
/* redo the driver's action */ /* redo the driver's action */
ret = stream->dtb ? (*stream->dtb->ping) (stream) : NIL; ret = stream->dtb ? (*stream->dtb->ping) (stream) : NIL;
} }
return ret; return ret;
} }
/* Mail check mailbox /* Mail check mailbox
* Accepts: mail stream * Accepts: mail stream
*/ */
void mail_check (MAILSTREAM *stream) void mail_check (MAILSTREAM *stream)
{ {
/* do the driver's action */ /* do the driver's action */
if (stream->dtb) (*stream->dtb->check) (stream); if (stream->dtb) (*stream->dtb->check) (stream);
} }
/* Mail expunge mailbox /* Mail expunge mailbox
* Accepts: mail stream * Accepts: mail stream
* sequence to expunge if non-NIL
* expunge options
* Returns: T on success, NIL on failure
*/ */
void mail_expunge (MAILSTREAM *stream) long mail_expunge_full (MAILSTREAM *stream,char *sequence,long options)
{ {
/* do the driver's action */ /* do the driver's action */
if (stream->dtb) (*stream->dtb->expunge) (stream); return stream->dtb ? (*stream->dtb->expunge) (stream,sequence,options) : NIL;
} }
/* Mail copy message(s) /* Mail copy message(s)
* Accepts: mail stream * Accepts: mail stream
* sequence * sequence
* destination mailbox * destination mailbox
* flags * flags
*/ */
long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox, long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox,
skipping to change at line 2605 skipping to change at line 2704
elt->zoccident ? "-" : "+",elt->zhours,elt->zminutes); elt->zoccident ? "-" : "+",elt->zhours,elt->zminutes);
return string; return string;
} }
/* Mail parse date into elt fields /* Mail parse date into elt fields
* Accepts: elt to write into * Accepts: elt to write into
* date string to parse * date string to parse
* Returns: T if parse successful, else NIL * Returns: T if parse successful, else NIL
* This routine parses dates as follows: * This routine parses dates as follows:
* . leading three alphas followed by comma and space are ignored * . leading three alphas followed by comma and space are ignored
* . date accepted in format: mm/dd/yy, mm/dd/yyyy, dd-mmm-yy, dd-mmm-yyyy, * . date accepted in format: mm/dd/yy, mm/dd/yyyy, dd-mmm-yy, dd-mmm-yyyy,
* dd mmm yy, dd mmm yyyy * dd mmm yy, dd mmm yyyy, yyyy-mm-dd, yyyymmdd
* . two and three digit years interpreted according to RFC 2822 rules * . two and three digit years interpreted according to RFC 2822 rules
* . space or end of string required * . mandatory end of string if yyyy-mm-dd or yyyymmdd; otherwise optional
* space followed by time:
* . time accepted in format hh:mm:ss or hh:mm * . time accepted in format hh:mm:ss or hh:mm
* . end of string accepted * . end of string accepted
* . timezone accepted: hyphen followed by symbolic timezone, or space * . timezone accepted: hyphen followed by symbolic timezone, or space
* followed by signed numeric timezone or symbolic timezone * followed by signed numeric timezone or symbolic timezone
* Examples of normal input: * Examples of normal input:
* . IMAP date-only (SEARCH): * . IMAP date-only (SEARCH):
* dd-mmm-yyyy * dd-mmm-yyyy
* . IMAP date-time (INTERNALDATE): * . IMAP date-time (INTERNALDATE):
* dd-mmm-yyyy hh:mm:ss +zzzz * dd-mmm-yyyy hh:mm:ss +zzzz
* . RFC-822: * . RFC-822:
skipping to change at line 2658 skipping to change at line 2758
switch (*s) { /* different parse based on delimite r */ switch (*s) { /* different parse based on delimite r */
case '/': /* mm/dd/yy format */ case '/': /* mm/dd/yy format */
if (isdigit (*++s) && (d = strtoul (s,(char **) &s,10)) && if (isdigit (*++s) && (d = strtoul (s,(char **) &s,10)) &&
(*s == '/') && isdigit (*++s)) { (*s == '/') && isdigit (*++s)) {
y = strtoul (s,(char **) &s,10); y = strtoul (s,(char **) &s,10);
if (*s == '\0') break; /* must end here */ if (*s == '\0') break; /* must end here */
} }
return NIL; /* bogon */ return NIL; /* bogon */
case ' ': /* dd mmm yy format */ case ' ': /* dd mmm yy format */
while (s[1] == ' ') s++; /* slurp extra whitespace */ while (s[1] == ' ') s++; /* slurp extra whitespace */
case '-': /* dd-mmm-yy format */ case '-':
d = m; /* so the number we got is a day */ if (isdigit (s[1])) { /* possible ISO 8601 date format? */
y = m; /* yes, first number is year */
/* get month and day */
if ((m = strtoul (s+1,(char **) &s,10)) && (*s++ == '-') &&
(d = strtoul (s,(char **) &s,10)) && !*s) break;
return NIL; /* syntax error or time present */
}
d = m; /* dd-mmm-yy[yy], so first number is a day *
/
/* make sure string long enough! */ /* make sure string long enough! */
if (strlen (s) < (size_t) 5) return NIL; if (strlen (s) < (size_t) 5) return NIL;
/* Some compilers don't allow `<<' and/or longs in case statements. */ /* Some compilers don't allow `<<' and/or longs in case statements. */
/* slurp up the month string */ /* slurp up the month string */
ms = ((s[1] - 'A') * 1024) + ((s[2] - 'A') * 32) + (s[3] - 'A'); ms = ((s[1] - 'A') * 1024) + ((s[2] - 'A') * 32) + (s[3] - 'A');
switch (ms) { /* determine the month */ switch (ms) { /* determine the month */
case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break; case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break;
case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break; case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break;
case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break; case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break;
case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break; case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break;
skipping to change at line 2692 skipping to change at line 2799
mi = *s; /* note delimiter, skip alphas */ mi = *s; /* note delimiter, skip alphas */
for (s += 4; isalpha (*s); s++); for (s += 4; isalpha (*s); s++);
/* error if delimiter not here */ /* error if delimiter not here */
if (mi != *s++) return NIL; if (mi != *s++) return NIL;
} }
while (*s == ' ') s++; /* parse year */ while (*s == ' ') s++; /* parse year */
if (isdigit (*s)) { /* must be a digit here */ if (isdigit (*s)) { /* must be a digit here */
y = strtoul (s,(char **) &s,10); y = strtoul (s,(char **) &s,10);
if (*s == '\0' || *s == ' ') break; if (*s == '\0' || *s == ' ') break;
} }
case '\0': /* ISO 8601 compact date */
if (m < (BASEYEAR * 10000)) return NIL;
y = m / 10000; /* get year */
d = (m %= 10000) % 100; /* get day */
m /= 100; /* and month */
break;
default: default:
return NIL; /* unknown date format */ return NIL; /* unknown date format */
} }
/* minimal validity check of date */ /* minimal validity check of date */
if ((d > 31) || (m > 12)) return NIL; if ((d > 31) || (m > 12)) return NIL;
if (y < 49) y += 2000; /* RFC 2282 rules for two digit years 00-49 */ if (y < 49) y += 2000; /* RFC 2282 rules for two digit years 00-49 */
else if (y < 999) y += 1900; /* 2-digit years 50-99 and 3-digit years */ else if (y < 999) y += 1900; /* 2-digit years 50-99 and 3-digit years */
/* reject prehistoric and far future years * / /* reject prehistoric and far future years * /
if ((y < BASEYEAR) || (y > maxyear)) return NIL; if ((y < BASEYEAR) || (y > maxyear)) return NIL;
/* set values in elt */ /* set values in elt */
skipping to change at line 2890 skipping to change at line 3003
* number of messages * number of messages
*/ */
void mail_exists (MAILSTREAM *stream,unsigned long nmsgs) void mail_exists (MAILSTREAM *stream,unsigned long nmsgs)
{ {
char tmp[MAILTMPLEN]; char tmp[MAILTMPLEN];
if (nmsgs > MAXMESSAGES) { if (nmsgs > MAXMESSAGES) {
sprintf (tmp,"Mailbox has more messages (%lu) exist than maximum (%lu)" , sprintf (tmp,"Mailbox has more messages (%lu) exist than maximum (%lu)" ,
nmsgs,MAXMESSAGES); nmsgs,MAXMESSAGES);
mm_log (tmp,ERROR); mm_log (tmp,ERROR);
nmsgs = MAXMESSAGES; /* cap to maximum */
/* probably will crash in mail_elt() soon enough... */
} }
else {
/* make sure cache is large enough */ /* make sure cache is large enough */
(*mailcache) (stream,nmsgs,CH_SIZE); (*mailcache) (stream,nmsgs,CH_SIZE);
stream->nmsgs = nmsgs; /* update stream status */ stream->nmsgs = nmsgs; /* update stream status */
/* notify main program of change */ /* notify main program of change */
if (!stream->silent) MM_EXISTS (stream,nmsgs); if (!stream->silent) MM_EXISTS (stream,nmsgs);
}
} }
/* Mail n messages are recent /* Mail n messages are recent
* Accepts: mail stream * Accepts: mail stream
* number of recent messages * number of recent messages
*/ */
void mail_recent (MAILSTREAM *stream,unsigned long recent) void mail_recent (MAILSTREAM *stream,unsigned long recent)
{ {
char tmp[MAILTMPLEN]; char tmp[MAILTMPLEN];
skipping to change at line 3094 skipping to change at line 3207
{ {
unsigned long i; unsigned long i;
unsigned char *s,*t; unsigned char *s,*t;
STRINGLIST *m; STRINGLIST *m;
if (!msglines) return T; /* full header is in cache */ if (!msglines) return T; /* full header is in cache */
/* need full header but filtered in cache */ /* need full header but filtered in cache */
if ((flags & FT_NOT) || !lines) return NIL; if ((flags & FT_NOT) || !lines) return NIL;
do { /* make sure all present & accounted for */ do { /* make sure all present & accounted for */
for (m = msglines; m; m = m->next) if (lines->text.size == m->text.size ) { for (m = msglines; m; m = m->next) if (lines->text.size == m->text.size ) {
for (s = lines->text.data,t = m->text.data,i = lines->text.size; for (s = lines->text.data,t = m->text.data,i = lines->text.size;
i && ((islower (*s) ? (*s-('a'-'A')) : *s) == i && !compare_uchar (*s,*t); s++,t++,i--);
(islower (*t) ? (*t-('a'-'A')) : *t)); s++,t++,i--);
if (!i) break; /* this line matches */ if (!i) break; /* this line matches */
} }
if (!m) return NIL; /* didn't find in the list */ if (!m) return NIL; /* didn't find in the list */
} }
while (lines = lines->next); while (lines = lines->next);
return T; /* all lines found */ return T; /* all lines found */
} }
/* Mail filter text by header lines /* Mail filter text by header lines
* Accepts: text to filter, with trailing null * Accepts: text to filter, with trailing null
* length of text * length of text
skipping to change at line 3382 skipping to change at line 3494
/* Mail search message header /* Mail search message header
* Accepts: header as sized text * Accepts: header as sized text
* strings to search * strings to search
* Returns: T if search found a match * Returns: T if search found a match
*/ */
long mail_search_header (SIZEDTEXT *hdr,STRINGLIST *st) long mail_search_header (SIZEDTEXT *hdr,STRINGLIST *st)
{ {
SIZEDTEXT h; SIZEDTEXT h;
long ret = LONGT; long ret = LONGT;
utf8_mime2text (hdr,&h); /* make UTF-8 version of header */ /* make UTF-8 version of header */
utf8_mime2text (hdr,&h,U8T_CANONICAL);
while (h.size && ((h.data[h.size-1]=='\015') || (h.data[h.size-1]=='\012' ))) while (h.size && ((h.data[h.size-1]=='\015') || (h.data[h.size-1]=='\012' )))
--h.size; /* slice off trailing newlines */ --h.size; /* slice off trailing newlines */
do if (h.size ? /* search non-empty string */ do if (h.size ? /* search non-empty string */
!search (h.data,h.size,st->text.data,st->text.size) : st->text.size ) !ssearch (h.data,h.size,st->text.data,st->text.size) : st->text.siz e)
ret = NIL; ret = NIL;
while (ret && (st = st->next)); while (ret && (st = st->next));
if (h.data != hdr->data) fs_give ((void **) &h.data); if (h.data != hdr->data) fs_give ((void **) &h.data);
return ret; return ret;
} }
/* Mail search message body /* Mail search message body
* Accepts: MAIL stream * Accepts: MAIL stream
* message number * message number
* optional section specification * optional section specification
* string list * string list
skipping to change at line 3420 skipping to change at line 3533
for (stream->private.search.string = s; st;) { for (stream->private.search.string = s; st;) {
s->text.data = st->text.data; s->text.data = st->text.data;
s->text.size = st->text.size; s->text.size = st->text.size;
if (st = st->next) s = s->next = mail_newstringlist (); if (st = st->next) s = s->next = mail_newstringlist ();
} }
stream->private.search.text = NIL; stream->private.search.text = NIL;
if (flags) { /* want header? */ if (flags) { /* want header? */
SIZEDTEXT s,t; SIZEDTEXT s,t;
s.data = (unsigned char *) s.data = (unsigned char *)
mail_fetch_header (stream,msgno,section,NIL,&s.size,FT_INTERNAL|FT_PE EK); mail_fetch_header (stream,msgno,section,NIL,&s.size,FT_INTERNAL|FT_PE EK);
utf8_mime2text (&s,&t); utf8_mime2text (&s,&t,U8T_CANONICAL);
ret = mail_search_string (&t,"UTF-8",&stream->private.search.string); ret = mail_search_string_work (&t,&stream->private.search.string);
if (t.data != s.data) fs_give ((void **) &t.data); if (t.data != s.data) fs_give ((void **) &t.data);
} }
if (!ret) { /* still looking for match? */ if (!ret) { /* still looking for match? */
/* no section, get top-level body */ /* no section, get top-level body */
if (!section) mail_fetchstructure (stream,msgno,&body); if (!section) mail_fetchstructure (stream,msgno,&body);
/* get body of nested message */ /* get body of nested message */
else if ((body = mail_body (stream,msgno,section)) && else if ((body = mail_body (stream,msgno,section)) &&
(body->type == TYPEMULTIPART) && body->subtype && (body->type == TYPEMULTIPART) && body->subtype &&
!strcmp (body->subtype,"RFC822")) body = body->nested.msg->body ; !strcmp (body->subtype,"RFC822")) body = body->nested.msg->body ;
if (body) ret = mail_search_body (stream,msgno,body,NIL,1,flags); if (body) ret = mail_search_body (stream,msgno,body,NIL,1,flags);
skipping to change at line 3467 skipping to change at line 3580
SIZEDTEXT st,h; SIZEDTEXT st,h;
PART *part; PART *part;
PARAMETER *param; PARAMETER *param;
if (prefix && (strlen (prefix) > (MAILTMPLEN - 20))) return NIL; if (prefix && (strlen (prefix) > (MAILTMPLEN - 20))) return NIL;
sprintf (sect,"%s%lu",prefix ? prefix : "",section++); sprintf (sect,"%s%lu",prefix ? prefix : "",section++);
if (flags && prefix) { /* want to search MIME header too? */ if (flags && prefix) { /* want to search MIME header too? */
st.data = (unsigned char *) mail_fetch_mime (stream,msgno,sect,&st.size , st.data = (unsigned char *) mail_fetch_mime (stream,msgno,sect,&st.size ,
FT_INTERNAL | FT_PEEK); FT_INTERNAL | FT_PEEK);
if (stream->dtb->flags & DR_LOWMEM) ret = stream->private.search.result ; if (stream->dtb->flags & DR_LOWMEM) ret = stream->private.search.result ;
else { else {
utf8_mime2text (&st,&h); /* make UTF-8 version of header */ /* make UTF-8 version of header */
ret = mail_search_string (&h,"UTF-8",&stream->private.search.string); utf8_mime2text (&st,&h,U8T_CANONICAL);
ret = mail_search_string_work (&h,&stream->private.search.string);
if (h.data != st.data) fs_give ((void **) &h.data); if (h.data != st.data) fs_give ((void **) &h.data);
} }
} }
if (!ret) switch (body->type) { if (!ret) switch (body->type) {
case TYPEMULTIPART: case TYPEMULTIPART:
/* extend prefix if not first time */ /* extend prefix if not first time */
s = prefix ? strcat (sect,".") : ""; s = prefix ? strcat (sect,".") : "";
for (i = 1,part = body->nested.part; part && !ret; i++,part = part->nex t) for (i = 1,part = body->nested.part; part && !ret; i++,part = part->nex t)
ret = mail_search_body (stream,msgno,&part->body,s,i,flags); ret = mail_search_body (stream,msgno,&part->body,s,i,flags);
break; break;
case TYPEMESSAGE: case TYPEMESSAGE:
if (!strcmp (body->subtype,"RFC822")) { if (!strcmp (body->subtype,"RFC822")) {
if (flags) { /* want to search nested message header? */ if (flags) { /* want to search nested message header? */
st.data = (unsigned char *) st.data = (unsigned char *)
mail_fetch_header (stream,msgno,sect,NIL,&st.size, mail_fetch_header (stream,msgno,sect,NIL,&st.size,
FT_INTERNAL | FT_PEEK); FT_INTERNAL | FT_PEEK);
if (stream->dtb->flags & DR_LOWMEM) ret =stream->private.search.resu lt; if (stream->dtb->flags & DR_LOWMEM) ret =stream->private.search.resu lt;
else { else {
utf8_mime2text (&st,&h);/* make UTF-8 version of header */ /* make UTF-8 version of header */
ret = mail_search_string (&h,"UTF-8",&stream->private.search.strin utf8_mime2text (&st,&h,U8T_CANONICAL);
g); ret = mail_search_string_work (&h,&stream->private.search.string);
if (h.data != st.data) fs_give ((void **) &h.data); if (h.data != st.data) fs_give ((void **) &h.data);
} }
} }
if (body = body->nested.msg->body) if (body = body->nested.msg->body)
ret = (body->type == TYPEMULTIPART) ? ret = (body->type == TYPEMULTIPART) ?
mail_search_body (stream,msgno,body,(prefix ? prefix : ""), mail_search_body (stream,msgno,body,(prefix ? prefix : ""),
section - 1,flags) : section - 1,flags) :
mail_search_body (stream,msgno,body,strcat (sect,"."),1,flags); mail_search_body (stream,msgno,body,strcat (sect,"."),1,flags);
break; break;
} }
skipping to change at line 3540 skipping to change at line 3655
} }
/* Mail search text /* Mail search text
* Accepts: sized text to search * Accepts: sized text to search
* character set of sized text * character set of sized text
* string list of search keys * string list of search keys
* Returns: T if search found a match * Returns: T if search found a match
*/ */
long mail_search_string (SIZEDTEXT *s,char *charset,STRINGLIST **st) long mail_search_string (SIZEDTEXT *s,char *charset,STRINGLIST **st)
{ {
void *t;
SIZEDTEXT u; SIZEDTEXT u;
long ret;
STRINGLIST **sc = st; STRINGLIST **sc = st;
/* convert to UTF-8 as best we can */ /* convert to UTF-8 as best we can */
if (!utf8_text (s,charset,&u,NIL)) utf8_text (s,NIL,&u,NIL); if (!utf8_text (s,charset,&u,U8T_CANONICAL))
utf8_text (s,NIL,&u,U8T_CANONICAL);
ret = mail_search_string_work (&u,st);
if (u.data != s->data) fs_give ((void **) &u.data);
return ret;
}
/* Mail search text worker routine
* Accepts: sized text to search
* string list of search keys
* Returns: T if search found a match
*/
long mail_search_string_work (SIZEDTEXT *s,STRINGLIST **st)
{
void *t;
STRINGLIST **sc = st;
while (*sc) { /* run down criteria list */ while (*sc) { /* run down criteria list */
if (search (u.data,u.size,(*sc)->text.data,(*sc)->text.size)) { if (ssearch (s->data,s->size,(*sc)->text.data,(*sc)->text.size)) {
t = (void *) (*sc); /* found one, need to flush this */ t = (void *) (*sc); /* found one, need to flush this */
*sc = (*sc)->next; /* remove it from the list */ *sc = (*sc)->next; /* remove it from the list */
fs_give (&t); /* flush the buffer */ fs_give (&t); /* flush the buffer */
} }
else sc = &(*sc)->next; /* move to next in list */ else sc = &(*sc)->next; /* move to next in list */
} }
if (u.data != s->data) fs_give ((void **) &u.data);
return *st ? NIL : LONGT; return *st ? NIL : LONGT;
} }
/* Mail search keyword /* Mail search keyword
* Accepts: MAIL stream * Accepts: MAIL stream
* elt to get flags from * elt to get flags from
* keyword list * keyword list
* T for keyword search, NIL for unkeyword search * T for keyword search, NIL for unkeyword search
* Returns: T if search found a match * Returns: T if search found a match
*/ */
skipping to change at line 3595 skipping to change at line 3725
* Returns: T if search found a match * Returns: T if search found a match
*/ */
#define SEARCHBUFLEN (size_t) 2000 #define SEARCHBUFLEN (size_t) 2000
#define SEARCHBUFSLOP (size_t) 5 #define SEARCHBUFSLOP (size_t) 5
long mail_search_addr (ADDRESS *adr,STRINGLIST *st) long mail_search_addr (ADDRESS *adr,STRINGLIST *st)
{ {
ADDRESS *a,tadr; ADDRESS *a,tadr;
SIZEDTEXT txt; SIZEDTEXT txt;
char tmp[MAILTMPLEN]; char tmp[SENDBUFLEN + 1];
size_t i = SEARCHBUFLEN; size_t i = SEARCHBUFLEN;
size_t k; size_t k;
long ret = NIL; long ret = NIL;
if (adr) { if (adr) {
txt.data = (unsigned char *) fs_get (i + SEARCHBUFSLOP); txt.data = (unsigned char *) fs_get (i + SEARCHBUFSLOP);
/* never an error or next */ /* never an error or next */
tadr.error = NIL,tadr.next = NIL; tadr.error = NIL,tadr.next = NIL;
/* write address list */ /* write address list */
for (txt.size = 0,a = adr; a; a = a->next) { for (txt.size = 0,a = adr; a; a = a->next) {
k = (tadr.mailbox = a->mailbox) ? 4 + 2*strlen (a->mailbox) : 3; k = (tadr.mailbox = a->mailbox) ? 4 + 2*strlen (a->mailbox) : 3;
if (tadr.personal = a->personal) k += 3 + 2*strlen (a->personal); if (tadr.personal = a->personal) k += 3 + 2*strlen (a->personal);
if (tadr.adl = a->adl) k += 3 + 2*strlen (a->adl); if (tadr.adl = a->adl) k += 3 + 2*strlen (a->adl);
if (tadr.host = a->host) k += 3 + 2*strlen (a->host); if (tadr.host = a->host) k += 3 + 2*strlen (a->host);
if (tadr.personal || tadr.adl) k += 2; if (tadr.personal || tadr.adl) k += 2;
if (k < (MAILTMPLEN-10)) { /* ignore ridiculous addresses */ if (k < (SENDBUFLEN-10)) {/* ignore ridiculous addresses */
tmp[0] = '\0'; tmp[0] = '\0';
rfc822_write_address (tmp,&tadr); rfc822_write_address (tmp,&tadr);
/* resize buffer if necessary */ /* resize buffer if necessary */
if (((k = strlen (tmp)) + txt.size) > i) if (((k = strlen (tmp)) + txt.size) > i)
fs_resize ((void **) &txt.data,SEARCHBUFSLOP + (i += SEARCHBUFLEN) ); fs_resize ((void **) &txt.data,SEARCHBUFSLOP + (i += SEARCHBUFLEN) );
/* add new address */ /* add new address */
memcpy (txt.data + txt.size,tmp,k); memcpy (txt.data + txt.size,tmp,k);
txt.size += k; txt.size += k;
/* another address follows */ /* another address follows */
if (a->next) txt.data[txt.size++] = ','; if (a->next) txt.data[txt.size++] = ',';
skipping to change at line 3844 skipping to change at line 3974
else return NIL; else return NIL;
break; break;
} }
while (*s) s = &(*s)->next; /* find tail of list */ while (*s) s = &(*s)->next; /* find tail of list */
*s = mail_newstringlist (); /* make new entry */ *s = mail_newstringlist (); /* make new entry */
/* return the data */ /* return the data */
(*s)->text.data = (unsigned char *) cpystr (d); (*s)->text.data = (unsigned char *) cpystr (d);
(*s)->text.size = n; (*s)->text.size = n;
return T; return T;
} }
/* Mail parse set from string
* Accepts: string to parse
* pointer to updated string pointer for return
* Returns: set with pointer updated, or NIL if error
*/
SEARCHSET *mail_parse_set (char *s,char **ret)
{
SEARCHSET *cur;
SEARCHSET *set = NIL;
while (isdigit (*s)) {
if (!set) cur = set = mail_newsearchset ();
else cur = cur->next = mail_newsearchset ();
/* parse value */
if (!(cur->first = strtoul (s,&s,10)) ||
((*s == ':') && !(isdigit (*++s) && (cur->last = strtoul (s,&s,10)))
))
break; /* bad value or range */
if (*s == ',') ++s; /* point to next value if more */
else { /* end of set */
*ret = s; /* set return pointer */
return set; /* return set */
}
}
mail_free_searchset (&set); /* failure, punt partial set */
return NIL;
}
/* Mail append to set
* Accepts: head of search set or NIL to do nothing
* message to add
* Returns: tail of search set or NIL if did nothing
*/
SEARCHSET *mail_append_set (SEARCHSET *set,unsigned long msgno)
{
if (set) { /* find tail */
while (set->next) set = set->next;
/* start of set if no first member */
if (!set->first) set->first = msgno;
else if (msgno == (set->last ? set->last : set->first) + 1)
set->last = msgno; /* extend range if 1 past current */
else (set = set->next = mail_newsearchset ())->first = msgno;
}
return set;
}
/* Mail sort messages /* Mail sort messages
* Accepts: mail stream * Accepts: mail stream
* character set * character set
* search program * search program
* sort program * sort program
* option flags * option flags
* Returns: vector of sorted message sequences or NIL if error * Returns: vector of sorted message sequences or NIL if error
*/ */
unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
skipping to change at line 3973 skipping to change at line 4148
for (pg = pgm; pg; pg = pg->next) switch (pg->function) { for (pg = pgm; pg; pg = pg->next) switch (pg->function) {
case SORTARRIVAL: /* sort by arrival date */ case SORTARRIVAL: /* sort by arrival date */
if (!s->arrival) { if (!s->arrival) {
/* internal date unknown but can get? */ /* internal date unknown but can get? */
if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) { if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) {
sprintf (tmp,"%lu",i); sprintf (tmp,"%lu",i);
mail_fetch_fast (stream,tmp,NIL); mail_fetch_fast (stream,tmp,NIL);
} }
/* wrong thing before 3-Jan-1970 */ /* wrong thing before 3-Jan-1970 */
s->arrival = elt->day ? mail_longdate (elt) : 1; s->arrival = elt->day ? mail_longdate (elt) : 1;
s->dirty = T;
} }
break; break;
case SORTSIZE: /* sort by message size */ case SORTSIZE: /* sort by message size */
if (!s->size) { if (!s->size) {
if (!elt->rfc822_size) { if (!elt->rfc822_size) {
sprintf (tmp,"%lu",i); sprintf (tmp,"%lu",i);
mail_fetch_fast (stream,tmp,NIL); mail_fetch_fast (stream,tmp,NIL);
} }
s->size = elt->rfc822_size ? elt->rfc822_size : 1; s->size = elt->rfc822_size ? elt->rfc822_size : 1;
s->dirty = T;
} }
break; break;
case SORTDATE: /* sort by date */ case SORTDATE: /* sort by date */
if (!s->date) { if (!s->date) {
if (env) t = env->date; if (env) t = env->date;
else if ((t = mail_fetch_header (stream,i,NIL,&maildateline,NIL, else if ((t = mail_fetch_header (stream,i,NIL,&maildateline,NIL,
FT_INTERNAL | FT_PEEK)) && FT_INTERNAL | FT_PEEK)) &&
(t = strchr (t,':'))) (t = strchr (t,':')))
for (x = ++t; x = strpbrk (x,"\012\015"); x++) for (x = ++t; x = strpbrk (x,"\012\015"); x++)
switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1 )){ switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1 )){
skipping to change at line 4015 skipping to change at line 4192
if (!(s->date = s->arrival)) { if (!(s->date = s->arrival)) {
/* internal date unknown but can get? */ /* internal date unknown but can get? */
if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) { if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) {
sprintf (tmp,"%lu",i); sprintf (tmp,"%lu",i);
mail_fetch_fast (stream,tmp,NIL); mail_fetch_fast (stream,tmp,NIL);
} }
/* wrong thing before 3-Jan-1970 */ /* wrong thing before 3-Jan-1970 */
s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1); s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1);
} }
} }
s->dirty = T;
} }
break; break;
case SORTFROM: /* sort by first from */ case SORTFROM: /* sort by first from */
if (!s->from) { if (!s->from) {
if (env) s->from = env->from && env->from->mailbox ? if (env) s->from = env->from && env->from->mailbox ?
cpystr (env->from->mailbox) : NIL; cpystr (env->from->mailbox) : NIL;
else if ((t = mail_fetch_header (stream,i,NIL,&mailfromline,NIL, else if ((t = mail_fetch_header (stream,i,NIL,&mailfromline,NIL,
FT_INTERNAL | FT_PEEK)) && FT_INTERNAL | FT_PEEK)) &&
(t = strchr (t,':'))) { (t = strchr (t,':'))) {
for (x = ++t; x = strpbrk (x,"\012\015"); x++) for (x = ++t; x = strpbrk (x,"\012\015"); x++)
skipping to change at line 4046 skipping to change at line 4224
default: /* tie off extraneous text */ default: /* tie off extraneous text */
*x = x[1] = '\0'; *x = x[1] = '\0';
} }
if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) { if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
s->from = adr->mailbox; s->from = adr->mailbox;
adr->mailbox = NIL; adr->mailbox = NIL;
mail_free_address (&adr); mail_free_address (&adr);
} }
} }
if (!s->from) s->from = cpystr (""); if (!s->from) s->from = cpystr ("");
s->dirty = T;
} }
break; break;
case SORTTO: /* sort by first to */ case SORTTO: /* sort by first to */
if (!s->to) { if (!s->to) {
if (env) s->to = env->to && env->to->mailbox ? if (env) s->to = env->to && env->to->mailbox ?
cpystr (env->to->mailbox) : NIL; cpystr (env->to->mailbox) : NIL;
else if ((t = mail_fetch_header (stream,i,NIL,&mailtonline,NIL, else if ((t = mail_fetch_header (stream,i,NIL,&mailtonline,NIL,
FT_INTERNAL | FT_PEEK)) && FT_INTERNAL | FT_PEEK)) &&
(t = strchr (t,':'))) { (t = strchr (t,':'))) {
for (x = ++t; x = strpbrk (x,"\012\015"); x++) for (x = ++t; x = strpbrk (x,"\012\015"); x++)
skipping to change at line 4077 skipping to change at line 4256
default: /* tie off extraneous text */ default: /* tie off extraneous text */
*x = x[1] = '\0'; *x = x[1] = '\0';
} }
if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) { if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
s->to = adr->mailbox; s->to = adr->mailbox;
adr->mailbox = NIL; adr->mailbox = NIL;
mail_free_address (&adr); mail_free_address (&adr);
} }
} }
if (!s->to) s->to = cpystr (""); if (!s->to) s->to = cpystr ("");
s->dirty = T;
} }
break; break;
case SORTCC: /* sort by first cc */ case SORTCC: /* sort by first cc */
if (!s->cc) { if (!s->cc) {
if (env) s->cc = env->cc && env->cc->mailbox ? if (env) s->cc = env->cc && env->cc->mailbox ?
cpystr (env->cc->mailbox) : NIL; cpystr (env->cc->mailbox) : NIL;
else if ((t = mail_fetch_header (stream,i,NIL,&mailccline,NIL, else if ((t = mail_fetch_header (stream,i,NIL,&mailccline,NIL,
FT_INTERNAL | FT_PEEK)) && FT_INTERNAL | FT_PEEK)) &&
(t = strchr (t,':'))) { (t = strchr (t,':'))) {
for (x = ++t; x = strpbrk (x,"\012\015"); x++) for (x = ++t; x = strpbrk (x,"\012\015"); x++)
skipping to change at line 4108 skipping to change at line 4288
default: /* tie off extraneous text */ default: /* tie off extraneous text */
*x = x[1] = '\0'; *x = x[1] = '\0';
} }
if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) { if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
s->cc = adr->mailbox; s->cc = adr->mailbox;
adr->mailbox = NIL; adr->mailbox = NIL;
mail_free_address (&adr); mail_free_address (&adr);
} }
} }
if (!s->cc) s->cc = cpystr (""); if (!s->cc) s->cc = cpystr ("");
s->dirty = T;
} }
break; break;
case SORTSUBJECT: /* sort by subject */ case SORTSUBJECT: /* sort by subject */
if (!s->subject) { if (!s->subject) {
/* get subject from envelope if have one */ /* get subject from envelope if have one */
if (env) t = env->subject ? env->subject : ""; if (env) t = env->subject ? env->subject : "";
/* otherwise snarf from header text */ /* otherwise snarf from header text */
else if ((t = mail_fetch_header (stream,i,NIL,&mailsubline, else if ((t = mail_fetch_header (stream,i,NIL,&mailsubline,
NIL,FT_INTERNAL | FT_PEEK)) && NIL,FT_INTERNAL | FT_PEEK)) &&
(t = strchr (t,':'))) (t = strchr (t,':')))
skipping to change at line 4129 skipping to change at line 4310
switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1 )){ switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1 )){
case ' ': /* erase continuation newlines */ case ' ': /* erase continuation newlines */
case '\t': case '\t':
memmove (x,v,strlen (v)); memmove (x,v,strlen (v));
break; break;
default: /* tie off extraneous text */ default: /* tie off extraneous text */
*x = x[1] = '\0'; *x = x[1] = '\0';
} }
else t = ""; /* empty subject */ else t = ""; /* empty subject */
/* strip and cache subject */ /* strip and cache subject */
s->refwd = mail_strip_subject (s->original_subject = cpystr (t), s->refwd = mail_strip_subject (t,&s->subject);
&s->subject); s->dirty = T;
} }
break; break;
default: default:
fatal ("Unknown sort function"); fatal ("Unknown sort function");
} }
} }
return sc; return sc;
} }
/* Strip subjects of extra spaces and leading and trailing cruft for sortin g /* Strip subjects of extra spaces and leading and trailing cruft for sortin g
* Accepts: unstripped subject * Accepts: unstripped subject
skipping to change at line 4155 skipping to change at line 4336
unsigned int mail_strip_subject (char *t,char **ret) unsigned int mail_strip_subject (char *t,char **ret)
{ {
SIZEDTEXT src,dst; SIZEDTEXT src,dst;
unsigned long i,slen; unsigned long i,slen;
char c,*s,*x; char c,*s,*x;
unsigned int refwd = NIL; unsigned int refwd = NIL;
if (src.size = strlen (t)) { /* have non-empty subject? */ if (src.size = strlen (t)) { /* have non-empty subject? */
src.data = (unsigned char *) t; src.data = (unsigned char *) t;
/* Step 1 */ /* Step 1 */
/* make copy, convert MIME2 if needed */ /* make copy, convert MIME2 if needed */
*ret = s = (utf8_mime2text (&src,&dst) && (src.data != dst.data)) ? *ret = s = (utf8_mime2text (&src,&dst,U8T_CANONICAL) &&
(char *) dst.data : cpystr (t); (src.data != dst.data)) ? (char *) dst.data : cpystr (t);
/* convert spaces to tab, strip extra spaces */ /* convert spaces to tab, strip extra spaces */
for (x = t = s, c = 'x'; *t; t++) { for (x = t = s, c = 'x'; *t; t++) {
if (c != ' ') c = *x++ = ((*t == '\t') ? ' ' : *t); if (c != ' ') c = *x++ = ((*t == '\t') ? ' ' : *t);
else if ((*t != '\t') && (*t != ' ')) c = *x++ = *t; else if ((*t != '\t') && (*t != ' ')) c = *x++ = *t;
} }
*x = '\0'; /* tie off string */ *x = '\0'; /* tie off string */
/* Step 2 */ /* Step 2 */
for (slen = dst.size; s; slen = strlen (s)) { for (slen = dst.size; s; slen = strlen (s)) {
for (t = s + slen; t > s; ) switch (t[-1]) { for (t = s + slen; t > s; ) switch (t[-1]) {
case ' ': case '\t': /* WSP */ case ' ': case '\t': /* WSP */
skipping to change at line 4540 skipping to change at line 4721
mail_fetch_overview (stream,tmp,mail_thread_loadcache); mail_fetch_overview (stream,tmp,mail_thread_loadcache);
} }
/* still missing data? */ /* still missing data? */
if (!s->date || !s->subject || !s->message_id || !s->references) { if (!s->date || !s->subject || !s->message_id || !s->references) {
/* try to load data from envelope */ /* try to load data from envelope */
if (env = mail_fetch_structure (stream,s->num,NIL,NIL)) { if (env = mail_fetch_structure (stream,s->num,NIL,NIL)) {
if (!s->date && env->date && mail_parse_date (&telt,env->date)) if (!s->date && env->date && mail_parse_date (&telt,env->date))
s->date = mail_longdate (&telt); s->date = mail_longdate (&telt);
if (!s->subject && env->subject) if (!s->subject && env->subject)
s->refwd = s->refwd =
mail_strip_subject (s->original_subject = cpystr (env->subject mail_strip_subject (env->subject,&s->subject);
),
&s->subject);
if (!s->message_id && env->message_id && *env->message_id) if (!s->message_id && env->message_id && *env->message_id)
s->message_id = mail_thread_parse_msgid (env->message_id,NIL); s->message_id = mail_thread_parse_msgid (env->message_id,NIL);
if (!s->references && /* use References: or In-Reply-To: */ if (!s->references && /* use References: or In-Reply-To: */
!(s->references = !(s->references =
mail_thread_parse_references (env->references,T))) mail_thread_parse_references (env->references,T)))
s->references = mail_thread_parse_references(env->in_reply_to,NI L); s->references = mail_thread_parse_references(env->in_reply_to,NI L);
} }
/* last resort */ /* last resort */
if (!s->date && !(s->date = s->arrival)) { if (!s->date && !(s->date = s->arrival)) {
/* internal date unknown but can get? */ /* internal date unknown but can get? */
if (!(elt = mail_elt (stream,s->num))->day && if (!(elt = mail_elt (stream,s->num))->day &&
!(stream->dtb->flags & DR_NOINTDATE)) { !(stream->dtb->flags & DR_NOINTDATE)) {
sprintf (tmp,"%lu",s->num); sprintf (tmp,"%lu",s->num);
mail_fetch_fast (stream,tmp,NIL); mail_fetch_fast (stream,tmp,NIL);
} }
/* wrong thing before 3-Jan-1970 */ /* wrong thing before 3-Jan-1970 */
s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1); s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1);
} }
if (!s->subject) s->subject = cpystr (""); if (!s->subject) s->subject = cpystr ("");
if (!s->references) s->references = mail_newstringlist (); if (!s->references) s->references = mail_newstringlist ();
s->dirty = T;
} }
} }
/* Step 1 (preliminary) */ /* Step 1 (preliminary) */
/* generate unique string */ /* generate unique string */
sprintf (tmp,"%s.%lx.%lx@%s",stream->mailbox,stream->uid_validity, sprintf (tmp,"%s.%lx.%lx@%s",stream->mailbox,stream->uid_validity,
mail_uid (stream,s->num),mylocalhost ()); mail_uid (stream,s->num),mylocalhost ());
/* flush old unique string if not message-id */ /* flush old unique string if not message-id */
if (s->unique && (s->unique != s->message_id)) if (s->unique && (s->unique != s->message_id))
fs_give ((void **) &s->unique); fs_give ((void **) &s->unique);
s->unique = s->message_id ? /* don't permit Message ID duplicate s */ s->unique = s->message_id ? /* don't permit Message ID duplicate s */
skipping to change at line 4740 skipping to change at line 4921
* overview of this message * overview of this message
* msgno of this message * msgno of this message
*/ */
void mail_thread_loadcache (MAILSTREAM *stream,unsigned long uid,OVERVIEW * ov, void mail_thread_loadcache (MAILSTREAM *stream,unsigned long uid,OVERVIEW * ov,
unsigned long msgno) unsigned long msgno)
{ {
if (msgno && ov) { /* just in case */ if (msgno && ov) { /* just in case */
MESSAGECACHE telt; MESSAGECACHE telt;
SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE); SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE);
if (!s->subject && ov->subject) if (!s->subject && ov->subject) {
s->refwd = mail_strip_subject (s->original_subject = cpystr(ov->subje s->refwd = mail_strip_subject (ov->subject,&s->subject);
ct), s->dirty = T;
&s->subject); }
if (!s->from && ov->from && ov->from->mailbox) if (!s->from && ov->from && ov->from->mailbox) {
s->from = cpystr (ov->from->mailbox); s->from = cpystr (ov->from->mailbox);
if (!s->date && ov->date && mail_parse_date (&telt,ov->date)) s->dirty = T;
}
if (!s->date && ov->date && mail_parse_date (&telt,ov->date)) {
s->date = mail_longdate (&telt); s->date = mail_longdate (&telt);
if (!s->message_id && ov->message_id) s->dirty = T;
}
if (!s->message_id && ov->message_id) {
s->message_id = mail_thread_parse_msgid (ov->message_id,NIL); s->message_id = mail_thread_parse_msgid (ov->message_id,NIL);
s->dirty = T;
}
if (!s->references && if (!s->references &&
!(s->references = mail_thread_parse_references (ov->references,T))) !(s->references = mail_thread_parse_references (ov->references,T))) {
/* don't do In-Reply-To with NNTP mailboxes */ /* don't do In-Reply-To with NNTP mailboxes */
s->references = mail_newstringlist (); s->references = mail_newstringlist ();
if (!s->size && ov->optional.octets) s->size = ov->optional.octets; s->dirty = T;
}
if (!s->size && ov->optional.octets) {
s->size = ov->optional.octets;
s->dirty = T;
}
} }
} }
/* Thread parse Message ID /* Thread parse Message ID
* Accepts: pointer to purported Message ID * Accepts: pointer to purported Message ID
* pointer to return pointer * pointer to return pointer
* Returns: Message ID or NIL, return pointer updated * Returns: Message ID or NIL, return pointer updated
*/ */
char *mail_thread_parse_msgid (char *s,char **ss) char *mail_thread_parse_msgid (char *s,char **ss)
{ {
skipping to change at line 4798 skipping to change at line 4991
*/ */
STRINGLIST *mail_thread_parse_references (char *s,long flag) STRINGLIST *mail_thread_parse_references (char *s,long flag)
{ {
char *t; char *t;
STRINGLIST *ret = NIL; STRINGLIST *ret = NIL;
STRINGLIST *cur; STRINGLIST *cur;
/* found first reference? */ /* found first reference? */
if (t = mail_thread_parse_msgid (s,&s)) { if (t = mail_thread_parse_msgid (s,&s)) {
(ret = mail_newstringlist ())->text.data = (unsigned char *) t; (ret = mail_newstringlist ())->text.data = (unsigned char *) t;
/* parse subsequent references */ ret->text.size = strlen (t);
if (flag) for (cur = ret; t = mail_thread_parse_msgid (s,&s); if (flag) /* parse subsequent references */
(cur = cur->next = mail_newstringlist ())->text.data = for (cur = ret; t = mail_thread_parse_msgid (s,&s); cur = cur->next)
(unsigned char *) t); {
(cur->next = mail_newstringlist ())->text.data = (unsigned char *) t
;
cur->next->text.size = strlen (t);
}
} }
return ret; return ret;
} }
/* Prune dummy messages /* Prune dummy messages
* Accepts: candidate container to prune * Accepts: candidate container to prune
* older sibling of container, if any * older sibling of container, if any
* Returns: container in this position, possibly pruned * Returns: container in this position, possibly pruned
* All children and younger siblings are also pruned * All children and younger siblings are also pruned
*/ */
skipping to change at line 5024 skipping to change at line 5219
} }
/* Parse flag list /* Parse flag list
* Accepts: MAIL stream * Accepts: MAIL stream
* flag list as a character string * flag list as a character string
* pointer to user flags to return * pointer to user flags to return
* Returns: system flags * Returns: system flags
*/ */
long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf) long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf)
{ {
char *t,*n,*s,tmp[MAILTMPLEN],flg[MAILTMPLEN]; char *t,*n,*s,tmp[MAILTMPLEN],msg[MAILTMPLEN];
short f = 0; short f = 0;
long i,j; long i,j;
*uf = 0; /* initially no user flags */ *uf = 0; /* initially no user flags */
if (flag && *flag) { /* no-op if no flag string */ if (flag && *flag) { /* no-op if no flag string */
/* check if a list and make sure valid */ /* check if a list and make sure valid */
if (((i = (*flag == '(')) ^ (flag[strlen (flag)-1] == ')')) || if (((i = (*flag == '(')) ^ (flag[strlen (flag)-1] == ')')) ||
(strlen (flag) >= MAILTMPLEN)) { (strlen (flag) >= MAILTMPLEN)) {
MM_LOG ("Bad flag list",ERROR); MM_LOG ("Bad flag list",ERROR);
return NIL; return NIL;
} }
/* copy the flag string w/o list construct * / /* copy the flag string w/o list construct * /
strncpy (n = tmp,flag+i,(j = strlen (flag) - (2*i))); strncpy (n = tmp,flag+i,(j = strlen (flag) - (2*i)));
tmp[j] = '\0'; tmp[j] = '\0';
while ((t = n) && *t) { /* parse the flags */ while ((t = n) && *t) { /* parse the flags */
i = 0; /* flag not known yet */
/* find end of flag */ /* find end of flag */
if (n = strchr (t,' ')) *n++ = '\0'; if (n = strchr (t,' ')) *n++ = '\0';
ucase (strcpy (flg,t)); if (*t == '\\') { /* system flag? */
if (flg[0] == '\\') { /* system flag? */ if (!compare_cstring (t+1,"SEEN")) f |= fSEEN;
switch (flg[1]) { /* dispatch based on first character */ else if (!compare_cstring (t+1,"DELETED")) f |= fDELETED;
case 'S': /* possible \Seen flag */ else if (!compare_cstring (t+1,"FLAGGED")) f |= fFLAGGED;
if (flg[2] == 'E' && flg[3] == 'E' && flg[4] == 'N' && !flg[5]) else if (!compare_cstring (t+1,"ANSWERED")) f |= fANSWERED;
i = fSEEN; else if (!compare_cstring (t+1,"DRAFT")) f |= fDRAFT;
break; else {
case 'D': /* possible \Deleted or \Draft flag */ sprintf (msg,"Unsupported system flag: %.80s",t);
if (flg[2] == 'E' && flg[3] == 'L' && flg[4] == 'E' && MM_LOG (msg,WARN);
flg[5] == 'T' && flg[6] == 'E' && flg[7] == 'D' && !flg[8])
i = fDELETED;
else if (flg[2] == 'R' && flg[3] == 'A' && flg[4] == 'F' &&
flg[5] == 'T' && !flg[6]) i = fDRAFT;
break;
case 'F': /* possible \Flagged flag */
if (flg[2] == 'L' && flg[3] == 'A' && flg[4] == 'G' &&
flg[5] == 'G' && flg[6] == 'E' && flg[7] == 'D' && !flg[8])
i = fFLAGGED;
break;
case 'A': /* possible \Answered flag */
if (flg[2] == 'N' && flg[3] == 'S' && flg[4] == 'W' &&
flg[5] == 'E' && flg[6] == 'R' && flg[7] == 'E' &&
flg[8] == 'D' && !flg[9]) i = fANSWERED;
break;
default: /* unknown */
break;
} }
if (i) f |= i; /* add flag to flags list */
} }
/* user flag, search through table */ else { /* keyword flag */
else for (j = 0; !i && j < NUSERFLAGS && (s =stream->user_flags[j]); for (i = j = 0; /* user flag, search through table */
++j) !i && (j < NUSERFLAGS) && (s = stream->user_flags[j]); ++j)
if (!compare_cstring (t,s)) *uf |= i = 1 << j; if (!compare_cstring (t,s)) *uf |= i = 1 << j;
if (!i) { /* didn't find a matching flag? */ if (!i) { /* flag not found, can it be created? */
if (*t == '\\') { if (stream->kwd_create && (j < NUSERFLAGS) &&
sprintf (flg,"Unsupported system flag: %.80s",t); (strlen (t) <= MAXUSERFLAG)) {
MM_LOG (flg,WARN); for (s = t; t && *s; s++) switch (*s) {
} default: /* all other characters */
/* can we create it? */
else if (stream->kwd_create && (j < NUSERFLAGS) &&
(strlen (t) <= MAXUSERFLAG)) {
for (s = t; t && *s; s++) switch (*s) {
default: /* all other characters */
/* SPACE, CTL, or not CHAR */ /* SPACE, CTL, or not CHAR */
if ((*s > ' ') && (*s < 0x7f)) break; if ((*s > ' ') && (*s < 0x7f)) break;
case '*': case '%': /* list_wildcards */ case '*': case '%': /* list_wildcards */
case '"': case '\\': /* quoted-specials */ case '"': case '\\':/* quoted-specials */
/* atom_specials */ /* atom_specials */
case '(': case ')': case '{': case '(': case ')': case '{':
sprintf (flg,"Invalid flag: %.80s",t); sprintf (msg,"Invalid flag: %.80s",t);
MM_LOG (flg,WARN); MM_LOG (msg,WARN);
t = NIL; t = NIL;
} }
if (t) { /* only if valid */ if (t) { /* only if valid */
*uf |= 1 << j; /* set the bit */ *uf |= 1 << j; /* set the bit */
stream->user_flags[j] = cpystr (t); stream->user_flags[j] = cpystr (t);
/* if out of user flags */ /* if out of user flags */
if (j == NUSERFLAGS - 1) stream->kwd_create = NIL; if (j == NUSERFLAGS - 1) stream->kwd_create = NIL;
}
}
else {
sprintf (msg,"Unknown flag: %.80s",t);
MM_LOG (msg,WARN);
} }
}
else {
sprintf (flg,"Unknown flag: %.80s",t);
MM_LOG (flg,WARN);
} }
} }
} }
} }
return f; return f;
} }
/* Mail check network stream for usability with new name /* Mail check network stream for usability with new name
* Accepts: MAIL stream * Accepts: MAIL stream
* candidate new name * candidate new name
* Returns: T if stream can be used, NIL otherwise * Returns: T if stream can be used, NIL otherwise
skipping to change at line 5659 skipping to change at line 5832
* argument count * argument count
* argument vector * argument vector
* Returns: authenticated user name or NIL * Returns: authenticated user name or NIL
*/ */
char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]) char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[])
{ {
AUTHENTICATOR *auth; AUTHENTICATOR *auth;
for (auth = mailauthenticators; auth; auth = auth->next) for (auth = mailauthenticators; auth; auth = auth->next)
if (auth->server && !compare_cstring (auth->name,mechanism)) if (auth->server && !compare_cstring (auth->name,mechanism))
return ((auth->flags & AU_SECURE) || return (!(auth->flags & AU_DISABLE) &&
!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)) ? ((auth->flags & AU_SECURE) ||
(*auth->server) (resp,argc,argv) : NIL; !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))) ?
(*auth->server) (resp,argc,argv) : NIL;
return NIL; /* no authenticator found */ return NIL; /* no authenticator found */
} }
/* Lookup authenticator index /* Lookup authenticator index
* Accepts: authenticator index * Accepts: authenticator index
* Returns: authenticator, or 0 if not found * Returns: authenticator, or 0 if not found
*/ */
AUTHENTICATOR *mail_lookup_auth (unsigned long i) AUTHENTICATOR *mail_lookup_auth (unsigned long i)
{ {
AUTHENTICATOR *auth = mailauthenticators; AUTHENTICATOR *auth = mailauthenticators;
skipping to change at line 5688 skipping to change at line 5862
* required authenticator flags * required authenticator flags
* Returns: index in authenticator chain, or 0 if not found * Returns: index in authenticator chain, or 0 if not found
*/ */
unsigned int mail_lookup_auth_name (char *mechanism,long flags) unsigned int mail_lookup_auth_name (char *mechanism,long flags)
{ {
int i; int i;
AUTHENTICATOR *auth; AUTHENTICATOR *auth;
for (i = 1, auth = mailauthenticators; auth; i++, auth = auth->next) for (i = 1, auth = mailauthenticators; auth; i++, auth = auth->next)
if (auth->client && !(flags & ~auth->flags) && if (auth->client && !(flags & ~auth->flags) &&
!compare_cstring (auth->name,mechanism)) !(auth->flags & AU_DISABLE) && !compare_cstring (auth->name,mechanis m))
return i; return i;
return 0; return 0;
} }
/* Standard TCP/IP network driver */ /* Standard TCP/IP network driver */
static NETDRIVER tcpdriver = { static NETDRIVER tcpdriver = {
tcp_open, /* open connection */ tcp_open, /* open connection */
tcp_aopen, /* open preauthenticated connection */ tcp_aopen, /* open preauthenticated connection */
tcp_getline, /* get a line */ tcp_getline, /* get a line */
tcp_getbuffer, /* get a buffer */ tcp_getbuffer, /* get a buffer */
 End of changes. 98 change blocks. 
218 lines changed or deleted 389 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/