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/ |