diff options
Diffstat (limited to 'libmail/mboxadd.C')
| -rw-r--r-- | libmail/mboxadd.C | 243 | 
1 files changed, 243 insertions, 0 deletions
| diff --git a/libmail/mboxadd.C b/libmail/mboxadd.C new file mode 100644 index 0000000..7278da2 --- /dev/null +++ b/libmail/mboxadd.C @@ -0,0 +1,243 @@ +/* +** Copyright 2002-2006, Double Precision Inc. +** +** See COPYING for distribution information. +*/ +#include "libmail_config.h" +#include "mboxadd.H" +#include "mboxsighandler.H" +#include "file.H" + +#include <errno.h> +#include <pwd.h> +#include <time.h> + +#include <sys/types.h> +#include <sys/stat.h> + +using namespace std; + +mail::mbox::folder::add::add(mail::mbox &mboxArg, string pathArg, +					   mail::callback &callbackArg) +	: mail::addMessage(&mboxArg), path(pathArg), +	  callback(callbackArg), +	  fp(tmpfile()), +	  mboxAccount(&mboxArg) +{ +} + +mail::mbox::folder::add::~add() +{ +	if (fp) +		fclose(fp); +} + +void mail::mbox::folder::add::saveMessageContents(string msg) +{ +	if (*(msg.c_str()) == 0) +		return; + +	if (fp) +		if (fwrite(&msg[0], msg.size(), 1, fp) != 1) +			; // Ignore gcc warning +} + +void mail::mbox::folder::add::fail(string msg) +{ +	callback.fail(msg); +	delete this; +} + +void mail::mbox::folder::add::success(string msg) +{ +	callback.success(msg); +	delete this; +} + +void mail::mbox::folder::add::reportProgress(size_t bytesCompleted, +					     size_t bytesEstimatedTotal, +			     +					     size_t messagesCompleted, +					     size_t messagesEstimatedTotal) +{ +	callback.reportProgress(bytesCompleted, bytesEstimatedTotal, +				messagesCompleted, messagesEstimatedTotal); +} + +void mail::mbox::folder::add::go() +{ +	if (!fp) +		fail(strerror(errno)); + +	if (mboxAccount.isDestroyed()) +	{ +		fail("Server connection aborted"); +		return; +	} + +	try { +		if (path == mboxAccount->currentFolder) +		{ +			mboxAccount->installTask(new LockCurrentFolder( *this )); +		} +		else +		{ +			mboxAccount->installTask(new LockCurrentFolder( *this, +								 path)); +		} +	} catch (...) { +		fail("An exception occured while adding message."); +		return; +	} +} + +// +// Folder's now locked. +// + +void mail::mbox::folder::add::copyTo(mail::file &file) +{ +	struct stat st; + +	mail::mbox::sighandler updating(fileno(static_cast<FILE *>(file))); + +	try { + +		// Make sure the mboxAccount file ends with a trailing newline + +		if (fstat(fileno(static_cast<FILE *>(file)), &st) < 0) +		{ +			fail(strerror(errno)); +			return; +		} + +		int ch='\n'; + +		if (st.st_size > 0) +		{ +			if (fseek(file, -1, SEEK_END) < 0 || +			    (ch=getc(file)) == EOF) +			{ +				fail(strerror(errno)); +				return; +			} +		} + +		if (fseek(file, 0L, SEEK_END) < 0 || +		    fseek(fp, 0L, SEEK_SET) < 0) +		{ +			fail(strerror(errno)); +			return; +		} + +		if (ch != '\n') +			putc('\n', file); + +		mail::file f(fileno(fp), "w+"); + +		messageInfo.uid= mail::mboxMagicTag() +			.getMessageInfo().uid; + +		string hdr=mail::mboxMagicTag(messageInfo.uid, +					      messageInfo, + +					      mail::keywords::Message() +					      // KEYWORDS + +					      ).toString(); + +		struct passwd *pw; +		pw=getpwuid(getuid()); + +		fprintf(file, "From %s %s%s\n", +			pw ? pw->pw_name:"nobody", +			ctime(&messageDate), +			hdr.c_str()); + +		size_t bytesDone=0; +		size_t bytesNextReport=0; + +		while (!feof(f)) +		{ +			string l=f.getline(); + +			if (l.size() == 0 && feof(f)) +				break; + +			const char *p=l.c_str(); + +			while (*p == '>') +				p++; + +			if (strncmp(p, "From ", 5) == 0) +				l=">" + l; + +			l += "\n"; + +			if (fwrite(&l[0], l.size(), 1, file) != 1) +				; // Ignore gcc warning + +			bytesDone += l.size(); + +			if (bytesDone >= bytesNextReport) +			{ +				bytesNextReport=bytesDone + BUFSIZ; +				callback.reportProgress(bytesDone, 0, 0, 1); +			} +		} + +		if (fflush(file) < 0 || ferror(file)) +		{ +			updating.rollback(); +			fail(strerror(errno)); +			return; +		} + +		callback.reportProgress(bytesDone, bytesDone, 1, 1); +		updating.block(); +	} catch (...) { +		updating.rollback(); +		fail("An exception occured while adding message."); +		return; +	} + +	try { +		fclose(fp); +		fp=NULL; +		success("OK"); +	} catch (...) { +		delete this; +		LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); +	} +} + +/////////////////////////////////////////////////////////////////////////// + +mail::mbox::folder::add::LockCurrentFolder +::LockCurrentFolder(add &meArg, string pathArg) +	: LockTask(*meArg.mboxAccount, meArg, pathArg), me(meArg) +{ +} + +mail::mbox::folder::add::LockCurrentFolder::~LockCurrentFolder() +{ +} + + +bool mail::mbox::folder::add::LockCurrentFolder::locked(mail::file +							&lockedFile) +{ +	// If the current folder is opened in read-only mode, this is a no-go. + +	if (me.path == me.mboxAccount->currentFolder && mboxAccount.currentFolderReadOnly) +	{ +		me.fail("Folder opened in read-only mode."); +		done(); +		return true; +	} + +	me.copyTo(lockedFile); +	done(); +	return true; +} + | 
