diff options
Diffstat (limited to 'libmail/imapfolder.C')
| -rw-r--r-- | libmail/imapfolder.C | 3498 | 
1 files changed, 0 insertions, 3498 deletions
| diff --git a/libmail/imapfolder.C b/libmail/imapfolder.C deleted file mode 100644 index 7f00f35..0000000 --- a/libmail/imapfolder.C +++ /dev/null @@ -1,3498 +0,0 @@ -/* -** Copyright 2003-2004, Double Precision Inc. -** -** See COPYING for distribution information. -*/ -#include "libmail_config.h" -#include "imap.H" -#include "misc.H" -#include "imaphandler.H" -#include "imapidle.H" -#include "imapfetchhandler.H" -#include "imapfolder.H" -#include "imapparsefmt.H" - -#include "smapopen.H" -#include "smapidle.H" -#include "smapnoopexpunge.H" -#include "smapstore.H" -#include "smapcopy.H" -#include "smapsearch.H" - -#include "generic.H" -#include "copymessage.H" -#include "search.H" -#include "rfcaddr.H" -#include "envelope.H" -#include "structure.H" -#include "rfc822/rfc822.h" -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <sstream> -#include <limits.h> -#include <errno.h> - -using namespace std; - -mail::imapFOLDERinfo::imapFOLDERinfo(string pathArg, -				     mail::callback::folder &folderCallbackArg) -	: folderCallback(folderCallbackArg), -	  exists(0), closeInProgress(false), -	  path(pathArg) -{ -} - -mail::imapFOLDERinfo::~imapFOLDERinfo() -{ -} - - -mail::imapFOLDERinfo::indexInfo::indexInfo() -{ -} - -mail::imapFOLDERinfo::indexInfo::~indexInfo() -{ -} - -void mail::imapFOLDERinfo::setUid(size_t count, string uid) -{ -	if (count < index.size()) -		index[count].uid=uid; -} - -void mail::imapFOLDERinfo::opened() -{ -} - - -///////////////////////////////////////////////////////////////////////// -// -// Helper class for processing the SELECT command.  It's installed when -// a SELECT command is issued.  It handles the * FLAGS, * OK, and * NO -// untagged messages, during folder open, as well as the * n EXISTS message -// ( TODO - ignore any other garbage ) -// - -LIBMAIL_START - -class imapSELECT : public imapCommandHandler { - -	mail::callback &openCallback; -	mail::callback::folder &folderCallback; - -	string path; - -public: -	string uidv; -	size_t exists; - -	imapSELECT(string pathArg, -			 mail::callback &openCallbackArg, -			 mail::callback::folder &folderCallbackArg); - -	~imapSELECT(); - -	void installed(imap &imapAccount); -	static const char name[]; - -private: -	const char *getName(); -	void timedOut(const char *errmsg); - -	bool untaggedMessage(imap &imapAccount, string name); -	bool taggedMessage(imap &imapAccount, string name, -			   string message, -			   bool okfail, string errmsg); -}; - -LIBMAIL_END - -const char mail::imapSELECT::name[]="SELECT"; - -mail::imapSELECT::imapSELECT(string pathArg, -				   mail::callback &openCallbackArg, -				   mail::callback::folder &folderCallbackArg) -	: openCallback(openCallbackArg), -	  folderCallback(folderCallbackArg), path(pathArg), -	  uidv(""), exists(0) -{ -} - -mail::imapSELECT::~imapSELECT() -{ -} - -void mail::imapSELECT::installed(mail::imap &imapAccount) -{ -	imapAccount.imapcmd("SELECT", "SELECT " + -		     imapAccount.quoteSimple(path) + "\r\n"); - -	imapAccount.folderFlags.clear(); -	imapAccount.permanentFlags.clear(); -} - -const char *mail::imapSELECT::getName() -{ -	return name; -} - -void mail::imapSELECT::timedOut(const char *errmsg) -{ -	callbackTimedOut(openCallback, errmsg); -} - -// -// Helper class for processing the untagged FLAGS response -// - -LIBMAIL_START - -class imapSELECT_FLAGS : public imapHandlerStructured { - -	void (imapSELECT_FLAGS::*next_func)(imap &, Token t); - -public: -	imapSELECT_FLAGS(); -	~imapSELECT_FLAGS(); -	void installed(imap &imapAccount); - -private: -	const char *getName(); -	void timedOut(const char *errmsg); - -	void process(imap &imapAccount, Token t); -	void start_flags(imap &imapAccount, Token t); -	void process_flags(imap &imapAccount, Token t); -}; - -LIBMAIL_END - -mail::imapSELECT_FLAGS::imapSELECT_FLAGS() -	: next_func(&mail::imapSELECT_FLAGS::start_flags) -{ -} - -mail::imapSELECT_FLAGS::~imapSELECT_FLAGS() -{ -} - -void mail::imapSELECT_FLAGS::installed(mail::imap &imapAccount) -{ -} - -const char *mail::imapSELECT_FLAGS::getName() -{ -	return ("* FLAGS"); -} - -void mail::imapSELECT_FLAGS::timedOut(const char *errmsg) -{ -} - -void mail::imapSELECT_FLAGS::process(mail::imap &imapAccount, Token t) -{ -	(this->*next_func)(imapAccount, t); -} - -// -// Helper class for processing an untagged * #nnnn response during a SELECT -// - -LIBMAIL_START - -class imapSELECT_COUNT : public imapHandlerStructured { - -	imapSELECT &select; - -	void (imapSELECT_COUNT::*next_func)(imap &, Token t); - -	size_t count; - -public: -	imapSELECT_COUNT(imapSELECT &mySelect, -			       size_t myCount); -	~imapSELECT_COUNT(); -	void installed(imap &imapAccount); - -private: -	const char *getName(); -	void timedOut(const char *); -	void process(imap &imapAccount, Token t); -	void get_count(imap &imapAccount, Token t); -}; - -LIBMAIL_END - -mail::imapSELECT_COUNT::imapSELECT_COUNT(mail::imapSELECT &mySelect, -					       size_t myCount) -	: select(mySelect), -	  next_func(&mail::imapSELECT_COUNT::get_count), -	  count(myCount) -{ -} - -mail::imapSELECT_COUNT::~imapSELECT_COUNT() -{ -} - -void mail::imapSELECT_COUNT::installed(mail::imap &imapAccount) -{ -} - -const char *mail::imapSELECT_COUNT::getName() -{ -	return ("* #"); -} - -void mail::imapSELECT_COUNT::timedOut(const char *errmsg) -{ -} - -void mail::imapSELECT_COUNT::process(mail::imap &imapAccount, Token t) -{ -	(this->*next_func)(imapAccount, t); -} - -// -// Helper class for processing an untagged * OK response during a SELECT -// - -LIBMAIL_START - -class imapSELECT_OK : public imapHandler { - -	imapSELECT &select; -	string type; -public: -	imapSELECT_OK(imapSELECT &mySelect, -			    string typeArg); -	~imapSELECT_OK(); -	void installed(imap &imapAccount); - -private: -	const char *getName(); -	void timedOut(const char *errmsg); - -	int process(imap &imapAccount, string &buffer); -	void process(string &buffer); -}; - -LIBMAIL_END - -mail::imapSELECT_OK::imapSELECT_OK(mail::imapSELECT &mySelect, -					 string typeArg) -	: select(mySelect), type(typeArg) -{ -	upper(type); -} - -mail::imapSELECT_OK::~imapSELECT_OK() -{ -} - -void mail::imapSELECT_OK::installed(mail::imap &imapAccount) -{ -} - -const char *mail::imapSELECT_OK::getName() -{ -	return("* OK"); -} - -void mail::imapSELECT_OK::timedOut(const char *errmsg) -{ -} - -////////////////////////////////////////////////////////////////////////// -// -// After a SELECT, and any time * n EXISTS received, a SELECT FLAGS UID -// is automatically issued (either for the entire folder, or just the new -// messages).  When this command completes, the application callback methods -// will be invoked accordingly. -// - -LIBMAIL_START - -class imapSYNCHRONIZE : public imapCommandHandler { - -	mail::callback &callback; -  -	size_t fetchedCounter; - -	size_t newExists; - -public: -	static size_t counter; -	// Keeps track of the # of objects in existence. - -	imapSYNCHRONIZE(mail::callback &callbackArg); -	~imapSYNCHRONIZE(); - -	void installed(imap &imapAccount); - -	void fetchedUID(); - -private: -	const char *getName(); -	void timedOut(const char *errmsg); - -	bool untaggedMessage(imap &imapAccount, string name); -	bool taggedMessage(imap &imapAccount, string name, -			   string message, -			   bool okfail, string errmsg); -}; - -LIBMAIL_END - -const char *mail::imapSYNCHRONIZE::getName() -{ -	return("SYNC"); -} - -void mail::imapSYNCHRONIZE::timedOut(const char *errmsg) -{ -	callbackTimedOut(callback, errmsg); -} - -/////////////////////////////////////////////////////////////////////// -// -// Stub call from mail::imapFolder::open() -// - -void mail::imap::openFolder(string path, -			    mail::snapshot *restoreSnapshot, -			    mail::callback &openCallback, -			    mail::callback::folder &folderCallback) -{ -	if (!ready(openCallback)) -		return; - -	// If an existing folder is opened, tell the folder not to poll for -	// new mail any more. -	if (currentFolder) -		currentFolder->closeInProgress=true; - -	installForegroundTask(smap ? -			      (imapHandler *) -			      new mail::smapOPEN(path, -						 restoreSnapshot, -						 openCallback, -						 folderCallback) -			      : new mail::imapSELECT(path, openCallback, -						     folderCallback)); -} - -// -// A manually-requested NOOP. -// - -LIBMAIL_START - -class imapCHECKMAIL : public imapCommandHandler { - -	mail::callback &callback; - -public: -	imapCHECKMAIL(mail::callback &myCallback); -	~imapCHECKMAIL(); -	void installed(imap &imapAccount); - -	class dummyCallback : public mail::callback { -	public: -		dummyCallback(); -		~dummyCallback(); - -		void success(string); -		void fail(string); - -		void reportProgress(size_t bytesCompleted, -				    size_t bytesEstimatedTotal, - -				    size_t messagesCompleted, -				    size_t messagesEstimatedTotal); -	}; - -private: - -	const char *getName(); - -	void timedOut(const char *errmsg); - -	bool untaggedMessage(imap &imapAccount, string name); - -	bool taggedMessage(imap &imapAccount, string name, -			   string message, -			   bool okfail, string errmsg); -}; - -LIBMAIL_END - -mail::imapCHECKMAIL::imapCHECKMAIL(mail::callback &myCallback) -	: callback(myCallback) -{ -} - -mail::imapCHECKMAIL::~imapCHECKMAIL() -{ -} - -void mail::imapCHECKMAIL::installed(mail::imap &imapAccount) -{ -	imapAccount.imapcmd("NOOP2", "NOOP\r\n"); -} - -const char *mail::imapCHECKMAIL::getName() -{ -	return "NOOP2"; -} - -void mail::imapCHECKMAIL::timedOut(const char *errmsg) -{ -	callbackTimedOut(callback, errmsg); -} - -bool mail::imapCHECKMAIL::untaggedMessage(mail::imap &imapAccount, string name) -{ -	return false; -} - -bool mail::imapCHECKMAIL::taggedMessage(mail::imap &imapAccount, string name, -					string message, -					bool okfail, string errmsg) -{ - -	// The check for completion of a manual new mail check must be -	// done slightly differently.  That's because new mail -	// processing is handled by the regular new mail processing -	// objects, which don't really know anything about us. -	// If new mail processing got kicked off, there should be a -	// mail::imapSYNCHRONIZE object floating around somewhere. -	// If there is, what we do is we throw another checkNewMail -	// object in the queue, which should float to the beginning of -	// the queue after the current mail::imapSYNCHRONIZE object -	// goes away. - -	if (name == "NOOP2") -	{ -		if (mail::imapSYNCHRONIZE::counter == 0) -		{ -			callback.success("DONE"); -			imapAccount.uninstallHandler(this); -			return true; -		} - -		imapAccount.installForegroundTask(new -					   mail::imapCHECKMAIL(callback)); - -		imapAccount.uninstallHandler(this); -		return true; -	} - -	return false; -} - -mail::imapCHECKMAIL::dummyCallback::dummyCallback() -{ -} - -mail::imapCHECKMAIL::dummyCallback::~dummyCallback() -{ -} - -void mail::imapCHECKMAIL::dummyCallback::success(string dummy) -{ -	delete this; -} - -void mail::imapCHECKMAIL::dummyCallback::fail(string dummy) -{ -	delete this; -} - -void mail::imapCHECKMAIL -::dummyCallback::reportProgress(size_t bytesCompleted, -				size_t bytesEstimatedTotal, - -				size_t messagesCompleted, -				size_t messagesEstimatedTot) -{ -} - -void mail::imap::checkNewMail(mail::callback &callback) -{ -	if (!ready(callback)) -		return; - -	if (currentFolder) -		currentFolder->resetMailCheckTimer(); - -	installForegroundTask(smap ? -			      (imapHandler *)new smapNoopExpunge("NOOP", -								 callback, -								 *this) -			      : new mail::imapCHECKMAIL(callback)); -} - -void mail::imapFOLDER::resetMailCheckTimer() -{ -	// Reset the regular new mail checking interval -	setTimeout(mailCheckInterval); -} - -////////////////////////////////////////////////////////////////////////////// -// SELECT processing. - -bool mail::imapSELECT::untaggedMessage(mail::imap &imapAccount, string name) -{ -	if (name == "FLAGS") -	{ -		imapAccount.installBackgroundTask(new mail::imapSELECT_FLAGS() -						  ); -		return true; -	} -	if (name == "OK" || name == "NO") -	{ -		imapAccount.installBackgroundTask(new mail::imapSELECT_OK(*this, -								   name)); -		return true; -	} - -	if (isdigit((int)(unsigned char)*name.begin())) -	{ -		size_t c=0; - -		istringstream(name.c_str()) >> c; - -		imapAccount.installBackgroundTask(new mail::imapSELECT_COUNT(*this, -								      c)); -		return true; -	} - -	return false; -} - -void mail::imapSELECT_FLAGS::start_flags(mail::imap &imapAccount, Token t) -{ -	imapAccount.folderFlags.clear(); -	if (t == NIL) -	{ -		done(); -		return; -	} - -	if (t != '(') -		error(imapAccount); -	next_func= &mail::imapSELECT_FLAGS::process_flags; -} - -void mail::imapSELECT_FLAGS::process_flags(mail::imap &imapAccount, Token t) -{ -	if (t == ATOM) -	{ -		string name=t.text; - -		upper(name); -		imapAccount.folderFlags.insert(name); -		return; -	} - -	if (t != ')') -		error(imapAccount); -	done(); -} - -void mail::imapSELECT_COUNT::get_count(mail::imap &imapAccount, Token t) -{ -	if (t != ATOM) -		error(imapAccount); -	else -	{ -		if (strcasecmp(t.text.c_str(), "EXISTS") == 0) -		{ -			select.exists=count; - -			// Check against hostile servers - -			if (select.exists > UINT_MAX -			    / sizeof(mail::messageInfo)) -				select.exists=UINT_MAX -					/ sizeof(mail::messageInfo); -		} -	} -	done(); -} - -int mail::imapSELECT_OK::process(mail::imap &imapAccount, string &buffer) -{ -	size_t p=buffer.find('\n'); - -	if (p == std::string::npos) -	{ -		if (p + 16000 < buffer.size()) -			return buffer.size() - 16000; -		// SANITY CHECK - DON'T LET HOSTILE SERVER DOS us - -		return 0; -	} - -	string buffer_cpy=buffer; - -	buffer_cpy.erase(p); -	process(buffer_cpy); -	imapAccount.uninstallHandler(this); -	return p+1; -} - -void mail::imapSELECT_OK::process(string &buffer) -{ -	if (type != "OK") -		return; - -	string::iterator b=buffer.begin(), e=buffer.end(); - -	while (b != e && unicode_isspace((unsigned char)*b)) -		b++; - -	if (b == e || *b != '[') -		return; -	b++; - -	string w=mail::imap::get_word(&b, &e); - -	upper(w); - -	if (w == "UIDVALIDITY") // Memorize * OK [UIDVALIDITY] -	{ -		w=mail::imap::get_word(&b, &e); -		select.uidv=w; -	} -	else if (w == "PERMANENTFLAGS") -	{ -		myimap->setPermanentFlags(b, e); -	} -} - -// -// After an initial SELECT succeeds, even if the subsequent resynchronization -// commands fail, we still want to indicate success. -// - -LIBMAIL_START - -class imapSELECTCallback : public mail::callback { - -	mail::callback &origCallback; - -	void reportProgress(size_t bytesCompleted, -			    size_t bytesEstimatedTotal, - -			    size_t messagesCompleted, -			    size_t messagesEstimatedTotal); - -public: -	imapSELECTCallback(mail::callback &cb); -	~imapSELECTCallback(); -	void success(string msg); -	void fail(string msg); -}; -LIBMAIL_END - -bool mail::imapSELECT::taggedMessage(mail::imap &imapAccount, string name, -				     string message, -				     bool okfail, string errmsg) -{ -	if (name != "SELECT") -		return false; - -	if (okfail && uidv.length() == 0) -	{ -		okfail=false; -		errmsg="Server did not return the folder UID-validity token."; -	} - -	if (okfail) -	{ -		mail::imapFOLDER *f=new mail::imapFOLDER(path, uidv, exists, -							 folderCallback, -							 imapAccount); -		imapAccount.installBackgroundTask(f); -		imapAccount.currentFolder=f; - -		f->exists=0; - -		if (exists > 0) -		{ -			mail::imapSELECTCallback *cb= -				new mail::imapSELECTCallback(openCallback); - -			try { -				imapAccount.installForegroundTask -					(new mail::imapSYNCHRONIZE(*cb)); -			} catch (...) { -				delete cb; -			} -		} -		else -			openCallback.success("Empty folder."); -	} -	else -	{ -		imapAccount.currentFolder=NULL; -		openCallback.fail(errmsg); -	} -	imapAccount.uninstallHandler(this); -	return true; -} - -mail::imapSELECTCallback::imapSELECTCallback(mail::callback &cb) -	: origCallback(cb) -{ -} - -mail::imapSELECTCallback::~imapSELECTCallback() -{ -} - -void mail::imapSELECTCallback::success(string msg) -{ -	origCallback.success(msg); -	delete this; -} - -void mail::imapSELECTCallback::fail(string msg) -{ -	origCallback.success(msg); -	delete this; -} - -void mail::imapSELECTCallback::reportProgress(size_t bytesCompleted, -					      size_t bytesEstimatedTotal, - -					      size_t messagesCompleted, -					      size_t messagesEstimatedTotal) -{ -	origCallback.reportProgress(bytesCompleted, bytesEstimatedTotal, -				    messagesCompleted, -				    messagesEstimatedTotal); -} - -//////////////////////////////////////////////////////////////////////// -// -// Helper class to resynchronize a folder - - -size_t mail::imapSYNCHRONIZE::counter=0; - -mail::imapSYNCHRONIZE::imapSYNCHRONIZE(mail::callback &callbackArg) -	: callback(callbackArg), fetchedCounter(0) -{ -	++counter; -} - -void mail::imapSYNCHRONIZE::installed(mail::imap &imapAccount) -{ -	ostringstream o; - -	newExists=imapAccount.currentFolder ? -		imapAccount.currentFolder->index.size():0; - -	if (imapAccount.currentFolder == NULL || -	    imapAccount.currentFolder->exists >= newExists) -	{ -		imapAccount.currentFolder->exists=newExists; // Insurance - -		o << "NOOP\r\n"; -	} -	else -	{ - -		o << "FETCH " << (imapAccount.currentFolder->exists+1) -		  << ":" << newExists << " (UID FLAGS)\r\n"; - -	} - -	imapAccount.imapcmd("SYNC", o.str()); -	imapAccount.currentSYNCHRONIZE=this; -} - -mail::imapSYNCHRONIZE::~imapSYNCHRONIZE() -{ -	if (myimap) -		myimap->currentSYNCHRONIZE=NULL; -	--counter; -} - -void mail::imapSYNCHRONIZE::fetchedUID() -{ -	size_t c=myimap && myimap->currentFolder ? -		myimap->currentFolder->exists:0; - - -	if (c >= newExists) -		c=newExists; - -	if (fetchedCounter < newExists - c) -	{ -		++fetchedCounter; -		callback.reportProgress(0, 0, -					fetchedCounter, newExists - c); -	} -} - -bool mail::imapSYNCHRONIZE::untaggedMessage(mail::imap &imapAccount, string name) -{ -	return false; -} - -bool mail::imapSYNCHRONIZE::taggedMessage(mail::imap &imapAccount, string name, -					  string message, -					  bool okfail, string errmsg) -{ -	if (name != "SYNC") -		return false; - -	if (!okfail) -	{ -		callback.fail(errmsg); -		imapAccount.uninstallHandler(this); -		return true; -	} - -	mail::imapFOLDERinfo *f=imapAccount.currentFolder; - -	size_t n; - -	for (n=f->exists; n<f->index.size(); n++) -		if (f->index[n].uid.length() == 0) -		{ -			callback.fail("Server failed to respond with message identifier."); -			imapAccount.uninstallHandler(this); -			return true; -		} - -	if (f->exists < newExists) -		f->exists=newExists; - - -	callback.success("Folder index updated."); -	imapAccount.uninstallHandler(this); -	return true; -} - - -size_t mail::imap::getFolderIndexSize() -{ -	if (currentFolder == NULL) -		return 0; - -	return currentFolder->exists; -} - -mail::messageInfo mail::imap::getFolderIndexInfo(size_t n) -{ -	if (currentFolder  != NULL && n < currentFolder->exists) -		return currentFolder->index[n]; - -	return mail::messageInfo(); -} - -void mail::imap::getFolderKeywordInfo(size_t n, std::set<std::string> &kwset) -{ -	if (currentFolder != NULL && n < currentFolder->exists) -	{ -		currentFolder->index[n].keywords.getFlags(kwset); -	} -	else -		kwset.clear(); -} - -////////////////////////////////////////////////////////////////////////// -// -// Server replies when a folder is currently open. -// - -const char mail::imapFOLDER::name[]="FolderHandler"; - -// -// Helper class for processing an untagged * #nnnn response during a SELECT -// - -LIBMAIL_START - -class imapFOLDER_COUNT : public imapHandlerStructured { - -	void (imapFOLDER_COUNT::*next_func)(imap &, Token t); - -	size_t count; -	bool body_part_reference; // Fetch References: header -	string references_buf; -	vector<string> flags; - -	bool accept_largestring; - -	bool wantLargeString(); -public: -	imapFOLDER_COUNT(size_t myCount); -	~imapFOLDER_COUNT(); -	void installed(imap &imapAccount) {} -private: -	const char *getName(); -	void timedOut(const char *errmsg); -	void process(imap &imapAccount, Token t); - -	void get_count(imap &imapAccount, Token t); - -	void get_fetch(imap &imapAccount, Token t); -	void get_fetch_item(imap &imapAccount, Token t); -	void get_fetch_uid(imap &imapAccount, Token t); - -	void get_fetch_flags(imap &imapAccount, Token t); -	void get_fetch_flag(imap &imapAccount, Token t); -	void saveflags(imap &imapAccount); - -	void get_internaldate(imap &imapAccount, Token t); -	void get_rfc822size(imap &imapAccount, Token t); - -	void get_envelope(imap &imapAccount, Token t); -	void get_bodystructure(imap &imapAccount, Token t); -	void get_body(imap &imapAccount, Token t); - -	bool fillbodystructure(imap &imapAccount, imapparsefmt &parser, -			       mimestruct &bodystructure, -			       string mime_id); - -	imapparsefmt parser; -}; - -LIBMAIL_END - -mail::imapFOLDER::imapFOLDER(string pathArg, string uidvArg, size_t existsArg, -			     mail::callback::folder &folderCallbackArg, -			     mail::imap &myserver) -	: mail::imapCommandHandler(myserver.noopSetting), -	  imapFOLDERinfo(pathArg, folderCallbackArg), -	  existsNotify(NULL), -	  uidv(uidvArg) -{ -	mailCheckInterval=myserver.noopSetting; -	setBackgroundTask(true); -	index.resize(existsArg); -} - -mail::imapFOLDER::~imapFOLDER() -{ -	if (existsNotify) -		existsNotify->me=NULL; -} - -mail::imapFOLDER::existsCallback::existsCallback() -{ -} - -mail::imapFOLDER::existsCallback::~existsCallback() -{ -} - -void mail::imapFOLDER::existsCallback::success(string message) -{ -	if (me) -	{ -		mail::imapFOLDER *cb=me; -		me=NULL; -		cb->existsNotify=NULL; -		cb->folderCallback.newMessages(); -	} -	delete this; -} - -void mail::imapFOLDER::existsCallback -::reportProgress(size_t bytesCompleted, -		 size_t bytesEstimatedTotal, - -		 size_t messagesCompleted, -		 size_t messagesEstimatedTotal) -{ -} - -void mail::imapFOLDER::existsCallback::fail(string message) -{ -	if (me) -	{ -		mail::imapFOLDER *cb=me; -		me=NULL; -		cb->existsNotify=NULL; -		cb->folderCallback.newMessages(); -	} -	delete this; -} - -const char *mail::imapFOLDER::getName() -{ -	return name; -} - -void mail::imapFOLDER::installed(mail::imap &imapAccount) -{ -} - -void mail::imapFOLDER::timedOut(const char *errmsg) -{ -} - -int mail::imapFOLDER::getTimeout(mail::imap &imapAccount) -{ -	int t=mail::imapCommandHandler::getTimeout(imapAccount); - -	if (t == 0) -	{ -		setTimeout(t=imapAccount.noopSetting); - -		imapHandler *h; - -		if (!closeInProgress // Not closing the folder -		    && ((h=imapAccount.hasForegroundTask()) == NULL || -			strcmp(h->getName(), "IDLE") == 0)) -			// Something else is already in progress -		{ -			imapCHECKMAIL::dummyCallback *dummy= -				new imapCHECKMAIL::dummyCallback(); - -			if (!dummy) -				LIBMAIL_THROW((strerror(errno))); - -			try { -				imapAccount -					.installForegroundTask(new -							       imapCHECKMAIL -							       (*dummy)); -			} catch (...) { -				delete dummy; -				throw; -			} -		} -	} -	return t;	// This handler never causes a timeout -} - -bool mail::imapFOLDER::untaggedMessage(mail::imap &imapAccount, string name) -{ -	if (isdigit((int)(unsigned char)*name.begin())) -	{ -		if (imapAccount.handlers.count(mail::imapSELECT::name) > 0) -			return false;	// SELECT in progress -		size_t c=0; - -		istringstream(name.c_str()) >> c; - -		imapAccount.installBackgroundTask(new mail::imapFOLDER_COUNT(c)); -		return true; -	} - -	if (name == "FLAGS") -	{ -		imapAccount -			.installBackgroundTask(new mail::imapSELECT_FLAGS()); -		return true; -	} - -	return false; -} - -bool mail::imapFOLDER::taggedMessage(mail::imap &imapAccount, string name, -				     string message, -				     bool okfail, string errmsg) -{ -	return false; -} - - -mail::imapFOLDER_COUNT::imapFOLDER_COUNT(size_t myCount) -	: next_func(&mail::imapFOLDER_COUNT::get_count), -	  count(myCount), body_part_reference(false), -	  accept_largestring(false) -{ -} - -mail::imapFOLDER_COUNT::~imapFOLDER_COUNT() -{ -} - -bool mail::imapFOLDER_COUNT::wantLargeString() -{ -	return accept_largestring; -} - -const char *mail::imapFOLDER_COUNT::getName() -{ -	return ("* #"); -} - -void mail::imapFOLDER_COUNT::timedOut(const char *errmsg) -{ -} - -void mail::imapFOLDER_COUNT::process(mail::imap &imapAccount, Token t) -{ -	(this->*next_func)(imapAccount, t); -} - -// Seen * nnnnn - -void mail::imapFOLDER_COUNT::get_count(mail::imap &imapAccount, Token t) -{ -	if (t != ATOM) -	{ -		error(imapAccount); -		return; -	} - -	string name=t.text; - -	upper(name); -	if (name == "FETCH") -	{ -		next_func= &mail::imapFOLDER_COUNT::get_fetch; -		return; -	} - -	if (name == "EXPUNGE") -	{ -		done(); - -		if (imapAccount.currentFolder != NULL && count > 0 && -		    count <= imapAccount.currentFolder->index.size()) -		{ -			size_t c=count-1; - -			vector<imapFOLDERinfo::indexInfo> &indexRef= -				imapAccount.currentFolder->index; - -			indexRef.erase(indexRef.begin() + c, -				       indexRef.begin() + c + 1); - -			if (c < imapAccount.currentFolder->exists) -			{ -				--imapAccount.currentFolder->exists; - -				vector< pair<size_t, size_t> > a; - -				a.push_back(make_pair(c, c)); -				imapAccount.currentFolder->folderCallback -					.messagesRemoved(a); -			} -		} -		return; -	} -	if (name == "EXISTS") -	{ -		done(); - -		if (imapAccount.currentFolder != NULL && -		    !imapAccount.currentFolder->closeInProgress && -		    count > imapAccount.currentFolder->index.size()) -		{ -			imapAccount.currentFolder -				->existsMore(imapAccount, count); -		} -	} - -	done(); -} - -void mail::imapFOLDER::existsMore(mail::imap &imapAccount, size_t count) -{ -	if (closeInProgress) -		return; - -	if (exists > count) -		exists=count; - -	index.resize(count, imapFOLDERinfo::indexInfo()); - -	if (existsNotify) -		existsNotify->me=NULL; - -	existsNotify=new mail::imapFOLDER::existsCallback; - -	if (!existsNotify) -		LIBMAIL_THROW("Out of memory."); - -	existsNotify->me=this; - -	imapAccount -		.installForegroundTask(new mail::imapSYNCHRONIZE(*existsNotify) -				       ); -} - -void mail::imapFOLDER_COUNT::get_fetch(mail::imap &imapAccount, Token t) -{ -	if (t != '(') -		error(imapAccount); -	next_func= &mail::imapFOLDER_COUNT::get_fetch_item; -} - -void mail::imapFOLDER_COUNT::get_fetch_item(mail::imap &imapAccount, Token t) -{ -	accept_largestring=false; -	if (t == ')') -	{ -		done(); -		return; -	} - -	if (t != ATOM) -	{ -		error(imapAccount); -		return; -	} - -	string name=t.text; - -	upper(name); - -	if (name == "UID") -	{ -		next_func= &mail::imapFOLDER_COUNT::get_fetch_uid; -		return; -	} - -	if (name == "FLAGS") -	{ -		next_func= &mail::imapFOLDER_COUNT::get_fetch_flags; -		return; -	} - -	if (name == "INTERNALDATE") -	{ -		next_func= &mail::imapFOLDER_COUNT::get_internaldate; -		return; -	} - -	if (name == "RFC822.SIZE") -	{ -		next_func= &mail::imapFOLDER_COUNT::get_rfc822size; -		return; -	} - -	if (name == "ENVELOPE") -	{ -		parser.begin(); -		next_func= &mail::imapFOLDER_COUNT::get_envelope; -		return; -	} - -	if (name == "BODYSTRUCTURE") -	{ -		parser.begin(); -		next_func= &mail::imapFOLDER_COUNT::get_bodystructure; -		return; -	} - -	if (strncasecmp(name.c_str(), "BODY[", 5) == 0 || -	    strncasecmp(name.c_str(), "BODY.PEEK[", 10) == 0) -	{ -		accept_largestring=true; -		next_func= &mail::imapFOLDER_COUNT::get_body; - -		size_t i=name.find(']'); - -		if (i != name.length()-1) -		{ -			error(imapAccount); -			return; -		} -		name.erase(i); -		name.erase(0, name.find('[')+1); - -		body_part_reference=strncasecmp(name.c_str(), -						"HEADER.FIELDS", 13) == 0; -		references_buf=""; -		// Getting the References: header. -		return; -	} -			 -	error(imapAccount); -} - -void mail::imapFOLDER_COUNT::get_fetch_uid(mail::imap &imapAccount, Token t) -{ -	if (t != ATOM) -	{ -		error(imapAccount); -		return; -	} - -	if (imapAccount.currentFolder && count > 0) -		imapAccount.currentFolder->setUid(count-1, t.text); - -	// Report progress -	if (imapAccount.currentSYNCHRONIZE) -		imapAccount.currentSYNCHRONIZE->fetchedUID(); - -	next_func= &mail::imapFOLDER_COUNT::get_fetch_item; -} - -void mail::imapFOLDER::setUid(size_t count, string uid) -{ -	imapFOLDERinfo::setUid(count, uidv + "/" + uid); -} - -void mail::imapFOLDER_COUNT::get_fetch_flags(mail::imap &imapAccount, Token t) -{ -	flags.clear(); - -	if (t == NIL) -	{ -		saveflags(imapAccount); -		return; -	} - -	if (t != '(') -	{ -		error(imapAccount); -		return; -	} - -	next_func= &mail::imapFOLDER_COUNT::get_fetch_flag; -} - -void mail::imapFOLDER_COUNT::get_fetch_flag(mail::imap &imapAccount, Token t) -{ -	if (t == ')') -	{ -		saveflags(imapAccount); -		return; -	} - -	if (t != ATOM) -	{ -		error(imapAccount); -		return; -	} - -	flags.push_back(t.text); -} - -void mail::imapFOLDER_COUNT::saveflags(mail::imap &imapAccount) -{ -	next_func= &mail::imapFOLDER_COUNT::get_fetch_item; - -	if (imapAccount.currentFolder && count > 0 && -	    count <= imapAccount.currentFolder->index.size()) -	{ -		imapFOLDERinfo::indexInfo &i= -			imapAccount.currentFolder->index[count-1]; - -		if (imapAccount.folderFlags.count("\\DRAFT") > 0) -			i.draft=0; - -		if (imapAccount.folderFlags.count("\\ANSWERED") > 0) -			i.replied=0; - -		if (imapAccount.folderFlags.count("\\FLAGGED") > 0) -			i.marked=0; - -		if (imapAccount.folderFlags.count("\\DELETED") > 0) -			i.deleted=0; - -		if (imapAccount.folderFlags.count("\\SEEN") > 0) -			i.unread=1; - -		if (imapAccount.folderFlags.count("\\RECENT") > 0) -			i.recent=0; - -		size_t n; - -		mail::keywords::Message newMessage; - -		for (n=0; n<flags.size(); n++) -		{ -			string f=flags[n]; - -			upper(f); -			if (f == "\\DRAFT") -				i.draft=1; -			else if (f == "\\ANSWERED") -				i.replied=1; -			else if (f == "\\FLAGGED") -				i.marked=1; -			else if (f == "\\DELETED") -				i.deleted=1; -			else if (f == "\\SEEN") -				i.unread=0; -			else if (f == "\\RECENT") -				i.recent=1; -			else if (*flags[n].c_str() != '\\') -			{ -				if (!newMessage.addFlag(imapAccount -							.keywordHashtable, -							flags[n])) -					LIBMAIL_THROW(strerror(errno)); -			} -		} - -		i.keywords=newMessage; - -		if (count <= imapAccount.currentFolder->exists) -			imapAccount.currentFolder-> -				folderCallback.messageChanged(count-1); -	} -} - -static void parse_addr_list(mail::imapparsefmt *list, -			    vector<mail::address> &addresses) -{ -	vector<mail::imapparsefmt *>::iterator b=list->children.begin(), -		e=list->children.end(); - -	while (b != e) -	{ -		mail::imapparsefmt *address= *b; - -		if (address->children.size() >= 4) -		{ -			mail::imapparsefmt *name=address->children[0]; -			mail::imapparsefmt *mailbox=address->children[2]; -			mail::imapparsefmt *host=address->children[3]; - -			if (host->nil) -			{ -				if (mailbox->nil) -					addresses. -						push_back(mail::address(";", -									"")); -				else -					addresses. -						push_back(mail::address(mailbox -									->value -									+ ":", -									"")); -			} -			else -			{ -				addresses. -					push_back(mail::address(name->value, -								mailbox->value -								+ "@" + -								host->value)); -			} -		} -		b++; -	} -} - -static bool fillenvelope(mail::imapparsefmt &imapenvelope, -			 mail::envelope &envelope) -{ -	if (imapenvelope.children.size() < 10) -		return false; - -	vector<mail::imapparsefmt *>::iterator b=imapenvelope.children.begin(); - - -	envelope.date=rfc822_parsedt((*b)->value.c_str()); b++; - -	envelope.subject= (*b)->value; b++; - -	parse_addr_list(*b, envelope.from); b++; -	parse_addr_list(*b, envelope.sender); b++; -	parse_addr_list(*b, envelope.replyto); b++; -	parse_addr_list(*b, envelope.to); b++; -	parse_addr_list(*b, envelope.cc); b++; -	parse_addr_list(*b, envelope.bcc); b++; - -	envelope.inreplyto= (*b)->value; b++; -	envelope.messageid= (*b)->value; -	return true; -} - -void mail::imapFOLDER_COUNT::get_internaldate(mail::imap &imapAccount, Token t) -{ -	if (t != ATOM && t != STRING) -	{ -		error(imapAccount); -		return; -	} - -	if (imapAccount.currentFetch) -	{ -		// Make IMAP date presentable for rfc822_parsedt() by -		// replacing dd-mmm-yyyy with dd mmm yyyy - -		string d=t.text; - -		if (d[0] == ' ') -			d[0]='0'; - -		size_t spacepos=d.find(' '); -		size_t n; - -		while ((n=d.find('-')) < spacepos) -			d[n]=' '; - -		time_t tm=rfc822_parsedt(d.c_str()); - -		if (tm) -			imapAccount.currentFetch -				->messageArrivalDateCallback(count-1, tm); -	} - -	next_func= &mail::imapFOLDER_COUNT::get_fetch_item; -} - -void mail::imapFOLDER_COUNT::get_rfc822size(mail::imap &imapAccount, Token t) -{ -	if (t != ATOM) -	{ -		error(imapAccount); -		return; -	} - -	if (imapAccount.currentFetch) -	{ -		unsigned long msgsize=0; - -		istringstream(t.text.c_str()) >> msgsize; - -		imapAccount.currentFetch -			->messageSizeCallback(count-1, msgsize); -	} - -	next_func= &mail::imapFOLDER_COUNT::get_fetch_item; -} - -void mail::imapFOLDER_COUNT::get_envelope(mail::imap &imapAccount, Token t) -{ -	bool err_flag; - -	if (!parser.process(imapAccount, t, err_flag)) -		return;	// Not yet - -	next_func= &mail::imapFOLDER_COUNT::get_fetch_item; - -	mail::envelope envelope; - -	if (err_flag || !fillenvelope(parser, envelope)) -	{ -		error(imapAccount); -		return; -	} - -	if (imapAccount.currentFetch) -		imapAccount.currentFetch -			->messageEnvelopeCallback(count-1, envelope); -} - - -static void fill_type_parameters(mail::imapparsefmt *ptr, -				  mail::mimestruct &bodystructure) -{ -	vector<mail::imapparsefmt *>::iterator -		bb=ptr->children.begin(), -		ee=ptr->children.end(); - -	while (bb != ee) -	{ -		string name= (*bb)->value; bb++; - -		if (bb != ee) -		{ -			bodystructure.type_parameters. -				set_simple(name, (*bb)->value); -			bb++; -		} -	} -} - - -static void fill_disposition(mail::imapparsefmt *ptr, -			     mail::mimestruct &bodystructure) -{ -	if (ptr->children.size() > 0) -		bodystructure.content_disposition= -			ptr->children[0]->value; - -	if (ptr->children.size() < 2) -		return; - -	vector<mail::imapparsefmt *>::iterator -		bb=ptr->children[1]->children.begin(), -		ee=ptr->children[1]->children.end(); - -	while (bb != ee) -	{ -		string name= (*bb)->value; bb++; - -		if (bb != ee) -		{ -			bodystructure.content_disposition_parameters -				.set_simple(name, (*bb)->value); -			bb++; -		} -	} -} - -bool mail::imapFOLDER_COUNT::fillbodystructure(mail::imap &imapAccount, -					       mail::imapparsefmt &parser, -					       mail::mimestruct &bodystructure, -					       string mime_id) -{ -	vector<mail::imapparsefmt *>::iterator b=parser.children.begin(), -		e=parser.children.end(); - -	if (b == e) -	{ -		error(imapAccount); -		return false; -	} - -	if ( (*b)->children.size() == 0)  // Non-multipart -	{ - -		bodystructure.mime_id=mime_id; - -		if (mime_id.length() == 0) -			mime_id="1"; - -		bodystructure.type= (*b)->value; b++; - -		if (b != e) -		{ -			bodystructure.subtype= (*b)->value; -			b++; -		} - -		mail::upper(bodystructure.type); -		mail::upper(bodystructure.subtype); - -		if (b != e) -		{ -			fill_type_parameters( *b, bodystructure ); b++; -		} - -		if (b != e) -		{ -			bodystructure.content_id= (*b)->value; -			b++; -		} - -		if (b != e) -		{ -			bodystructure.content_description= (*b)->value; -			b++; -		} - -		if (b != e) -		{ -			bodystructure.content_transfer_encoding= (*b)->value; -			b++; -		} - -		if (b != e) -		{ -			istringstream((*b)->value.c_str()) >> -				bodystructure.content_size; -			b++; - -			if (bodystructure.messagerfc822()) -			{ -				if (b != e) -				{ -					if (!fillenvelope(**b, -							  bodystructure -							  .getEnvelope()) -					    ) -					{ -						error(imapAccount); -						return false; -					} - -					b++; -				} -				if (b != e) -				{ -					if ( (*b)->children.size() == 0) -						mime_id=mime_id + ".1"; - -					mail::mimestruct &child_struct= -						*bodystructure.addChild(); - -					if (!fillbodystructure(imapAccount, -							       **b, -							       child_struct, -							       mime_id)) -						return false; - -					if (child_struct.getNumChildren() == 0) -						child_struct.mime_id= -							mime_id + ".1"; -					// Fixup -				} - -				if (b != e) -				{ -					istringstream((*b)->value.c_str()) >> -						bodystructure.content_lines; -				} -			} -			else if (bodystructure.type == "TEXT") -			{ -				if (b != e) -				{ -					istringstream((*b)->value.c_str()) >> -						bodystructure.content_lines; -					b++; -				} -			} -		} - -		if (b != e) -		{ -			bodystructure.content_md5= (*b)->value; -			b++; -		} -	} -	else	// MULTIPART -	{ -		size_t body_num=1; - -		bodystructure.mime_id=mime_id; - -		if (mime_id.length() > 0) -			mime_id=mime_id+"."; -#if 0 -		else -			bodystructure.mime_id="1"; -#endif - -		while (b != e) -		{ -			if ( (*b)->children.size() == 0) -				break; - -			string buffer; -			{ -				ostringstream o; - -				o << body_num; -				buffer=o.str(); -			} -			body_num++; - -			if (!fillbodystructure(imapAccount, **b, -					       *bodystructure.addChild(), -					       mime_id + buffer)) -				return false; -			b++; -		} - -		bodystructure.type="MULTIPART"; -		bodystructure.subtype="MIXED"; - -		if (b != e) -		{ -			bodystructure.subtype= (*b)->value; -			b++; -		} - -		mail::upper(bodystructure.subtype); - -		if (b != e) -		{ -			fill_type_parameters( *b, bodystructure ); -			b++; -		} -	} - - -	if (b != e) -	{ -		fill_disposition( (*b), bodystructure ); -		b++; -	} - -	if (b != e) -	{ -		bodystructure.content_language= (*b)->value; -		b++; -	} - -	return true; -} - -void mail::imapFOLDER_COUNT::get_bodystructure(mail::imap &imapAccount, Token t) -{ -	bool err_flag; - -	if (!parser.process(imapAccount, t, err_flag)) -		return;	// Not yet - -	next_func= &mail::imapFOLDER_COUNT::get_fetch_item; - -	mail::mimestruct bodystructure; -	if (err_flag) -	{ -		error(imapAccount); -		return; -	} - -	if (!fillbodystructure(imapAccount, parser, bodystructure, "")) -		return; - -	if (imapAccount.currentFetch) -		imapAccount.currentFetch -			->messageStructureCallback(count-1, bodystructure); - -} - -void mail::imapFOLDER_COUNT::get_body(mail::imap &imapAccount, Token t) -{ -	if (t == STRING) -		next_func= &mail::imapFOLDER_COUNT::get_fetch_item; - -	if (t == STRING || t == LARGESTRING) -	{ -		string buf=t.text; - -		size_t cr; - -		while ((cr=buf.find('\r')) != std::string::npos) -			buf.erase(cr, 1); - -		if (imapAccount.currentFetch) -		{ -			imapAccount.currentFetch->messageTextEstimatedSize = -				t == LARGESTRING -				? largestringsize:t.text.size(); - -			imapAccount.currentFetch -				->messageTextCompleted += t.text.size(); - -			if (t == STRING) -			{ -				imapAccount.currentFetch->messageTextCompleted -					= imapAccount.currentFetch-> -					messageTextEstimatedSize; -				++imapAccount.currentFetch->messageCntDone; -			} - -			if (body_part_reference) -				// Processing References: header -			{ -				references_buf += buf; - -				while (references_buf.size() > 10000) -					// Prevent the server from DOssing us -				{ -					size_t n=references_buf.find('>'); - -					if (n != std::string::npos) -						++n; -					else n=references_buf.size()-10000; - -					references_buf -						.erase(references_buf.begin(), -						       references_buf.begin() -						       +n); -				} - -				if (t == STRING) -				{ -					vector<address> address_list; -					size_t err_index; - -					address::fromString(references_buf, -							    address_list, -							    err_index); - -					vector<string> msgid_list; - -					vector<address>::iterator -						b=address_list.begin(), -						e=address_list.end(); - -					while (b != e) -					{ -						string s=b->getAddr(); - -						if (s.size() > 0) -							msgid_list.push_back -								("<" + -								 s + ">"); -						++b; -					} - -					if (msgid_list.size() > 0) -						imapAccount.currentFetch-> -							messageReferencesCallback(count-1, msgid_list); -				} -			} -			else -				imapAccount.currentFetch -					->messageTextCallback(count-1, buf); -		} - -	} -	else -		error(imapAccount); -} - -///////////////////////////////////////////////////////////////////////////// -// -//  The STORE command. -// - -LIBMAIL_START - -class imapSTORE : public imapCommandHandler { - -	mail::callback &callback; - -	string storecmd; - -public: -	imapSTORE(mail::callback &callbackArg, string storecmdArg); -	~imapSTORE(); - -	void installed(imap &imapAccount); - -private: -	const char *getName(); -	void timedOut(const char *errmsg); - -	bool untaggedMessage(imap &imapAccount, string name); -	bool taggedMessage(imap &imapAccount, string name, -			   string message, -			   bool okfail, string errmsg); -}; - -LIBMAIL_END - -void mail::imapSTORE::timedOut(const char *errmsg) -{ -	callbackTimedOut(callback, errmsg); -} - -mail::imapSTORE::imapSTORE(mail::callback &callbackArg, -				 string storecmdArg) -	: callback(callbackArg), storecmd(storecmdArg) -{ -} - -mail::imapSTORE::~imapSTORE() -{ -} - -void mail::imapSTORE::installed(mail::imap &imapAccount) -{ -	imapAccount.imapcmd("STORE", storecmd + "\r\n"); -} - -const char *mail::imapSTORE::getName() -{ -	return "STORE"; -} - -bool mail::imapSTORE::untaggedMessage(mail::imap &imapAccount, string name) -{ -	return false; -} - -bool mail::imapSTORE::taggedMessage(mail::imap &imapAccount, string name, -				    string message, -				    bool okfail, string errmsg) -{ -	if (name == "STORE") -	{ -		if (okfail) -			callback.success(errmsg); -		else -			callback.fail(errmsg); -		imapAccount.uninstallHandler(this); -		return true; -	} -	return false; -} - -bool mail::imap::keywordAllowed(string kwName) -{ -	upper(kwName); - -	return permanentFlags.count(kwName) > 0 || -		permanentFlags.count("\\*") > 0; -} - -void mail::imap::saveFolderIndexInfo(size_t messageNum, -				     const mail::messageInfo &indexInfo, -				     mail::callback &callback) -{ -	if (!ready(callback)) -		return; - -	if (messageNum >= getFolderIndexSize()) -	{ -		callback.success("Invalid message number - ignored."); -		return; -	} - -	if (smap) -	{ -		string flags; - -#define FLAG -#define NOTFLAG ! -#define DOFLAG(NOT, field, name) \ -		if (NOT indexInfo.field) flags += "," name - -		LIBMAIL_SMAPFLAGS; -#undef DOFLAG -#undef NOTFLAG -#undef FLAG - -		if (flags.size() > 0) -			flags=flags.substr(1); - - -		installForegroundTask(new smapSTORE(messageNum, -						    "FLAGS=" + flags, -						    *this, -						    callback)); -		return; -	} - -	bool fakeUpdateFlag; - -	string flags=messageFlagStr(indexInfo, -				    ¤tFolder->index[messageNum], -				    &fakeUpdateFlag); - -	{ -		set<string> oflags; -		currentFolder->index[messageNum].keywords.getFlags(oflags); - -		set<string>::iterator b=oflags.begin(), e=oflags.end(); - -		while (b != e) -		{ -			if (keywordAllowed(*b)) -			{ -				if (flags.size() > 0) -					flags += " "; -				flags += *b; -			} - -			++b; -		} -	} - -	string messageNumBuffer; - -	{ -		ostringstream o; - -		o << "STORE " << (messageNum+1) << " FLAGS ("; -		messageNumBuffer=o.str(); -	} - -	installForegroundTask(new mail::imapSTORE(callback, -						  messageNumBuffer -						  + flags + ")")); - -	if (fakeUpdateFlag && messageNum < currentFolder->exists) -		currentFolder->folderCallback.messageChanged(messageNum); -} - -///////////////////////////////////////////////////////////////////////// -// -//  A STORE for a list may be broken up into multiple commands. -//  Count the number of tagged STORE acknowledgments received, and run the -//  app callback only after the last STORE ack comes in. - -LIBMAIL_START - -class imapUpdateFlagsCallback : public mail::callback { - -	mail::callback &origCallback; - -	void reportProgress(size_t bytesCompleted, -			    size_t bytesEstimatedTotal, - -			    size_t messagesCompleted, -			    size_t messagesEstimatedTotal); - -public: -	imapUpdateFlagsCallback(mail::callback &callback); -	~imapUpdateFlagsCallback(); - -	void success(string message); -	void fail(string message); - -	bool failFlag; -	string message; - -	size_t cnt; -}; - -LIBMAIL_END - -mail::imapUpdateFlagsCallback::imapUpdateFlagsCallback(mail::callback -							     &callback) -	: origCallback(callback), -	  failFlag(false), message(""), cnt(0) -{ -} - -mail::imapUpdateFlagsCallback::~imapUpdateFlagsCallback() -{ -} - -void mail::imapUpdateFlagsCallback::success(string message) -{ -	// If any failures were received, the app fail() callback will be -	// invoked. - -	if (!failFlag) -		this->message=message; - -	if (--cnt == 0) -	{ -		if (failFlag) -			origCallback.fail(message); -		else -			origCallback.success(message); -		delete this; -	} -} - -void mail::imapUpdateFlagsCallback::fail(string message) -{ -	this->message=message; -	failFlag=true; -	success(message); -} - -void mail::imapUpdateFlagsCallback -::reportProgress(size_t bytesCompleted, -		 size_t bytesEstimatedTotal, - -		 size_t messagesCompleted, -		 size_t messagesEstimatedTotal) -{ -	origCallback.reportProgress(bytesCompleted, -				    bytesEstimatedTotal, -				    messagesCompleted, -				    messagesEstimatedTotal); -} - -void mail::imap::updateFolderIndexFlags(const vector<size_t> &messages, -					bool doFlip, -					bool enableDisable, -					const mail::messageInfo &flags, -					mail::callback &callback) -{ -	if (doFlip) -	{ -		mail::imapUpdateFlagsCallback *myCallback= -			new mail::imapUpdateFlagsCallback(callback); - -		if (!myCallback) -		{ -			callback.fail("Out of memory."); -			return; -		} - -		// -		// Very ugly, but this is the cleanest ugly solution. -		// For each flipped flag, segregate messages whose -		// flag should be turned on, and ones that should be -		// turned off, and issue a separate STORE for each set. -		// Lather, rinse, repeat, for all flags. -		// - -		try { - -#define DOFLAG(NOT, field, name) { \ -		vector<size_t> enabled, disabled;\ -\ -		vector<size_t>::const_iterator b=messages.begin(),\ -			e=messages.end();\ -\ -		while (b != e)\ -		{\ -			size_t n= *b++;\ -\ -			if (n >= getFolderIndexSize())\ -				continue;\ -\ -			mail::messageInfo &info=currentFolder->index[n];\ -\ -			if ( flags.field ) \ -			{ \ -				if (info.field)\ -					disabled.push_back(n);\ -				else\ -					enabled.push_back(n);\ -			}\ -		}\ -\ -		mail::messageInfo oneFlag;\ -\ -		oneFlag.field=true;\ -		++myCallback->cnt;\ -		updateFolderIndexFlags(enabled, true, oneFlag, *myCallback);\ -		++myCallback->cnt;\ -		updateFolderIndexFlags(disabled, false, oneFlag, *myCallback);\ -		} - -			++myCallback->cnt; -#define NOTFLAG -#define FLAG -			LIBMAIL_MSGFLAGS; -#undef NOTFLAG -#undef FLAG -#undef DOFLAG -			myCallback->success("Success"); - -		} catch (...) { -			delete myCallback; - -			callback.fail("An exception occured in updateFolderIndexFlags()"); -		} -		return; -	} - -	updateFolderIndexFlags(messages, enableDisable, flags, callback); -} - -LIBMAIL_START - -class imapMessageCallbackStub : public mail::callback::message { - -	mail::callback &origCallback; - -	void reportProgress(size_t bytesCompleted, -			    size_t bytesEstimatedTotal, - -			    size_t messagesCompleted, -			    size_t messagesEstimatedTotal); - -public: -	imapMessageCallbackStub(mail::callback &callbackArg); -	~imapMessageCallbackStub(); - -	void success(string message); -	void fail(string message); -}; - -LIBMAIL_END - -mail::imapMessageCallbackStub -::imapMessageCallbackStub(mail::callback &callbackArg) -	: origCallback(callbackArg) -{ -} - -mail::imapMessageCallbackStub::~imapMessageCallbackStub() -{ -} - -void mail::imapMessageCallbackStub::success(string message) -{ -	origCallback.success(message); -	delete this; -} - -void mail::imapMessageCallbackStub::fail(string message) -{ -	origCallback.fail(message); -	delete this; -} - -void mail::imapMessageCallbackStub -::reportProgress(size_t bytesCompleted, -		 size_t bytesEstimatedTotal, -		 size_t messagesCompleted, -		 size_t messagesEstimatedTotal) -{ -	origCallback.reportProgress(bytesCompleted, bytesEstimatedTotal, -				    messagesCompleted, messagesEstimatedTotal); -} - -void mail::imap::updateFolderIndexFlags(const vector<size_t> &messages, -					bool enableDisable, -					const mail::messageInfo &flags, -					mail::callback &callback) -{ -	if (smap) -	{ -		const char *plus="+FLAGS="; -		const char *minus="-FLAGS="; - - -		string lista; -		string listb; - -#define FLAG lista -#define NOTFLAG listb -#define DOFLAG(FLAG, field, name) \ -		if (flags.field) FLAG += "," name - -		LIBMAIL_SMAPFLAGS; -#undef DOFLAG -#undef NOTFLAG -#undef FLAG - -		if (lista.size() > 0) -			lista=(enableDisable ? plus:minus) -				+ lista.substr(1); - -		if (listb.size() > 0) -			listb=(enableDisable ? minus:plus) -				+ listb.substr(1); - - -		installForegroundTask(new smapSTORE(messages, -						    lista + " " + listb, -						    *this, -						    callback)); -		return; -	} - -	const char *plusminus=NULL; - -	string name=""; -	 -#define DOFLAG(MARK, field, n)  if ( flags.field ) { plusminus=MARK; name += " " n; } -#define FLAG "+-" -#define NOTFLAG "-+" - -	LIBMAIL_MSGFLAGS; - -#undef FLAG -#undef NOTFLAG -#undef DOFLAG - -	if (!plusminus || messages.size() == 0) -	{ -		callback.success("Ok"); -		return; -	} - -	name=name.substr(1); - -	char buf[2]; - -	buf[0]=plusminus[enableDisable ? 0:1]; -	buf[1]=0; - -	mail::imapMessageCallbackStub *c= -		new mail::imapMessageCallbackStub(callback); - -	if (!c) -	{ -		callback.fail("Out of memory."); -		return; -	} - -	try { -		messagecmd(messages, string(" ") -			   + buf + "FLAGS (" + name + ")", -			   "UID STORE", "STORE", *c); -	} catch (...) { -		delete c; -		LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); -	} -} - -class mail::imap::updateImapKeywordHelper : public mail::callback { - -	mail::callback *origCallback; -	mail::ptr<mail::imap> myimap; - -public: -	set<string> newflags; -	set<string> uids; - -	updateImapKeywordHelper(mail::callback *origCallbackArg, -				mail::imap *myimapArg); -	~updateImapKeywordHelper(); - -	void success(std::string message); -	void fail(std::string message); - -	void reportProgress(size_t bytesCompleted, -			    size_t bytesEstimatedTotal, - -			    size_t messagesCompleted, -			    size_t messagesEstimatedTotal); -}; - - - -void mail::imap::updateKeywords(const vector<size_t> &messages, -				const set<string> &keywords, -				bool setOrChange, -				// false: set, true: see changeTo -				bool changeTo, -				callback &cb) -{ -	set<string>::const_iterator b=keywords.begin(), e=keywords.end(); - -	while (b != e) -	{ -		string::const_iterator sb=b->begin(), se=b->end(); - -		while (sb != se) -		{ -			if (strchr(smap ? ",\t\r\n,":"() \t\r\n[]{}\\\"", *sb)) -			{ -				cb.fail("Invalid flag"); -				return; -			} -			++sb; -		} -		++b; -	} - -	b=keywords.begin(); -	e=keywords.end(); - -	if (smap) -	{ -		string setCmd= setOrChange ? changeTo -			? "+KEYWORDS=":"-KEYWORDS=":"KEYWORDS="; - -		const char *comma=""; - -		while (b != e) -		{ -			setCmd += comma; -			setCmd += *b; -			++b; -			comma=","; -		} - -		installForegroundTask(new smapSTORE(messages, -						    quoteSMAP(setCmd), -						    *this, cb)); -		return; -	} - -	if (!setOrChange) -	{ -		updateImapKeywordHelper *h= -			new updateImapKeywordHelper(&cb, this); - -		if (!h) -		{ -			cb.fail(strerror(errno)); -			return; -		} - -		try { -			h->newflags=keywords; - -			map<string, string> allFlags; -			// Keyed by upper(name), value=name -			// (be nice, and preserve casing when turning off -			// flags). - -			vector<size_t>::const_iterator mb=messages.begin(), -				me=messages.end(); - -			while (mb != me) -			{ -				size_t n= *mb; - -				++mb; - -				if (n >= currentFolder->index.size()) -					continue; - -				h->uids.insert(currentFolder->index[n].uid); -				set<string> tempSet; - -				currentFolder->index[n].keywords -					.getFlags(tempSet); - -				set<string>::iterator -					tsb=tempSet.begin(), -					tse=tempSet.end(); - -				while (tsb != tse) -				{ -					string flagName= *tsb; - -					// IMAP kws are case insensitive - -					mail::upper(flagName); -					allFlags.insert(make_pair(flagName, -								  *tsb)); -					++tsb; -				} -			} - -			b=keywords.begin(); -			e=keywords.end(); - -			while (b != e) -			{ -				string flagName= *b; -				++b; - -				mail::upper(flagName); -				allFlags.erase(flagName); -				// No need to remove flags that are going to be -				// set anyway. -			} - -			if (allFlags.empty()) -				h->success("Ok - no keywords changed."); -			// Nothing to turn off, so punt it. -			else -			{ -				set<string> allFlagsV; - -				map<string, string>::iterator b= -					allFlags.begin(), e=allFlags.end(); - -				while (b != e) -				{ -					allFlagsV.insert(b->second); -					++b; -				} - -				allFlags.clear(); - -				updateImapKeywords(messages, allFlagsV, -						   false, *h); -			} -		} catch (...) { -			delete h; -		} -		return; -	} - -	updateImapKeywords(messages, keywords, changeTo, cb); -} - -mail::imap::updateImapKeywordHelper -::updateImapKeywordHelper(mail::callback *origCallbackArg, -			  mail::imap *myimapArg) -	: origCallback(origCallbackArg), myimap(myimapArg) -{ -} - -mail::imap::updateImapKeywordHelper::~updateImapKeywordHelper() -{ -	if (origCallback) -		origCallback->fail("Aborted."); -} - -void mail::imap::updateImapKeywordHelper::success(std::string message) -{ -	vector<size_t> msgSet; - -	mail::imapFOLDERinfo *f=myimap.isDestroyed() ? NULL: -		myimap->currentFolder; - -	size_t n=f ? f->index.size():0; -	size_t i; - -	for (i=0; i<n; i++) -		if (uids.count(f->index[i].uid) > 0) -			msgSet.push_back(i); - -	try { -		myimap->updateImapKeywords(msgSet, newflags, true, -					   *origCallback); -		origCallback=NULL; -		delete this; -	} catch (...) { -		delete this; -	} -} - -void mail::imap::updateImapKeywordHelper::fail(std::string message) -{ -	mail::callback *c=origCallback; -	origCallback=NULL; -	delete this; - -	c->fail(message); -} - -void mail::imap::updateImapKeywordHelper -::reportProgress(size_t bytesCompleted, -		 size_t bytesEstimatedTotal, -		 size_t messagesCompleted, -		 size_t messagesEstimatedTotal) -{ -} - -void mail::imap::updateImapKeywords(const vector<size_t> &messages, -				    const set<string> &keywords, -				    bool changeTo, -				    callback &cb) -{ -	set<string>::const_iterator b=keywords.begin(), e=keywords.end(); -	string setCmd= changeTo	? " +FLAGS (":" -FLAGS ("; -	const char *space=""; - -	while (b != e) -	{ -		string flagname= *b; - -		if (!keywordAllowed(flagname)) -		{ -			vector<size_t>::const_iterator mb, me; - -			mb=messages.begin(); -			me=messages.end(); - -			while (mb != me) -			{ -				size_t n= *mb; -				++mb; - -				if (n >= (currentFolder ? -					  currentFolder->index.size():0)) -					continue; - -				if (changeTo) -				{ -					if (!currentFolder->index[n] -					    .keywords.addFlag(keywordHashtable, -							      flagname)) -					{ -						LIBMAIL_THROW(strerror(errno)); -					} -				} -				else -				{ -					if (!currentFolder->index[n].keywords -					    .remFlag(flagname)) -						LIBMAIL_THROW(strerror(errno)); -				} -			} -			++b; -			continue; -		} - -		setCmd += space; -		setCmd += *b; -		++b; -		space=" "; -	} - -	if (*space == 0) -	{ -		MONITOR(mail::imap); - -		vector<size_t>::const_iterator mb, me; - -		mb=messages.begin(); -		me=messages.end(); - -		while (!DESTROYED() && mb != me) -		{ -			size_t n= *--me; - -			if (n >= (currentFolder ? -				  currentFolder->index.size():0)) -				continue; - -			currentFolder->folderCallback.messageChanged(n); -		} - -		cb.success("Ok."); -		return; -	} - - -	mail::imapMessageCallbackStub *c= -		new mail::imapMessageCallbackStub(cb); - -	if (!c) -	{ -		cb.fail("Out of memory."); -		return; -	} - -	try { -		messagecmd(messages, setCmd + ")", -			   "UID STORE", "STORE", *c); -	} catch (...) { -		delete c; -		LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); -	} -} - -/////////////////////////////////////////////////////////////////////////// - - -void mail::imap::copyMessagesTo(const vector<size_t> &messages, -				mail::folder *copyTo, -				mail::callback &callback) -{ -	sameServerFolderPtr=NULL; - -	copyTo->sameServerAsHelperFunc(); - -	if (!sameServerFolderPtr) -	{ -		// Copy to some other server, use a generic function. - -		mail::copyMessages::copy(this, messages, copyTo, callback); -		return; -	} - -	if (smap) -	{ -		installForegroundTask(new smapCOPY(messages, copyTo, -						   *this, -						   callback, "COPY")); -		return; -	} - -	mail::imapMessageCallbackStub *c= -		new mail::imapMessageCallbackStub(callback); - -	if (!c) -	{ -		callback.fail("Out of memory."); -		return; -	} - -	try { -		messagecmd(messages, " " + quoteSimple(copyTo->getPath()), -			   "UID COPY", "COPY", *c); -	} catch (...) { -		delete c; -		LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); -	} - -} - -void mail::imap::moveMessagesTo(const vector<size_t> &messages, -				mail::folder *copyTo, -				mail::callback &callback) -{ -	sameServerFolderPtr=NULL; - -	copyTo->sameServerAsHelperFunc(); - -	if (smap && sameServerFolderPtr) -	{ -		installForegroundTask(new smapCOPY(messages, copyTo, -						   *this, -						   callback, "MOVE")); -		return; -	} -	 -	generic::genericMoveMessages(this, messages, copyTo, callback); -} - -/////////////////////////////////////////////////////////////////////////// -// -//  The search command. - -LIBMAIL_START - -class imapSEARCH : public imapCommandHandler { - -	string searchCmd; -	bool hasStringArg; -	string stringArg; - -	mail::searchCallback &callback; - -	vector<size_t> found; - -	class SearchResults : public imapHandlerStructured { -		vector<size_t> &found; -	public: -		SearchResults(vector<size_t> &); -		~SearchResults(); - -		void installed(imap &imapAccount); -	private: -		const char *getName(); -		void timedOut(const char *errmsg); - -		void process(imap &imapAccount, Token t); -	}; - -public: -	imapSEARCH(string searchCmdArg, -			 bool hasParam2, -			 string param2Arg, -			 mail::searchCallback &callbackArg); -	~imapSEARCH(); - -	void installed(imap &); -	const char *getName(); -	void timedOut(const char *errmsg); - -	bool untaggedMessage(imap &imapAccount, string name); -	bool taggedMessage(imap &imapAccount, string name, -			   string message, -			   bool okfail, string errmsg); -	bool continuationRequest(imap &imapAccount, string request); -}; - -LIBMAIL_END - -mail::imapSEARCH::imapSEARCH(string searchCmdArg, -				   bool hasParam2, -				   string param2Arg, -				   mail::searchCallback &callbackArg) -	: searchCmd(searchCmdArg), -	  hasStringArg(hasParam2), -	  stringArg(param2Arg), -	  callback(callbackArg) -{ -} - -mail::imapSEARCH::~imapSEARCH() -{ -} - -void mail::imapSEARCH::installed(mail::imap &imapAccount) -{ -	if (hasStringArg) -	{ -		string::iterator b=stringArg.begin(), e=stringArg.end(); - -		while (b != e) -		{ -			if (*b < ' ' || *b >= 127) -				break; -			b++; -		} - -		if (b == e) -			searchCmd += mail::imap::quoteSimple(stringArg); -		else -		{ -			ostringstream o; - -			o << "{" << stringArg.size() << "}"; - -			searchCmd += o.str(); -		} -	} -	imapAccount.imapcmd("SEARCH", "SEARCH " + searchCmd + "\r\n"); -} - -// -// High-8 search string must be sent via a literal. -// - -bool mail::imapSEARCH::continuationRequest(mail::imap &imapAccount, string request) -{ -	imapAccount.socketWrite(stringArg + "\r\n"); -	return true; -} - -const char *mail::imapSEARCH::getName() -{ -	return "SEARCH"; -} - -void mail::imapSEARCH::timedOut(const char *errmsg) -{ -	callback.fail(errmsg); -} - -bool mail::imapSEARCH::untaggedMessage(mail::imap &imapAccount, string name) -{ -	if (name == "SEARCH") -	{ -		imapAccount.installBackgroundTask(new SearchResults(found)); -		return true; -	} -	return false; -} - -bool mail::imapSEARCH::taggedMessage(mail::imap &imapAccount, string name, -				     string message, -				     bool okfail, string errmsg) -{ -	if (name != "SEARCH") -		return false; - -	if (okfail) -		callback.success(found); -	else -		callback.fail(errmsg); - -	imapAccount.uninstallHandler(this); -	return true; -} - -mail::imapSEARCH::SearchResults::SearchResults(vector <size_t> &foundArg) -	: found(foundArg) -{ -} - -mail::imapSEARCH::SearchResults::~SearchResults() -{ -} - -void mail::imapSEARCH::SearchResults::installed(mail::imap &imapAccount) -{ -} - -const char *mail::imapSEARCH::SearchResults::getName() -{ -	return "* SEARCH"; -} - -void mail::imapSEARCH::SearchResults::timedOut(const char *errmsg) -{ -} - -void mail::imapSEARCH::SearchResults::process(mail::imap &imapAccount, Token t) -{ -	if (t == EOL) -		return; - -	if (t != ATOM) -	{ -		error(imapAccount); -		return; -	} - -	size_t n=0; - -	istringstream i(t.text.c_str()); - -	i >> n; - -	if (n == 0 || imapAccount.currentFolder == NULL -	    || n > imapAccount.currentFolder->index.size()) -	{ -		error(imapAccount); -		return; -	} - -	found.push_back(n-1); -} - -void mail::imap::searchMessages(const class mail::searchParams &searchInfo, -				class mail::searchCallback &callback) -{ -	if (smap) -	{ -		installForegroundTask(new mail::smapSEARCH(searchInfo, -							   callback, -							   *this)); -		return; -	} - -	if (folderFlags.count("\\FLAGGED") == 0) -	{ -		// Server doesn't implement \Flagged, do everything by hand - -		mail::searchMessages::search(callback, searchInfo, this); -		return; -	} - -	string cmd=""; - -	if (searchInfo.charset.size() > 0) -		cmd="CHARSET " + quoteSimple(searchInfo.charset) + " "; - -	switch (searchInfo.scope) { - -	case searchParams::search_all: -		cmd += "ALL"; -		break; - -	case searchParams::search_unmarked: -		cmd += "ALL NOT FLAGGED"; -		break; - -	case searchParams::search_marked: -		cmd += "ALL FLAGGED"; -		break; -	case searchParams::search_range: - -		{ -			ostringstream o; - -			o << searchInfo.rangeLo+1 << ':' -			  << searchInfo.rangeHi; - -			cmd += o.str(); -		} -		break; -	} - -	bool notFlag=searchInfo.searchNot; - -	if (searchInfo.criteria == searchInfo.unread) -		notFlag= !notFlag; - -	if (notFlag) -		cmd += " NOT"; - -	string sizeNumStr=""; - -	switch (searchInfo.criteria) { -	case searchParams::larger: -	case searchParams::smaller: - -		{ -			unsigned long sizeNum=0; - -			istringstream i(searchInfo.param2.c_str()); - -			i >> sizeNum; - -			if (i.fail()) -			{ -				callback.fail("Invalid message size string."); -				return; -			} - -			string buffer; - -			{ -				ostringstream o; - -				o << sizeNum; -				buffer=o.str(); -			} - -			sizeNumStr=buffer; -		} -		break; -	default: -		break; -	} - -	string param2=""; -	bool hasParam2=false; - -	string::const_iterator b, e; - -	switch (searchInfo.criteria) { -	case searchParams::replied: -		cmd += " ANSWERED"; -		break; -	case searchParams::deleted: -		cmd += " DELETED"; -		break; -	case searchParams::draft: -		cmd += " DRAFT"; -		break; -	case searchParams::unread: -		cmd += " SEEN"; -		break; - -		// Header match -		 -	case searchParams::from: -		cmd += " FROM "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::to: -		cmd += " TO "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::cc: -		cmd += " CC "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::bcc: -		cmd += " BCC "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::subject: -		cmd += " SUBJECT "; hasParam2=true; param2=searchInfo.param2; -		break; - -	case searchParams::header: - -		b=searchInfo.param1.begin(); -		e=searchInfo.param1.end(); - -		while (b != e) -		{ -			if (*b < ' '|| *b >= 127) -			{ -				callback.fail("Invalid header name."); -				return; -			} -		} - -		cmd += " HEADER " + quoteSimple(searchInfo.param1) -			+ " "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::body: -		cmd += " BODY "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::text: -		cmd += " TEXT "; hasParam2=true; param2=searchInfo.param2; -		break; - -		// Internal date: - -	case searchParams::before: -		cmd += " BEFORE "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::on:     -		cmd += " ON "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::since: -		cmd += " SINCE "; hasParam2=true; param2=searchInfo.param2; -		break; - -		// Sent date: - -	case searchParams::sentbefore: -		cmd += " SENTBEFORE "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::senton: -		cmd += " SENTON "; hasParam2=true; param2=searchInfo.param2; -		break; -	case searchParams::sentsince: -		cmd += " SENTSINCE "; hasParam2=true; param2=searchInfo.param2; -		break; - -	case searchParams::larger: -		cmd += " LARGER " + sizeNumStr; -		break; -	case searchParams::smaller: -		cmd += " SMALLER " + sizeNumStr; -		break; -	default: -		callback.fail("Unknown search criteria."); -		return; -	} - -	installForegroundTask(new mail::imapSEARCH(cmd, hasParam2, param2, -						   callback)); -} - - -/////////////////////////////////////////////////////////////////////////// -// -// Convert flags in mail::messageInfo to IMAP flag names. -// For those flags that are not supported on the server, update the -// flags in the folder index manually, and set the flagsUpdated flag. - -string mail::imap::messageFlagStr(const mail::messageInfo &indexInfo, -				  mail::messageInfo *oldIndexInfo, -				  bool *flagsUpdated) -{ -	string flags=""; - -	if (flagsUpdated) -		*flagsUpdated=false; - -#define DOFLAG(NOT, field, name) \ -	if (oldIndexInfo == NULL /* APPEND assumes all flags are present */ ||\ -			folderFlags.count( name ) > 0)\ -	{\ -		if (NOT indexInfo.field)\ -			flags += " " name;\ -	}\ -	else if ( oldIndexInfo->field != indexInfo.field)\ -	{\ -		oldIndexInfo->field=indexInfo.field;\ -		*flagsUpdated=true;\ -	} - -#define FLAG -#define NOTFLAG ! - -	LIBMAIL_MSGFLAGS; - -#undef FLAG -#undef DOFLAG -#undef NOTFLAG - - -	if (flags.size() > 0) -		flags=flags.substr(1); - -	return flags; -} - -//////////////////////////////////////////////////////////////////////////// -// -// The IMAP EXPUNGE command. - -LIBMAIL_START - -class imapEXPUNGE : public imapCommandHandler { - -	mail::callback &callback; - -public: -	imapEXPUNGE(mail::callback &callbackArg); -	~imapEXPUNGE(); - -	void installed(imap &imapAccount); - -private: -	const char *getName(); -	void timedOut(const char *errmsg); - -	bool untaggedMessage(imap &imapAccount, string name); -	bool taggedMessage(imap &imapAccount, string name, -			   string message, -			   bool okfail, string errmsg); -}; - -LIBMAIL_END - -mail::imapEXPUNGE::imapEXPUNGE(mail::callback &callbackArg) -	: callback(callbackArg) -{ -} - -void mail::imapEXPUNGE::timedOut(const char *errmsg) -{ -	callbackTimedOut(callback, errmsg); -} - -mail::imapEXPUNGE::~imapEXPUNGE() -{ -} - -void mail::imapEXPUNGE::installed(mail::imap &imapAccount) -{ -	imapAccount.imapcmd("EXPUNGE", "EXPUNGE\r\n"); -} - -const char *mail::imapEXPUNGE::getName() -{ -	return "EXPUNGE"; -} - -bool mail::imapEXPUNGE::untaggedMessage(mail::imap &imapAccount, string name) -{ -	return false; -} - -bool mail::imapEXPUNGE::taggedMessage(mail::imap &imapAccount, string name, -				      string message, -				      bool okfail, string errmsg) -{ -	if (name == "EXPUNGE") -	{ -		if (okfail) -			callback.success(errmsg); -		else -			callback.fail(errmsg); -		imapAccount.uninstallHandler(this); -		return true; -	} -	return false; -} - -void mail::imap::updateNotify(bool enableDisable, callback &callbackArg) -{ -	if (!ready(callbackArg)) -		return; - -	wantIdleMode=enableDisable; -	updateNotify(&callbackArg); -} - -void mail::imap::updateNotify(callback *callbackArg) -{ -	if (!smap && (!hasCapability("IDLE") || noIdle)) -	{ -		if (callbackArg) -			callbackArg->success("Ok"); -		return; -	} - -	installForegroundTask(smap ? -			      (imapHandler *)new smapIdleHandler(wantIdleMode, -								 callbackArg): -			      new imapIdleHandler(wantIdleMode, callbackArg)); -} - -void mail::imap::updateFolderIndexInfo(mail::callback &callback) -{ -	if (!ready(callback)) -		return; - -	installForegroundTask(smap ? -			      (imapHandler *)new smapNoopExpunge("EXPUNGE", -								 callback, -								 *this) -			      : new mail::imapEXPUNGE(callback)); -} - -////////////////////////////////////////////////////////////////////////// -// -// UID EXPUNGE - -//////////////////////////////////////////////////////////////////////////// -// -// The IMAP EXPUNGE command. - -LIBMAIL_START - -class imapUIDEXPUNGE : public mail::callback::message { - -	set<string> uids; - -	ptr<mail::imap> acct; -	mail::callback &callback; - -	bool uidSent; - -public: - -	imapUIDEXPUNGE(mail::imap &imapAccount, -		       mail::callback &callbackArg, -		       const vector<size_t> &msgs); -	~imapUIDEXPUNGE(); - -	void mkVector(mail::imap &, vector<size_t> &); - -private: -	void success(string msg); -	void fail(string msg); - -	void reportProgress(size_t bytesCompleted, -			    size_t bytesEstimatedTotal, - -			    size_t messagesCompleted, -			    size_t messagesEstimatedTotal); - -}; - -LIBMAIL_END - -mail::imapUIDEXPUNGE::imapUIDEXPUNGE(mail::imap &imapAccount, -				     mail::callback &callbackArg, -				     const vector<size_t> &msgs) -	: acct(&imapAccount), callback(callbackArg), uidSent(false) -{ -	vector<size_t>::const_iterator b, e; - -	for (b=msgs.begin(), e=msgs.end(); b != e; b++) -	{ -		if (imapAccount.currentFolder && -		    *b < imapAccount.currentFolder->index.size()) -			uids.insert(imapAccount.currentFolder -				    ->index[*b].uid); -	} -} - -mail::imapUIDEXPUNGE::~imapUIDEXPUNGE() -{ -} - -void mail::imapUIDEXPUNGE::mkVector(mail::imap &imapAccount, -				    vector<size_t> &vec) -{ -	if (imapAccount.currentFolder) -	{ -		size_t i; - -		for (i=0; i<imapAccount.currentFolder->exists; i++) -		{ -			if (uids.count(imapAccount.currentFolder -				       ->index[i].uid) > 0) -				vec.push_back(i); -		} -	} -} - -void mail::imapUIDEXPUNGE::success(string dummy) -{ -	if (acct.isDestroyed() || uidSent) -	{ -		callback.success(dummy); -		delete this; -		return; -	} - -	vector<size_t> vec; - -	mkVector(*acct, vec); - -	if (vec.size() == 0) -	{ -		mail::callback * volatile c= &callback; - -		delete this; - -		c->fail(dummy); -		return; -	} - -	uidSent=true; -	acct->messagecmd(vec, "", "UID EXPUNGE", "EXPUNGE", *this); -} - -void mail::imapUIDEXPUNGE::reportProgress(size_t bytesCompleted, -					  size_t bytesEstimatedTotal, - -					  size_t messagesCompleted, -					  size_t messagesEstimatedTotal) -{ -} - -void mail::imapUIDEXPUNGE::fail(string dummy) -{ -	mail::callback * volatile c= &callback; - -	delete this; - -	c->fail(dummy); -} - -void mail::imap::removeMessages(const std::vector<size_t> &messages, -				callback &cb) -{ -	if (!ready(cb)) -		return; - -	if (smap) -	{ -		installForegroundTask(new smapNoopExpunge(messages, cb, -							  *this)); -		return; -	} - -	if (!hasCapability("UIDPLUS")) -	{ -		mail::generic::genericRemoveMessages(this, messages, cb); -		return; -	} - -	imapUIDEXPUNGE *exp=new imapUIDEXPUNGE(*this, cb, messages); - -	try { -		vector<size_t> msgs; - -		exp->mkVector(*this, msgs); - -		if (msgs.size() == 0) -		{ -			delete exp; -			exp=NULL; - -			cb.success("OK"); -			return; -		} - -		messagecmd(msgs, " +FLAGS.SILENT (\\Deleted)", -			   "UID STORE", "STORE", *exp); -	} catch (...) { -		if (exp) -			delete exp; - -		cb.fail("An exception occured in removeMessages"); -		return; -	} -} | 
