diff options
| author | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-04-30 00:33:56 +0200 | 
|---|---|---|
| committer | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-04-30 00:33:56 +0200 | 
| commit | aa4d426b4d3527d7e166df1a05058c9a4a0f6683 (patch) | |
| tree | 4ff17ce8b89a2321b9d0ed4bcfc37c447bcb6820 /vmime-master/src/vmime/net/maildir | |
| download | smtps-and-pop3s-console-program-master.tar.gz smtps-and-pop3s-console-program-master.zip | |
Diffstat (limited to 'vmime-master/src/vmime/net/maildir')
23 files changed, 5244 insertions, 0 deletions
| diff --git a/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp new file mode 100644 index 0000000..e611949 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp @@ -0,0 +1,569 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/format/courierMaildirFormat.hpp" + +#include "vmime/net/maildir/maildirStore.hpp" +#include "vmime/net/maildir/maildirUtils.hpp" + +#include "vmime/platform.hpp" + + +namespace vmime { +namespace net { +namespace maildir { +namespace format { + + +courierMaildirFormat::courierMaildirFormat(const shared_ptr <context>& ctx) +	: maildirFormat(ctx) { + +} + + +const string courierMaildirFormat::getName() const { + +	return "courier"; +} + + +void courierMaildirFormat::createFolder(const folder::path& path) { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) { +		throw exceptions::invalid_folder_name(); +	} + +	shared_ptr <utility::file> rootDir = fsf->create( +		folderPathToFileSystemPath(path, ROOT_DIRECTORY) +	); + +	shared_ptr <utility::file> newDir = fsf->create( +		folderPathToFileSystemPath(path, NEW_DIRECTORY) +	); +	shared_ptr <utility::file> tmpDir = fsf->create( +		folderPathToFileSystemPath(path, TMP_DIRECTORY) +	); +	shared_ptr <utility::file> curDir = fsf->create( +		folderPathToFileSystemPath(path, CUR_DIRECTORY) +	); + +	rootDir->createDirectory(true); + +	newDir->createDirectory(false); +	tmpDir->createDirectory(false); +	curDir->createDirectory(false); + +	shared_ptr <utility::file> maildirFile = fsf->create( +		folderPathToFileSystemPath(path, ROOT_DIRECTORY) +		 	/ utility::file::path::component("maildirfolder") +	); + +	maildirFile->createFile(); +} + + +void courierMaildirFormat::destroyFolder(const folder::path& path) { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	// Recursively delete directories of subfolders +	const std::vector <folder::path> folders = listFolders(path, true); + +	for (std::vector <folder::path>::size_type i = 0, n = folders.size() ; i < n ; ++i) { + +		maildirUtils::recursiveFSDelete( +			fsf->create(folderPathToFileSystemPath(folders[i], ROOT_DIRECTORY)) +		); +	} + +	// Recursively delete the directory of this folder +	maildirUtils::recursiveFSDelete( +		fsf->create(folderPathToFileSystemPath(path, ROOT_DIRECTORY)) +	); +} + + +void courierMaildirFormat::renameFolder( +	const folder::path& oldPath, +	const folder::path& newPath +) { + +	const std::vector <folder::path> folders = listFolders(oldPath, true); + +	for (std::vector <folder::path>::size_type i = 0, n = folders.size() ; i < n ; ++i) { + +		const folder::path folderOldPath = folders[i]; + +		folder::path folderNewPath = folderOldPath; +		folderNewPath.renameParent(oldPath, newPath); + +		renameFolderImpl(folderOldPath, folderNewPath); +	} + +	renameFolderImpl(oldPath, newPath); +} + + +void courierMaildirFormat::renameFolderImpl( +	const folder::path& oldPath, +	const folder::path& newPath +) { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	const utility::file::path oldFSPath = +		folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY); + +	const utility::file::path newFSPath = +		folderPathToFileSystemPath(newPath, ROOT_DIRECTORY); + +	shared_ptr <utility::file> rootDir = fsf->create(oldFSPath); +	rootDir->rename(newFSPath); +} + + +bool courierMaildirFormat::folderExists(const folder::path& path) const { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	shared_ptr <utility::file> rootDir = fsf->create( +		folderPathToFileSystemPath(path, ROOT_DIRECTORY) +	); + +	shared_ptr <utility::file> newDir = fsf->create( +		folderPathToFileSystemPath(path, NEW_DIRECTORY) +	); +	shared_ptr <utility::file> tmpDir = fsf->create( +		folderPathToFileSystemPath(path, TMP_DIRECTORY) +	); +	shared_ptr <utility::file> curDir = fsf->create( +		folderPathToFileSystemPath(path, CUR_DIRECTORY) +	); + +	shared_ptr <utility::file> maildirFile = fsf->create( +		folderPathToFileSystemPath(path, ROOT_DIRECTORY) +		 	/ utility::file::path::component("maildirfolder") +	); + +	bool exists = rootDir->exists() && rootDir->isDirectory() && +	              newDir->exists() && newDir->isDirectory() && +	              tmpDir->exists() && tmpDir->isDirectory() && +	              curDir->exists() && curDir->isDirectory(); + +	// If this is not the root folder, then a file named "maildirfolder" +	// must also be present in the directory +	if (!path.isRoot()) { +		exists = exists && maildirFile->exists() && maildirFile->isFile(); +	} + +	return exists; +} + + +bool courierMaildirFormat::folderHasSubfolders(const folder::path& path) const { + +	std::vector <string> dirs; +	return listDirectories(path, dirs, true); +} + + +const utility::file::path courierMaildirFormat::folderPathToFileSystemPath( +	const folder::path& path, +	const DirectoryType type +) const { + +	// Virtual folder "/MyFolder/SubFolder" corresponds to physical +	// directory "[store root]/.MyFolder.SubFolder" +	utility::file::path fsPath = getContext()->getStore()->getFileSystemPath(); + +	if (!path.isRoot()) { + +		string folderComp; + +		for (size_t i = 0, n = path.getSize() ; i < n ; ++i) { +			folderComp += "." + toModifiedUTF7(path[i]); +		} + +		fsPath /= utility::file::path::component(folderComp); +	} + +	// Last component +	switch (type) { + +		case ROOT_DIRECTORY: + +			// Nothing to add +			break; + +		case NEW_DIRECTORY: + +			fsPath /= NEW_DIR; +			break; + +		case CUR_DIRECTORY: + +			fsPath /= CUR_DIR; +			break; + +		case TMP_DIRECTORY: + +			fsPath /= TMP_DIR; +			break; + +		case CONTAINER_DIRECTORY: + +			// Not used +			break; +	} + +	return fsPath; +} + + +const std::vector <folder::path> courierMaildirFormat::listFolders( +	const folder::path& root, +	const bool recursive +) const { + +	// First, list directories +	std::vector <string> dirs; +	listDirectories(root, dirs, false); + +	// Then, map directories to folders +	std::vector <folder::path> folders; + +	for (std::vector <string>::size_type i = 0, n = dirs.size() ; i < n ; ++i) { + +		const string dir = dirs[i].substr(1) + "."; +		folder::path path; + +		for (size_t pos = dir.find("."), prev = 0 ; +		     pos != string::npos ; prev = pos + 1, pos = dir.find(".", pos + 1)) { + +			const string comp = dir.substr(prev, pos - prev); +			path /= fromModifiedUTF7(comp); +		} + +		if (recursive || path.getSize() == root.getSize() + 1) { +			folders.push_back(path); +		} +	} + +	return folders; +} + + +bool courierMaildirFormat::listDirectories( +	const folder::path& root, +	std::vector <string>& dirs, +	const bool onlyTestForExistence +) const { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	shared_ptr <utility::file> rootDir = fsf->create( +		getContext()->getStore()->getFileSystemPath() +	); + +	if (rootDir->exists()) { + +		// To speed up things, and if we are not searching in root folder, +		// search for directories with a common prefix +		string base; + +		if (!root.isRoot()) { +			for (size_t i = 0, n = root.getSize() ; i < n ; ++i) { +				base += "." + toModifiedUTF7(root[i]); +			} +		} + +		// Enumerate directories +		shared_ptr <utility::fileIterator> it = rootDir->getFiles(); + +		while (it->hasMoreElements()) { + +			shared_ptr <utility::file> file = it->nextElement(); + +			if (isSubfolderDirectory(*file)) { + +				const string dir = file->getFullPath().getLastComponent().getBuffer(); + +				if (base.empty() || (dir.length() > base.length() && dir.substr(0, base.length()) == base)) { + +					dirs.push_back(dir); + +					if (onlyTestForExistence) { +						return true; +					} +				} +			} +		} + +	} else { + +		// No sub-folder +	} + +	std::sort(dirs.begin(), dirs.end()); + +	return !dirs.empty(); +} + + +// static +bool courierMaildirFormat::isSubfolderDirectory(const utility::file& file) { + +	// A directory which names starts with '.' may be a subfolder +	if (file.isDirectory() && +	    file.getFullPath().getLastComponent().getBuffer().length() >= 1 && +	    file.getFullPath().getLastComponent().getBuffer()[0] == '.') { + +		return true; +	} + +	return false; +} + + +// static +const string courierMaildirFormat::toModifiedUTF7(const folder::path::component& text) { + +	// From http://www.courier-mta.org/?maildir.html: +	// +	// Folder names can contain any Unicode character, except for control +	// characters. US-ASCII characters, U+0x0020 - U+0x007F, except for the +	// period, forward-slash, and ampersand characters (U+0x002E, U+0x002F, +	// and U+0x0026) represent themselves. The ampersand is represented by +	// the two character sequence "&-". The period, forward slash, and non +	// US-ASCII Unicode characters are represented using the UTF-7 character +	// set, and encoded with a modified form of base64-encoding. +	// +	// The "&" character starts the modified base64-encoded sequence; the +	// sequence is terminated by the "-" character. The sequence of 16-bit +	// Unicode characters is written in big-endian order, and encoded using +	// the base64-encoding method described in section 5.2 of RFC 1521, with +	// the following modifications: +	// +	// * The "=" padding character is omitted. When decoding, an incomplete +	//   16-bit character is discarded. +	// +	// * The comma character, "," is used in place of the "/" character in +	//   the base64 alphabet. +	// +	// For example, the word "Resume" with both "e"s being the e-acute +	// character, U+0x00e9, is encoded as "R&AOk-sum&AOk-" (so a folder of +	// that name would be a maildir subdirectory called ".R&AOk-sum&AOk-"). +	// + +	// Transcode path component to UTF-7 charset. +	// WARNING: This may throw "exceptions::charset_conv_error" +	const string cvt = text.getConvertedText(charset(charsets::UTF_7)); + +	// Transcode to modified UTF-7 (RFC-2060). +	string out; +	out.reserve((cvt.length() * 3) / 2); + +	bool inB64sequence = false; + +	for (string::const_iterator it = cvt.begin() ; it != cvt.end() ; ++it) { + +		const unsigned char c = *it; + +		switch (c) { + +			// Beginning of Base64 sequence: replace '+' with '&' +			case '+': { + +				if (!inB64sequence) { +					inB64sequence = true; +					out += '&'; +				} else { +					out += '+'; +				} + +				break; +			} +			// End of Base64 sequence +			case '-': { + +				inB64sequence = false; +				out += '-'; +				break; +			} +			// ',' is used instead of '/' in modified Base64, +			// and simply UTF7-encoded out of a Base64 sequence +			case '/': { + +				if (inB64sequence) { +					out += ','; +				} else { +					out += "&Lw-"; +				} + +				break; +			} +			// Encode period (should not happen in a Base64 sequence) +			case '.': { + +				out += "&Lg-"; +				break; +			} +			// '&' (0x26) is represented by the two-octet sequence "&-" +			case '&': { + +				if (!inB64sequence) { +					out += "&-"; +				} else { +					out += '&'; +				} + +				break; +			} +			default: { + +				out += c; +				break; +			} +		} +	} + +	return out; +} + + +// static +const folder::path::component courierMaildirFormat::fromModifiedUTF7(const string& text) { + +	// Transcode from modified UTF-7 +	string out; +	out.reserve(text.length()); + +	bool inB64sequence = false; +	unsigned char prev = 0; + +	for (string::const_iterator it = text.begin() ; it != text.end() ; ++it) { + +		const unsigned char c = *it; + +		switch (c) { + +			// Start of Base64 sequence +			case '&': { + +				if (!inB64sequence) { +					inB64sequence = true; +					out += '+'; +				} else { +					out += '&'; +				} + +				break; +			} +			// End of Base64 sequence (or "&-" --> "&") +			case '-': { + +				if (inB64sequence && prev == '&') { +					out += '&'; +				} else { +					out += '-'; +				} + +				inB64sequence = false; +				break; +			} +			// ',' is used instead of '/' in modified Base64 +			case ',': { + +				out += (inB64sequence ? '/' : ','); +				break; +			} +			default: { + +				out += c; +				break; +			} + +		} + +		prev = c; +	} + +	// Store it as UTF-8 by default +	string cvt; +	charset::convert(out, cvt, charset(charsets::UTF_7), charset(charsets::UTF_8)); + +	return folder::path::component(cvt, charset(charsets::UTF_8)); +} + + +bool courierMaildirFormat::supports() const { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	shared_ptr <utility::file> rootDir = fsf->create( +		getContext()->getStore()->getFileSystemPath() +	); + +	if (rootDir->exists()) { + +		// Try to find a file named "maildirfolder", which indicates +		// the Maildir is in Courier format +		shared_ptr <utility::fileIterator> it = rootDir->getFiles(); + +		while (it->hasMoreElements()) { + +			shared_ptr <utility::file> file = it->nextElement(); + +			if (isSubfolderDirectory(*file)) { + +				shared_ptr <utility::file> folderFile = fsf->create( +					file->getFullPath() / utility::file::path::component("maildirfolder") +				); + +				if (folderFile->exists() && folderFile->isFile()) { +					return true; +				} +			} +		} +	} + +	return false; +} + + +} // format +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + diff --git a/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp new file mode 100644 index 0000000..7db1a83 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp @@ -0,0 +1,127 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED +#define VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirFormat.hpp" + + +namespace vmime { +namespace net { +namespace maildir { +namespace format { + + +/** Reads Courier/QMail Maildir format. +  */ +class VMIME_EXPORT courierMaildirFormat : public maildirFormat { + +public: + +	courierMaildirFormat(const shared_ptr <context>& ctx); + + +	/* Folder types: +	 * +	 * - ROOT_DIRECTORY:       ~/Mail/.MyFolder +	 * - NEW_DIRECTORY:        ~/Mail/.MyFolder/new +	 * - CUR_DIRECTORY:        ~/Mail/.MyFolder/cur +	 * - TMP_DIRECTORY:        ~/Mail/.MyFolder/tmp +	 * - CONTAINER_DIRECTORY:  not used +	 */ + +	const string getName() const; + +	void createFolder(const folder::path& path); +	void destroyFolder(const folder::path& path); +	void renameFolder(const folder::path& oldPath, const folder::path& newPath); + +	bool folderExists(const folder::path& path) const; +	bool folderHasSubfolders(const folder::path& path) const; + +	const utility::file::path folderPathToFileSystemPath( +		const folder::path& path, +		const DirectoryType type +	) const; + +	const std::vector <folder::path> listFolders( +		const folder::path& root, +		const bool recursive +	) const; + +protected: + +	bool supports() const; + + +	static const string toModifiedUTF7(const folder::path::component& text); +	static const folder::path::component fromModifiedUTF7(const string& text); + +	void renameFolderImpl(const folder::path& oldPath, const folder::path& newPath); + +	/** Test whether the specified file system directory corresponds to +	  * a maildir subfolder. The name of the directory should start +	  * with a '.' to be listed as a subfolder. +	  * +	  * @param file reference to a file system directory +	  * @return true if the specified directory is a maildir subfolder, +	  * false otherwise +	  */ +	static bool isSubfolderDirectory(const utility::file& file); + +	/** List directories corresponding to folders which are (direct or +	  * indirect) children of specified folder. +	  * +	  * @param root root folder +	  * @param dirs list in which found directories will be added +	  * @param onlyTestForExistence if true, the function returns as soon +	  * as the first directory is found +	  * @return true if at least one directory has been found, +	  * false otherwise +	  */ +	bool listDirectories( +		const folder::path& root, +		std::vector <string>& dirs, +		const bool onlyTestForExistence +	) const; +}; + + +} // format +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp new file mode 100644 index 0000000..4eb89e8 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp @@ -0,0 +1,337 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/format/kmailMaildirFormat.hpp" + +#include "vmime/net/maildir/maildirStore.hpp" +#include "vmime/net/maildir/maildirUtils.hpp" + +#include "vmime/platform.hpp" + + +namespace vmime { +namespace net { +namespace maildir { +namespace format { + + +kmailMaildirFormat::kmailMaildirFormat(const shared_ptr <context>& ctx) +	: maildirFormat(ctx) { + +} + + +const string kmailMaildirFormat::getName() const { + +	return "kmail"; +} + + +void kmailMaildirFormat::createFolder(const folder::path& path) { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) { +		throw exceptions::invalid_folder_name(); +	} + +	shared_ptr <utility::file> rootDir = fsf->create( +		folderPathToFileSystemPath(path, ROOT_DIRECTORY) +	); + +	shared_ptr <utility::file> newDir = fsf->create( +		folderPathToFileSystemPath(path, NEW_DIRECTORY) +	); +	shared_ptr <utility::file> tmpDir = fsf->create( +		folderPathToFileSystemPath(path, TMP_DIRECTORY) +	); +	shared_ptr <utility::file> curDir = fsf->create( +		folderPathToFileSystemPath(path, CUR_DIRECTORY) +	); + +	rootDir->createDirectory(true); + +	newDir->createDirectory(false); +	tmpDir->createDirectory(false); +	curDir->createDirectory(false); +} + + +void kmailMaildirFormat::destroyFolder(const folder::path& path) { + +	// Delete 'folder' and '.folder.directory' directories +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	maildirUtils::recursiveFSDelete( +		fsf->create(folderPathToFileSystemPath(path, ROOT_DIRECTORY))  // root +	); + +	maildirUtils::recursiveFSDelete( +		fsf->create(folderPathToFileSystemPath(path, CONTAINER_DIRECTORY))  // container +	); +} + + +bool kmailMaildirFormat::folderExists(const folder::path& path) const { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	shared_ptr <utility::file> rootDir = fsf->create( +		folderPathToFileSystemPath(path, ROOT_DIRECTORY) +	); + +	shared_ptr <utility::file> newDir = fsf->create( +		folderPathToFileSystemPath(path, NEW_DIRECTORY) +	); +	shared_ptr <utility::file> tmpDir = fsf->create( +		folderPathToFileSystemPath(path, TMP_DIRECTORY) +	); +	shared_ptr <utility::file> curDir = fsf->create( +		folderPathToFileSystemPath(path, CUR_DIRECTORY) +	); + +	return rootDir->exists() && rootDir->isDirectory() && +	       newDir->exists() && newDir->isDirectory() && +	       tmpDir->exists() && tmpDir->isDirectory() && +	       curDir->exists() && curDir->isDirectory(); +} + + +const utility::file::path kmailMaildirFormat::folderPathToFileSystemPath( +	const folder::path& path, +	const DirectoryType type +) const { + +	// Root path +	utility::file::path fsPath = getContext()->getStore()->getFileSystemPath(); + +	const size_t pathSize = path.getSize(); +	const size_t count = (type == CONTAINER_DIRECTORY +		? pathSize : (pathSize >= 1 ? pathSize - 1 : 0)); + +	// Parent folders +	for (size_t i = 0 ; i < count ; ++i) { + +		utility::file::path::component comp(path[i]); + +		// TODO: may not work with all encodings... +		comp.setBuffer("." + comp.getBuffer() + ".directory"); + +		fsPath /= comp; +	} + +	// Last component +	if (path.getSize() != 0 && type != CONTAINER_DIRECTORY) { + +		fsPath /= path.getLastComponent(); + +		switch (type) { + +			case ROOT_DIRECTORY: + +				// Nothing to add +				break; + +			case NEW_DIRECTORY: + +				fsPath /= NEW_DIR; +				break; + +			case CUR_DIRECTORY: + +				fsPath /= CUR_DIR; +				break; + +			case TMP_DIRECTORY: + +				fsPath /= TMP_DIR; +				break; + +			case CONTAINER_DIRECTORY: + +				// Can't happen... +				break; +		} +	} + +	return fsPath; +} + + +const std::vector <folder::path> kmailMaildirFormat::listFolders( +	const folder::path& root, +	const bool recursive +) const { + +	std::vector <folder::path> list; +	listFoldersImpl(list, root, recursive); + +	return list; +} + + +void kmailMaildirFormat::listFoldersImpl( +	std::vector <folder::path>& list, +	const folder::path& root, +	const bool recursive +) const { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	shared_ptr <utility::file> rootDir = fsf->create( +		folderPathToFileSystemPath(root, root.isEmpty() ? ROOT_DIRECTORY : CONTAINER_DIRECTORY) +	); + +	if (rootDir->exists()) { + +		shared_ptr <utility::fileIterator> it = rootDir->getFiles(); + +		while (it->hasMoreElements()) { + +			shared_ptr <utility::file> file = it->nextElement(); + +			if (isSubfolderDirectory(*file)) { + +				const utility::path subPath = root / file->getFullPath().getLastComponent(); + +				list.push_back(subPath); + +				if (recursive) { +					listFoldersImpl(list, subPath, true); +				} +			} +		} + +	} else { + +		// No sub-folder +	} +} + + +// static +bool kmailMaildirFormat::isSubfolderDirectory(const utility::file& file) { + +	// A directory which name does not start with '.' is listed as a sub-folder +	if (file.isDirectory() && +	    file.getFullPath().getLastComponent().getBuffer().length() >= 1 && +	    file.getFullPath().getLastComponent().getBuffer()[0] != '.') { + +		return true; +	} + +	return false; +} + + +void kmailMaildirFormat::renameFolder(const folder::path& oldPath, const folder::path& newPath) { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	shared_ptr <utility::file> rootDir = fsf->create( +		folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY) +	); +	shared_ptr <utility::file> contDir = fsf->create( +		folderPathToFileSystemPath(oldPath, CONTAINER_DIRECTORY) +	); + +	try { + +		const utility::file::path newRootPath = +			folderPathToFileSystemPath(newPath, ROOT_DIRECTORY); +		const utility::file::path newContPath = +			folderPathToFileSystemPath(newPath, CONTAINER_DIRECTORY); + +		rootDir->rename(newRootPath); + +		// Container directory may not exist, so ignore error when trying to rename it +		try { +			contDir->rename(newContPath); +		} catch (exceptions::filesystem_exception& e) { +			// Ignore +		} + +	} catch (exceptions::filesystem_exception& e) { + +		// Revert to old location +		const utility::file::path rootPath = +			folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY); +		const utility::file::path contPath = +			folderPathToFileSystemPath(oldPath, CONTAINER_DIRECTORY); + +		try { +			rootDir->rename(rootPath); +			contDir->rename(contPath); +		} catch (exceptions::filesystem_exception& e) { +			// Ignore (not recoverable) +		} + +		throw; +	} +} + + +bool kmailMaildirFormat::folderHasSubfolders(const folder::path& path) const { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	shared_ptr <utility::file> rootDir = fsf->create( +		folderPathToFileSystemPath(path, CONTAINER_DIRECTORY) +	); + +	shared_ptr <utility::fileIterator> it = rootDir->getFiles(); + +	while (it->hasMoreElements()) { + +		shared_ptr <utility::file> file = it->nextElement(); + +		if (isSubfolderDirectory(*file)) { +			return true; +		} +	} + +	return false; +} + + +bool kmailMaildirFormat::supports() const { + +	// This is the default +	return true; +} + + +} // format +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + diff --git a/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp new file mode 100644 index 0000000..26b557a --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp @@ -0,0 +1,115 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED +#define VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirFormat.hpp" + + +namespace vmime { +namespace net { +namespace maildir { +namespace format { + + +/** Reads KMail Maildir format. +  */ +class VMIME_EXPORT kmailMaildirFormat : public maildirFormat { + +public: + +	kmailMaildirFormat(const shared_ptr <context>& ctx); + + +	/* Folder types: +	 * +	 * - ROOT_DIRECTORY:       ~/Mail/MyFolder +	 * - NEW_DIRECTORY:        ~/Mail/MyFolder/new +	 * - CUR_DIRECTORY:        ~/Mail/MyFolder/cur +	 * - TMP_DIRECTORY:        ~/Mail/MyFolder/tmp +	 * - CONTAINER_DIRECTORY:  ~/Mail/.MyFolder.directory +	 */ + +	const string getName() const; + +	void createFolder(const folder::path& path); +	void destroyFolder(const folder::path& path); +	void renameFolder(const folder::path& oldPath, const folder::path& newPath); + +	bool folderExists(const folder::path& path) const; +	bool folderHasSubfolders(const folder::path& path) const; + +	const utility::file::path folderPathToFileSystemPath( +		const folder::path& path, +		const DirectoryType type +	) const; + +	const std::vector <folder::path> listFolders( +		const folder::path& root, +		const bool recursive +	) const; + +protected: + +	bool supports() const; + + +	/** Recursive implementation of listFolders(). +	  */ +	void listFoldersImpl( +		std::vector <folder::path>& list, +		const folder::path& root, +		const bool recursive +	) const; + +	/** Test whether the specified file system directory corresponds to +	  * a maildir subfolder. The name of the directory should not start +	  * with '.' to be listed as a subfolder. +	  * +	  * @param file reference to a file system directory +	  * @return true if the specified directory is a maildir subfolder, +	  * false otherwise +	  */ +	static bool isSubfolderDirectory(const utility::file& file); +}; + + +} // format +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#endif // VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/maildir/maildir.hpp b/vmime-master/src/vmime/net/maildir/maildir.hpp new file mode 100644 index 0000000..8835bf4 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildir.hpp @@ -0,0 +1,34 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED + + +#include "vmime/net/maildir/maildirFolder.hpp" +#include "vmime/net/maildir/maildirFolderStatus.hpp" +#include "vmime/net/maildir/maildirMessage.hpp" +#include "vmime/net/maildir/maildirStore.hpp" + + +#endif // VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/maildir/maildirFolder.cpp b/vmime-master/src/vmime/net/maildir/maildirFolder.cpp new file mode 100644 index 0000000..8c02025 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirFolder.cpp @@ -0,0 +1,1365 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirFolder.hpp" + +#include "vmime/net/maildir/maildirStore.hpp" +#include "vmime/net/maildir/maildirMessage.hpp" +#include "vmime/net/maildir/maildirUtils.hpp" +#include "vmime/net/maildir/maildirFormat.hpp" +#include "vmime/net/maildir/maildirFolderStatus.hpp" + +#include "vmime/message.hpp" + +#include "vmime/exception.hpp" +#include "vmime/platform.hpp" + +#include "vmime/utility/outputStreamAdapter.hpp" +#include "vmime/utility/inputStreamStringAdapter.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +maildirFolder::maildirFolder( +	const folder::path& path, +	const shared_ptr <maildirStore>& store +) +	: m_store(store), +	  m_path(path), +	  m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()), +	  m_mode(-1), +	  m_open(false), +	  m_unreadMessageCount(0), +	  m_messageCount(0) { + +	store->registerFolder(this); +} + + +maildirFolder::~maildirFolder() { + +	try { + +		shared_ptr <maildirStore> store = m_store.lock(); + +		if (store) { + +			if (m_open) { +				close(false); +			} + +			store->unregisterFolder(this); + +		} else if (m_open) { + +			close(false); +		} + +	} catch (...) { + +		// Don't throw in destructor +	} +} + + +void maildirFolder::onStoreDisconnected() { + +	m_store.reset(); +} + + +int maildirFolder::getMode() const { + +	if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} + +	return m_mode; +} + + +const folderAttributes maildirFolder::getAttributes() { + +	folderAttributes attribs; + +	if (m_path.isEmpty()) { +		attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS); +	} else { +		attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS | folderAttributes::TYPE_CONTAINS_MESSAGES); +	} + +	if (m_store.lock()->getFormat()->folderHasSubfolders(m_path)) { +		attribs.setFlags(folderAttributes::FLAG_HAS_CHILDREN);  // contains at least one sub-folder +	} + +	return attribs; +} + + +const folder::path::component maildirFolder::getName() const { + +	return m_name; +} + + +const folder::path maildirFolder::getFullPath() const { + +	return m_path; +} + + +void maildirFolder::open(const int mode, bool /* failIfModeIsNotAvailable */) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (isOpen()) { +		throw exceptions::illegal_state("Folder is already open"); +	} else if (!exists()) { +		throw exceptions::illegal_state("Folder does not exist"); +	} + +	scanFolder(); + +	m_open = true; +	m_mode = mode; +} + + +void maildirFolder::close(const bool expunge) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} + +	if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} + +	if (expunge) { +		this->expunge(); +	} + +	m_open = false; +	m_mode = -1; + +	onClose(); +} + + +void maildirFolder::onClose() { + +	for (std::vector <maildirMessage*>::iterator it = m_messages.begin() ; +	     it != m_messages.end() ; ++it) { + +		(*it)->onFolderClosed(); +	} + +	m_messages.clear(); +} + + +void maildirFolder::registerMessage(maildirMessage* msg) { + +	m_messages.push_back(msg); +} + + +void maildirFolder::unregisterMessage(maildirMessage* msg) { + +	std::vector <maildirMessage*>::iterator it = +		std::find(m_messages.begin(), m_messages.end(), msg); + +	if (it != m_messages.end()) { +		m_messages.erase(it); +	} +} + + +void maildirFolder::create(const folderAttributes& /* attribs */) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (isOpen()) { +		throw exceptions::illegal_state("Folder is open"); +	} else if (exists()) { +		throw exceptions::illegal_state("Folder already exists"); +	} else if (!store->isValidFolderName(m_name)) { +		throw exceptions::invalid_folder_name(); +	} + +	// Create directory on file system +	try { +		store->getFormat()->createFolder(m_path); +	} catch (exceptions::filesystem_exception& e) { +		throw exceptions::command_error("CREATE", "", "File system exception", e); +	} + +	// Notify folder created +	shared_ptr <events::folderEvent> event = +		make_shared <events::folderEvent>( +			dynamicCast <folder>(shared_from_this()), +			events::folderEvent::TYPE_CREATED, +			m_path, m_path +		); + +	notifyFolder(event); +} + + +void maildirFolder::destroy() { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (isOpen()) { +		throw exceptions::illegal_state("Folder is open"); +	} + +	// Delete folder +	try { +		store->getFormat()->destroyFolder(m_path); +	} catch (std::exception&) { +		// Ignore exception: anyway, we can't recover from this... +	} + +	// Notify folder deleted +	shared_ptr <events::folderEvent> event = +		make_shared <events::folderEvent>( +			dynamicCast <folder>(shared_from_this()), +			events::folderEvent::TYPE_DELETED, +			m_path, m_path +		); + +	notifyFolder(event); +} + + +bool maildirFolder::exists() { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	return store->getFormat()->folderExists(m_path); +} + + +bool maildirFolder::isOpen() const { + +	return m_open; +} + + +void maildirFolder::scanFolder() { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	try { + +		m_messageCount = 0; +		m_unreadMessageCount = 0; + +		shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +		utility::file::path newDirPath = +			store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::NEW_DIRECTORY); +		shared_ptr <utility::file> newDir = fsf->create(newDirPath); + +		utility::file::path curDirPath = +			store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); +		shared_ptr <utility::file> curDir = fsf->create(curDirPath); + +		// New received messages (new/) +		shared_ptr <utility::fileIterator> nit = newDir->getFiles(); +		std::vector <utility::file::path::component> newMessageFilenames; + +		while (nit->hasMoreElements()) { + +			shared_ptr <utility::file> file = nit->nextElement(); + +			if (maildirUtils::isMessageFile(*file)) { +				newMessageFilenames.push_back(file->getFullPath().getLastComponent()); +			} +		} + +		// Current messages (cur/) +		shared_ptr <utility::fileIterator> cit = curDir->getFiles(); +		std::vector <utility::file::path::component> curMessageFilenames; + +		while (cit->hasMoreElements()) { + +			shared_ptr <utility::file> file = cit->nextElement(); + +			if (maildirUtils::isMessageFile(*file)) { +				curMessageFilenames.push_back(file->getFullPath().getLastComponent()); +			} +		} + +		// Update/delete existing messages (found in previous scan) +		for (size_t i = 0 ; i < m_messageInfos.size() ; ++i) { + +			messageInfos& msgInfos = m_messageInfos[i]; + +			// NOTE: the flags may have changed (eg. moving from 'new' to 'cur' +			// may imply the 'S' flag) and so the filename. That's why we use +			// "maildirUtils::messageIdComparator" to compare only the 'unique' +			// portion of the filename... + +			if (msgInfos.type == messageInfos::TYPE_CUR) { + +				const std::vector <utility::file::path::component>::iterator pos = +					std::find_if( +						curMessageFilenames.begin(), +						curMessageFilenames.end(), +						maildirUtils::messageIdComparator(msgInfos.path) +					); + +				// If we cannot find this message in the 'cur' directory, +				// it means it has been deleted (and expunged). +				if (pos == curMessageFilenames.end()) { + +					msgInfos.type = messageInfos::TYPE_DELETED; + +				// Otherwise, update its information. +				} else { + +					msgInfos.path = *pos; +					curMessageFilenames.erase(pos); +				} +			} +		} + +		m_messageInfos.reserve(m_messageInfos.size() +			+ newMessageFilenames.size() + curMessageFilenames.size()); + +		// Add new messages from 'new': we are responsible to move the files +		// from the 'new' directory to the 'cur' directory, and append them +		// to our message list. +		for (std::vector <utility::file::path::component>::const_iterator +		     it = newMessageFilenames.begin() ; it != newMessageFilenames.end() ; ++it) { + +			const utility::file::path::component newFilename = +				maildirUtils::buildFilename(maildirUtils::extractId(*it), 0); + +			// Move messages from 'new' to 'cur' +			shared_ptr <utility::file> file = fsf->create(newDirPath / *it); +			file->rename(curDirPath / newFilename); + +			// Append to message list +			messageInfos msgInfos; +			msgInfos.path = newFilename; + +			if (maildirUtils::extractFlags(msgInfos.path) & message::FLAG_DELETED) { +				msgInfos.type = messageInfos::TYPE_DELETED; +			} else { +				msgInfos.type = messageInfos::TYPE_CUR; +			} + +			m_messageInfos.push_back(msgInfos); +		} + +		// Add new messages from 'cur': the files have already been moved +		// from 'new' to 'cur'. Just append them to our message list. +		for (std::vector <utility::file::path::component>::const_iterator +		     it = curMessageFilenames.begin() ; it != curMessageFilenames.end() ; ++it) { + +			// Append to message list +			messageInfos msgInfos; +			msgInfos.path = *it; + +			if (maildirUtils::extractFlags(msgInfos.path) & message::FLAG_DELETED) { +				msgInfos.type = messageInfos::TYPE_DELETED; +			} else { +				msgInfos.type = messageInfos::TYPE_CUR; +			} + +			m_messageInfos.push_back(msgInfos); +		} + +		// Update message count +		size_t unreadMessageCount = 0; + +		for (std::vector <messageInfos>::const_iterator +		     it = m_messageInfos.begin() ; it != m_messageInfos.end() ; ++it) { + +			if ((maildirUtils::extractFlags((*it).path) & message::FLAG_SEEN) == 0) { +				++unreadMessageCount; +			} +		} + +		m_unreadMessageCount = unreadMessageCount; +		m_messageCount = static_cast <size_t>(m_messageInfos.size()); + +	} catch (exceptions::filesystem_exception&) { + +		// Should not happen... +	} +} + + +shared_ptr <message> maildirFolder::getMessage(const size_t num) { + +	if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} + +	if (num < 1 || num > m_messageCount) { +		throw exceptions::message_not_found(); +	} + +	return make_shared <maildirMessage>(dynamicCast <maildirFolder>(shared_from_this()), num); +} + + +std::vector <shared_ptr <message> > maildirFolder::getMessages(const messageSet& msgs) { + +	if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} + +	if (msgs.isNumberSet()) { + +		const std::vector <size_t> numbers = maildirUtils::messageSetToNumberList(msgs, m_messageCount); + +		std::vector <shared_ptr <message> > messages; +		shared_ptr <maildirFolder> thisFolder = dynamicCast <maildirFolder>(shared_from_this()); + +		for (std::vector <size_t>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) { + +			if (*it < 1|| *it > m_messageCount) { +				throw exceptions::message_not_found(); +			} + +			messages.push_back(make_shared <maildirMessage>(thisFolder, *it)); +		} + +		return messages; + +	} else { + +		throw exceptions::operation_not_supported(); +	} +} + + +size_t maildirFolder::getMessageCount() { + +	return m_messageCount; +} + + +shared_ptr <folder> maildirFolder::getFolder(const folder::path::component& name) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} + +	return shared_ptr <maildirFolder>(new maildirFolder(m_path / name, store)); +} + + +std::vector <shared_ptr <folder> > maildirFolder::getFolders(const bool recursive) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!isOpen() && !store) { +		throw exceptions::illegal_state("Store disconnected"); +	} + +	std::vector <shared_ptr <folder> > list; + +	listFolders(list, recursive); + +	return list; +} + + +void maildirFolder::listFolders(std::vector <shared_ptr <folder> >& list, const bool recursive) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	try { + +		std::vector <folder::path> pathList = +			store->getFormat()->listFolders(m_path, recursive); + +		list.reserve(pathList.size()); + +		for (std::vector <folder::path>::size_type i = 0, n = pathList.size() ; i < n ; ++i) { + +			shared_ptr <maildirFolder> subFolder( +				new maildirFolder(pathList[i], store) +			); + +			list.push_back(subFolder); +		} + +	} catch (exceptions::filesystem_exception& e) { + +		throw exceptions::command_error("LIST", "", "", e); +	} +} + + +void maildirFolder::rename(const folder::path& newPath) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (m_path.isEmpty() || newPath.isEmpty()) { +		throw exceptions::illegal_operation("Cannot rename root folder"); +	} else if (!store->isValidFolderName(newPath.getLastComponent())) { +		throw exceptions::invalid_folder_name(); +	} + +	// Rename the directory on the file system +	try { +		store->getFormat()->renameFolder(m_path, newPath); +	} catch (vmime::exception& e) { +		throw exceptions::command_error("RENAME", "", "", e); +	} + +	// Notify folder renamed +	folder::path oldPath(m_path); + +	m_path = newPath; +	m_name = newPath.getLastComponent(); + +	shared_ptr <events::folderEvent> event = +		make_shared <events::folderEvent>( +			dynamicCast <folder>(shared_from_this()), +			events::folderEvent::TYPE_RENAMED, +			oldPath, newPath +		); + +	notifyFolder(event); + +	// Notify folders with the same path +	for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ; +	     it != store->m_folders.end() ; ++it) { + +		if ((*it) != this && (*it)->getFullPath() == oldPath) { + +			(*it)->m_path = newPath; +			(*it)->m_name = newPath.getLastComponent(); + +			shared_ptr <events::folderEvent> event = +				make_shared <events::folderEvent>( +					dynamicCast <folder>((*it)->shared_from_this()), +					events::folderEvent::TYPE_RENAMED, +					oldPath, newPath +				); + +			(*it)->notifyFolder(event); + +		} else if ((*it) != this && oldPath.isParentOf((*it)->getFullPath())) { + +			folder::path oldPath((*it)->m_path); + +			(*it)->m_path.renameParent(oldPath, newPath); + +			shared_ptr <events::folderEvent> event = +				make_shared <events::folderEvent>( +					dynamicCast <folder>((*it)->shared_from_this()), +					events::folderEvent::TYPE_RENAMED, +					oldPath, (*it)->m_path +				); + +			(*it)->notifyFolder(event); +		} +	} +} + + +void maildirFolder::deleteMessages(const messageSet& msgs) { + +	// Mark messages as deleted +	setMessageFlags(msgs, message::FLAG_DELETED, message::FLAG_MODE_ADD); +} + + +void maildirFolder::setMessageFlags( +	const messageSet& msgs, +	const int flags, +	const int mode +) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} else if (m_mode == MODE_READ_ONLY) { +		throw exceptions::illegal_state("Folder is read-only"); +	} + +	if (msgs.isNumberSet()) { + +		const std::vector <size_t> nums = maildirUtils::messageSetToNumberList(msgs, m_messageCount); + +		// Change message flags +		shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +		utility::file::path curDirPath = store->getFormat()-> +			folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); + +		for (std::vector <size_t>::const_iterator it = +			 nums.begin() ; it != nums.end() ; ++it) { + +			const size_t num = *it - 1; + +			try { + +				const utility::file::path::component path = m_messageInfos[num].path; +				shared_ptr <utility::file> file = fsf->create(curDirPath / path); + +				int newFlags = maildirUtils::extractFlags(path); + +				switch (mode) { +					case message::FLAG_MODE_ADD:    newFlags |= flags; break; +					case message::FLAG_MODE_REMOVE: newFlags &= ~flags; break; +					default: +					case message::FLAG_MODE_SET:    newFlags = flags; break; +				} + +				const utility::file::path::component newPath = +					maildirUtils::buildFilename(maildirUtils::extractId(path), newFlags); + +				file->rename(curDirPath / newPath); + +				if (flags & message::FLAG_DELETED) { +					m_messageInfos[num].type = messageInfos::TYPE_DELETED; +				} else { +					m_messageInfos[num].type = messageInfos::TYPE_CUR; +				} + +				m_messageInfos[num].path = newPath; + +			} catch (exceptions::filesystem_exception& e) { + +				// Ignore (not important) +			} +		} + +		// Update local flags +		switch (mode) { + +			case message::FLAG_MODE_ADD: { + +				for (std::vector <maildirMessage*>::iterator it = +					 m_messages.begin() ; it != m_messages.end() ; ++it) { + +					if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) && +						(*it)->m_flags != maildirMessage::FLAG_UNDEFINED) { + +						(*it)->m_flags |= flags; +					} +				} + +				break; +			} +			case message::FLAG_MODE_REMOVE: { + +				for (std::vector <maildirMessage*>::iterator it = +					 m_messages.begin() ; it != m_messages.end() ; ++it) { + +					if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) && +						(*it)->m_flags != maildirMessage::FLAG_UNDEFINED) { + +						(*it)->m_flags &= ~flags; +					} +				} + +				break; +			} +			default: +			case message::FLAG_MODE_SET: { + +				for (std::vector <maildirMessage*>::iterator it = +					 m_messages.begin() ; it != m_messages.end() ; ++it) { + +					if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) && +						(*it)->m_flags != maildirMessage::FLAG_UNDEFINED) { + +						(*it)->m_flags = flags; +					} +				} + +				break; +			} + +		} + +		// Notify message flags changed +		shared_ptr <events::messageChangedEvent> event = +			make_shared <events::messageChangedEvent>( +				dynamicCast <folder>(shared_from_this()), +				events::messageChangedEvent::TYPE_FLAGS, +				nums +			); + +		notifyMessageChanged(event); + +		// TODO: notify other folders with the same path + +	} else { + +		throw exceptions::operation_not_supported(); +	} +} + + +messageSet maildirFolder::addMessage( +	const shared_ptr <vmime::message>& msg, +	const int flags, +	vmime::datetime* date, +	utility::progressListener* progress +) { + +	std::ostringstream oss; +	utility::outputStreamAdapter ossAdapter(oss); + +	msg->generate(ossAdapter); + +	const string& str = oss.str(); +	utility::inputStreamStringAdapter strAdapter(str); + +	return addMessage(strAdapter, str.length(), flags, date, progress); +} + + +messageSet maildirFolder::addMessage( +	utility::inputStream& is, +	const size_t size, +	const int flags, +	vmime::datetime* /* date */, +	utility::progressListener* progress +) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} else if (m_mode == MODE_READ_ONLY) { +		throw exceptions::illegal_state("Folder is read-only"); +	} + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	utility::file::path tmpDirPath = store->getFormat()-> +		folderPathToFileSystemPath(m_path,maildirFormat::TMP_DIRECTORY); +	utility::file::path dstDirPath = store->getFormat()-> +		folderPathToFileSystemPath( +			m_path, +			flags == message::FLAG_RECENT ? +				maildirFormat::NEW_DIRECTORY : +				maildirFormat::CUR_DIRECTORY +		); + +	const utility::file::path::component filename = +		maildirUtils::buildFilename(maildirUtils::generateId(), ((flags == -1) ? 0 : flags)); + +	try { +		shared_ptr <utility::file> tmpDir = fsf->create(tmpDirPath); +		tmpDir->createDirectory(true); +	} catch (exceptions::filesystem_exception&) { +		// Don't throw now, it will fail later... +	} + +	try { +		shared_ptr <utility::file> curDir = fsf->create(dstDirPath); +		curDir->createDirectory(true); +	} catch (exceptions::filesystem_exception&) { +		// Don't throw now, it will fail later... +	} + +	// Actually add the message +	copyMessageImpl(tmpDirPath, dstDirPath, filename, is, size, progress); + +	// Append the message to the cache list +	messageInfos msgInfos; +	msgInfos.path = filename; +	msgInfos.type = messageInfos::TYPE_CUR; + +	m_messageInfos.push_back(msgInfos); +	m_messageCount++; + +	if ((flags == -1) || !(flags & message::FLAG_SEEN)) { +		m_unreadMessageCount++; +	} + +	// Notification +	std::vector <size_t> nums; +	nums.push_back(m_messageCount); + +	shared_ptr <events::messageCountEvent> event = +		make_shared <events::messageCountEvent>( +			dynamicCast <folder>(shared_from_this()), +			events::messageCountEvent::TYPE_ADDED, +			nums +		); + +	notifyMessageCount(event); + +	// Notify folders with the same path +	for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ; +	     it != store->m_folders.end() ; ++it) { + +		if ((*it) != this && (*it)->getFullPath() == m_path) { + +			(*it)->m_messageCount = m_messageCount; +			(*it)->m_unreadMessageCount = m_unreadMessageCount; + +			(*it)->m_messageInfos.resize(m_messageInfos.size()); +			std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin()); + +			shared_ptr <events::messageCountEvent> event = +				make_shared <events::messageCountEvent>( +					dynamicCast <folder>((*it)->shared_from_this()), +					events::messageCountEvent::TYPE_ADDED, +					nums +				); + +			(*it)->notifyMessageCount(event); +		} +	} + +	return messageSet::empty(); +} + + +void maildirFolder::copyMessageImpl( +	const utility::file::path& tmpDirPath, +	const utility::file::path& dstDirPath, +	const utility::file::path::component& filename, +	utility::inputStream& is, const size_t size, +	utility::progressListener* progress +) { + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	shared_ptr <utility::file> file = fsf->create(tmpDirPath / filename); + +	if (progress) { +		progress->start(size); +	} + +	// First, write the message into 'tmp'... +	try { + +		file->createFile(); + +		shared_ptr <utility::fileWriter> fw = file->getFileWriter(); +		shared_ptr <utility::outputStream> os = fw->getOutputStream(); + +		byte_t buffer[65536]; +		size_t total = 0; + +		while (!is.eof()) { + +			const size_t read = is.read(buffer, sizeof(buffer)); + +			if (read != 0) { +				os->write(buffer, read); +				total += read; +			} + +			if (progress) { +				progress->progress(total, size); +			} +		} + +		os->flush(); + +	} catch (exception& e) { + +		if (progress) { +			progress->stop(size); +		} + +		// Delete temporary file +		try { +			shared_ptr <utility::file> file = fsf->create(tmpDirPath / filename); +			file->remove(); +		} catch (exceptions::filesystem_exception&) { +			// Ignore +		} + +		throw exceptions::command_error("ADD", "", "", e); +	} + +	// ...then, move it to 'cur' +	try { + +		file->rename(dstDirPath / filename); + +	} catch (exception& e) { + +		if (progress) { +			progress->stop(size); +		} + +		// Delete temporary file +		try { + +			file->remove(); +			shared_ptr <utility::file> file = fsf->create(dstDirPath / filename); +			file->remove(); + +		} catch (exceptions::filesystem_exception&) { + +			// Ignore +		} + +		throw exceptions::command_error("ADD", "", "", e); +	} + +	if (progress) { +		progress->stop(size); +	} +} + + +messageSet maildirFolder::copyMessages(const folder::path& dest, const messageSet& msgs) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	utility::file::path curDirPath = +		store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); + +	utility::file::path destCurDirPath = store->getFormat()-> +		folderPathToFileSystemPath(dest, maildirFormat::CUR_DIRECTORY); +	utility::file::path destTmpDirPath = store->getFormat()-> +		folderPathToFileSystemPath(dest, maildirFormat::TMP_DIRECTORY); + +	// Create destination directories +	try { + +		shared_ptr <utility::file> destTmpDir = fsf->create(destTmpDirPath); +		destTmpDir->createDirectory(true); + +	} catch (exceptions::filesystem_exception&) { + +		// Don't throw now, it will fail later... +	} + +	try { + +		shared_ptr <utility::file> destCurDir = fsf->create(destCurDirPath); +		destCurDir->createDirectory(true); + +	} catch (exceptions::filesystem_exception&) { + +		// Don't throw now, it will fail later... +	} + +	// Copy messages +	const std::vector <size_t> nums = maildirUtils::messageSetToNumberList(msgs, m_messageCount); + +	try { + +		for (std::vector <size_t>::const_iterator it = +		     nums.begin() ; it != nums.end() ; ++it) { + +			const size_t num = *it; +			const messageInfos& msg = m_messageInfos[num - 1]; +			const int flags = maildirUtils::extractFlags(msg.path); + +			const utility::file::path::component filename = +				maildirUtils::buildFilename(maildirUtils::generateId(), flags); + +			shared_ptr <utility::file> file = fsf->create(curDirPath / msg.path); +			shared_ptr <utility::fileReader> fr = file->getFileReader(); +			shared_ptr <utility::inputStream> is = fr->getInputStream(); + +			copyMessageImpl(destTmpDirPath, destCurDirPath, +				filename, *is, file->getLength(), NULL); +		} + +	} catch (exception& e) { + +		notifyMessagesCopied(dest); +		throw exceptions::command_error("COPY", "", "", e); +	} + +	notifyMessagesCopied(dest); + +	return messageSet::empty(); +} + + +void maildirFolder::notifyMessagesCopied(const folder::path& dest) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ; +	     it != store->m_folders.end() ; ++it) { + +		if ((*it) != this && (*it)->getFullPath() == dest) { + +			// We only need to update the first folder we found as calling +			// status() will notify all the folders with the same path. +			size_t count, unseen; +			(*it)->status(count, unseen); + +			return; +		} +	} +} + + +void maildirFolder::status(size_t& count, size_t& unseen) { + +	count = 0; +	unseen = 0; + +	shared_ptr <folderStatus> status = getStatus(); + +	count = status->getMessageCount(); +	unseen = status->getUnseenCount(); + +	m_messageCount = count; +} + + +shared_ptr <folderStatus> maildirFolder::getStatus() { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	const size_t oldCount = m_messageCount; + +	scanFolder(); + +	shared_ptr <maildirFolderStatus> status = make_shared <maildirFolderStatus>(); + +	status->setMessageCount(m_messageCount); +	status->setUnseenCount(m_unreadMessageCount); + +	// Notify message count changed (new messages) +	if (m_messageCount > oldCount) { + +		std::vector <size_t> nums; +		nums.reserve(m_messageCount - oldCount); + +		for (size_t i = oldCount + 1, j = 0 ; i <= m_messageCount ; ++i, ++j) { +			nums[j] = i; +		} + +		shared_ptr <events::messageCountEvent> event = +			make_shared <events::messageCountEvent>( +				dynamicCast <folder>(shared_from_this()), +				events::messageCountEvent::TYPE_ADDED, +				nums +			); + +		notifyMessageCount(event); + +		// Notify folders with the same path +		for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ; +		     it != store->m_folders.end() ; ++it) { + +			if ((*it) != this && (*it)->getFullPath() == m_path) { + +				(*it)->m_messageCount = m_messageCount; +				(*it)->m_unreadMessageCount = m_unreadMessageCount; + +				(*it)->m_messageInfos.resize(m_messageInfos.size()); +				std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin()); + +				shared_ptr <events::messageCountEvent> event = +					make_shared <events::messageCountEvent>( +						dynamicCast <folder>((*it)->shared_from_this()), +						events::messageCountEvent::TYPE_ADDED, +						nums +					); + +				(*it)->notifyMessageCount(event); +			} +		} +	} + +	return status; +} + + +void maildirFolder::expunge() { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} else if (m_mode == MODE_READ_ONLY) { +		throw exceptions::illegal_state("Folder is read-only"); +	} + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	utility::file::path curDirPath = store->getFormat()-> +		folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); + +	std::vector <size_t> nums; +	size_t unreadCount = 0; + +	for (size_t num = 1 ; num <= m_messageCount ; ++num) { + +		messageInfos& infos = m_messageInfos[num - 1]; + +		if (infos.type == messageInfos::TYPE_DELETED) { + +			nums.push_back(num); + +			for (std::vector <maildirMessage*>::iterator it = +			     m_messages.begin() ; it != m_messages.end() ; ++it) { + +				if ((*it)->m_num == num) { +					(*it)->m_expunged = true; +				} else if ((*it)->m_num > num) { +					(*it)->m_num--; +				} +			} + +			if (maildirUtils::extractFlags(infos.path) & message::FLAG_SEEN) { +				++unreadCount; +			} + +			// Delete file from file system +			try { +				shared_ptr <utility::file> file = fsf->create(curDirPath / infos.path); +				file->remove(); +			} catch (exceptions::filesystem_exception& e) { +				// Ignore (not important) +			} +		} +	} + +	if (!nums.empty()) { + +		for (std::vector <size_t>::size_type i = nums.size() ; i != 0 ; --i) { +			m_messageInfos.erase(m_messageInfos.begin() + (i - 1)); +		} +	} + +	m_messageCount -= static_cast <size_t>(nums.size()); +	m_unreadMessageCount -= unreadCount; + +	// Notify message expunged +	shared_ptr <events::messageCountEvent> event = +		make_shared <events::messageCountEvent>( +			dynamicCast <folder>(shared_from_this()), +			events::messageCountEvent::TYPE_REMOVED, +			nums +		); + +	notifyMessageCount(event); + +	// Notify folders with the same path +	for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ; +	     it != store->m_folders.end() ; ++it) { + +		if ((*it) != this && (*it)->getFullPath() == m_path) { + +			(*it)->m_messageCount = m_messageCount; +			(*it)->m_unreadMessageCount = m_unreadMessageCount; + +			(*it)->m_messageInfos.resize(m_messageInfos.size()); +			std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin()); + +			shared_ptr <events::messageCountEvent> event = +				make_shared <events::messageCountEvent>( +					dynamicCast <folder>((*it)->shared_from_this()), +					events::messageCountEvent::TYPE_REMOVED, +					nums +				); + +			(*it)->notifyMessageCount(event); +		} +	} +} + + +shared_ptr <folder> maildirFolder::getParent() { + +	if (m_path.isEmpty()) { +		return null; +	} else { +		return shared_ptr <maildirFolder>(new maildirFolder(m_path.getParent(), m_store.lock())); +	} +} + + +shared_ptr <const store> maildirFolder::getStore() const { + +	return m_store.lock(); +} + + +shared_ptr <store> maildirFolder::getStore() { + +	return m_store.lock(); +} + + +void maildirFolder::fetchMessages( +	std::vector <shared_ptr <message> >& msg, +	const fetchAttributes& options, +	utility::progressListener* progress +) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} + +	if (msg.empty()) { +		return; +	} + +	const size_t total = msg.size(); +	size_t current = 0; + +	if (progress) { +		progress->start(total); +	} + +	shared_ptr <maildirFolder> thisFolder = dynamicCast <maildirFolder>(shared_from_this()); + +	for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ; +	     it != msg.end() ; ++it) { + +		dynamicCast <maildirMessage>(*it)->fetch(thisFolder, options); + +		if (progress) { +			progress->progress(++current, total); +		} +	} + +	if (progress) { +		progress->stop(total); +	} +} + + +void maildirFolder::fetchMessage( +	const shared_ptr <message>& msg, +	const fetchAttributes& options +) { + +	shared_ptr <maildirStore> store = m_store.lock(); + +	if (!store) { +		throw exceptions::illegal_state("Store disconnected"); +	} else if (!isOpen()) { +		throw exceptions::illegal_state("Folder not open"); +	} + +	dynamicCast <maildirMessage>(msg)->fetch( +		dynamicCast <maildirFolder>(shared_from_this()), +		options +	); +} + + +std::vector <shared_ptr <message> > maildirFolder::getAndFetchMessages( +	const messageSet& msgs, +	const fetchAttributes& attribs +) { + +	if (msgs.isEmpty()) { +		return std::vector <shared_ptr <message> >(); +	} + +	std::vector <shared_ptr <message> > messages = getMessages(msgs); +	fetchMessages(messages, attribs); + +	return messages; +} + + +int maildirFolder::getFetchCapabilities() const { + +	return fetchAttributes::ENVELOPE | +	       fetchAttributes::STRUCTURE | +	       fetchAttributes::CONTENT_INFO | +	       fetchAttributes::FLAGS | +	       fetchAttributes::SIZE | +	       fetchAttributes::FULL_HEADER | +	       fetchAttributes::UID | +	       fetchAttributes::IMPORTANCE; +} + + +const utility::file::path maildirFolder::getMessageFSPath(const size_t number) const { + +	utility::file::path curDirPath = m_store.lock()->getFormat()-> +		folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); + +	return curDirPath / m_messageInfos[number - 1].path; +} + + +std::vector <size_t> maildirFolder::getMessageNumbersStartingOnUID(const message::uid& /* uid */) { + +	throw exceptions::operation_not_supported(); +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + diff --git a/vmime-master/src/vmime/net/maildir/maildirFolder.hpp b/vmime-master/src/vmime/net/maildir/maildirFolder.hpp new file mode 100644 index 0000000..24f2bf8 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirFolder.hpp @@ -0,0 +1,211 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include <vector> +#include <map> + +#include "vmime/types.hpp" + +#include "vmime/net/folder.hpp" + +#include "vmime/utility/file.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +class maildirStore; +class maildirMessage; + + +/** maildir folder implementation. +  */ +class VMIME_EXPORT maildirFolder : public folder { + +private: + +	friend class maildirStore; +	friend class maildirMessage; + +	maildirFolder(const maildirFolder&) : folder() { } +	maildirFolder(const folder::path& path, const shared_ptr <maildirStore>& store); + +public: + +	~maildirFolder(); + + +	int getMode() const; + +	const folderAttributes getAttributes(); + +	const folder::path::component getName() const; +	const folder::path getFullPath() const; + +	void open(const int mode, bool failIfModeIsNotAvailable = false); +	void close(const bool expunge); +	void create(const folderAttributes& attribs); + +	bool exists(); + +	void destroy(); + +	bool isOpen() const; + +	shared_ptr <message> getMessage(const size_t num); +	std::vector <shared_ptr <message> > getMessages(const messageSet& msgs); + +	size_t getMessageCount(); + +	shared_ptr <folder> getFolder(const folder::path::component& name); +	std::vector <shared_ptr <folder> > getFolders(const bool recursive = false); + +	void rename(const folder::path& newPath); + +	void deleteMessages(const messageSet& msgs); + +	void setMessageFlags( +		const messageSet& msgs, +		const int flags, +		const int mode = message::FLAG_MODE_SET +	); + +	messageSet addMessage( +		const shared_ptr <vmime::message>& msg, +		const int flags = -1, +		vmime::datetime* date = NULL, +		utility::progressListener* progress = NULL +	); + +	messageSet addMessage( +		utility::inputStream& is, +		const size_t size, +		const int flags = -1, +		vmime::datetime* date = NULL, +		utility::progressListener* progress = NULL +	); + +	messageSet copyMessages(const folder::path& dest, const messageSet& msgs); + +	void status(size_t& count, size_t& unseen); +	shared_ptr <folderStatus> getStatus(); + +	void expunge(); + +	shared_ptr <folder> getParent(); + +	shared_ptr <const store> getStore() const; +	shared_ptr <store> getStore(); + + +	void fetchMessages( +		std::vector <shared_ptr <message> >& msg, +		const fetchAttributes& options, +		utility::progressListener* progress = NULL +	); + +	void fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options); + +	std::vector <shared_ptr <message> > getAndFetchMessages( +		const messageSet& msgs, +		const fetchAttributes& attribs +	); + +	int getFetchCapabilities() const; + +	std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid); + +private: + +	void scanFolder(); + +	void listFolders(std::vector <shared_ptr <folder> >& list, const bool recursive); + +	void registerMessage(maildirMessage* msg); +	void unregisterMessage(maildirMessage* msg); + +	const utility::file::path getMessageFSPath(const size_t number) const; + +	void onStoreDisconnected(); + +	void onClose(); + +	void deleteMessagesImpl(const std::vector <size_t>& nums); +	void setMessageFlagsImpl(const std::vector <size_t>& nums, const int flags, const int mode); + +	void copyMessagesImpl(const folder::path& dest, const std::vector <size_t>& nums); +	void copyMessageImpl(const utility::file::path& tmpDirPath, const utility::file::path& curDirPath, const utility::file::path::component& filename, utility::inputStream& is, const size_t size, utility::progressListener* progress); + +	void notifyMessagesCopied(const folder::path& dest); + + +	weak_ptr <maildirStore> m_store; + +	folder::path m_path; +	folder::path::component m_name; + +	int m_mode; +	bool m_open; + +	size_t m_unreadMessageCount; +	size_t m_messageCount; + +	// Store information about scanned messages +	struct messageInfos { + +		enum Type { +			TYPE_CUR, +			TYPE_DELETED +		}; + +		utility::file::path::component path;    // filename +		Type type;                              // current location +	}; + +	std::vector <messageInfos> m_messageInfos; + +	// Instanciated message objects +	std::vector <maildirMessage*> m_messages; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp new file mode 100644 index 0000000..7438d8c --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp @@ -0,0 +1,88 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirFolderStatus.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +maildirFolderStatus::maildirFolderStatus() +	: m_count(0), +	  m_unseen(0) { + +} + + +maildirFolderStatus::maildirFolderStatus(const maildirFolderStatus& other) +	: folderStatus(), +	  m_count(other.m_count), +	  m_unseen(other.m_unseen) { + +} + + +size_t maildirFolderStatus::getMessageCount() const { + +	return m_count; +} + + +size_t maildirFolderStatus::getUnseenCount() const { + +	return m_unseen; +} + + +void maildirFolderStatus::setMessageCount(const size_t count) { + +	m_count = count; +} + + +void maildirFolderStatus::setUnseenCount(const size_t unseen) { + +	m_unseen = unseen; +} + + +shared_ptr <folderStatus> maildirFolderStatus::clone() const { + +	return make_shared <maildirFolderStatus>(*this); +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR diff --git a/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp new file mode 100644 index 0000000..3b69375 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp @@ -0,0 +1,75 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/folderStatus.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +/** Holds the status of a Maildir folder. +  */ +class VMIME_EXPORT maildirFolderStatus : public folderStatus { + +public: + +	maildirFolderStatus(); +	maildirFolderStatus(const maildirFolderStatus& other); + +	// Inherited from folderStatus +	size_t getMessageCount() const; +	size_t getUnseenCount() const; + +	shared_ptr <folderStatus> clone() const; + + +	void setMessageCount(const size_t count); +	void setUnseenCount(const size_t unseen); + +private: + +	size_t m_count; +	size_t m_unseen; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/maildir/maildirFormat.cpp b/vmime-master/src/vmime/net/maildir/maildirFormat.cpp new file mode 100644 index 0000000..914c078 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirFormat.cpp @@ -0,0 +1,104 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirFormat.hpp" +#include "vmime/net/maildir/maildirStore.hpp" + +#include "vmime/net/maildir/format/kmailMaildirFormat.hpp" +#include "vmime/net/maildir/format/courierMaildirFormat.hpp" + +#include "vmime/utility/file.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +const utility::file::path::component maildirFormat::TMP_DIR("tmp", vmime::charset(vmime::charsets::US_ASCII)); +const utility::file::path::component maildirFormat::CUR_DIR("cur", vmime::charset(vmime::charsets::US_ASCII)); +const utility::file::path::component maildirFormat::NEW_DIR("new", vmime::charset(vmime::charsets::US_ASCII)); + + +// +// maildirFormat::context +// + +maildirFormat::context::context(const shared_ptr <maildirStore>& store) +	: m_store(store) { + +} + + +shared_ptr <maildirStore> maildirFormat::context::getStore() { + +	return m_store.lock(); +} + + +// +// maildirFormat +// + +maildirFormat::maildirFormat(const shared_ptr <context>& ctx) +	: m_context(ctx) { + +} + + +shared_ptr <maildirFormat::context> maildirFormat::getContext() const { + +	return m_context; +} + + +// static +shared_ptr <maildirFormat> maildirFormat::detect(const shared_ptr <maildirStore>& store) { + +	shared_ptr <context> ctx = make_shared <context>(store); + +	// Try Courier format +	shared_ptr <maildirFormat> fmt = make_shared <format::courierMaildirFormat>(ctx); + +	if (fmt->supports()) { +		return fmt; +	} + +	// Default is KMail format +	return make_shared <format::kmailMaildirFormat>(ctx); +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + diff --git a/vmime-master/src/vmime/net/maildir/maildirFormat.hpp b/vmime-master/src/vmime/net/maildir/maildirFormat.hpp new file mode 100644 index 0000000..9b9e063 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirFormat.hpp @@ -0,0 +1,192 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED +#define VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/folder.hpp" + +#include "vmime/utility/file.hpp" +#include "vmime/utility/path.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +class maildirStore; + + +/** Interface for an object capable of reading a specific Maildir format. +  */ +class VMIME_EXPORT maildirFormat : public object { + +public: + +	class context : public object { + +	public: + +		context(const shared_ptr <maildirStore>& store); + +		shared_ptr <maildirStore> getStore(); + +	private: + +		weak_ptr <maildirStore> m_store; +	}; + + +	/** Physical directory types. */ +	enum DirectoryType { +		ROOT_DIRECTORY,       /**< Root directory. */ +		NEW_DIRECTORY,        /**< Directory containing unread messages. */ +		CUR_DIRECTORY,        /**< Directory containing messages that have been seen. */ +		TMP_DIRECTORY,        /**< Temporary directory used for reliable delivery. */ +		CONTAINER_DIRECTORY   /**< Container for subfolders. */ +	}; + +	/** Return the name of this Maildir format. +	  * +	  * @return format name +	  */ +	virtual const string getName() const = 0; + +	/** Create the specified folder. +	  * +	  * @param path virtual path of the folder +	  * @throw exceptions::filesystem_exception, invalid_folder_name +	  */ +	virtual void createFolder(const folder::path& path) = 0; + +	/** Destroy the specified folder. +	  * +	  * @param path virtual path of the folder +	  * @throw exceptions::filesystem_exception +	  */ +	virtual void destroyFolder(const folder::path& path) = 0; + +	/** Rename the specified folder. +	  * +	  * @param oldPath old virtual path of the folder +	  * @param newPath new virtual path of the folder +	  * @throw exceptions::filesystem_exception +	  */ +	virtual void renameFolder(const folder::path& oldPath, const folder::path& newPath) = 0; + +	/** Test whether the specified folder exists. +	  * +	  * @param path virtual path of the folder +	  * @return true if the folder exists, false otherwise +	  */ +	virtual bool folderExists(const folder::path& path) const = 0; + +	/** Test whether the specified folder has subfolders. +	  * +	  * @param path virtual path of the folder +	  * @return true if the folder has at least one subfolder, +	  * false otherwise +	  */ +	virtual bool folderHasSubfolders(const folder::path& path) const = 0; + +	/** Returns the directory which represents the specified +	  * folder on the file system. +	  * +	  * @param path virtual path of the folder +	  * @param type type of directory to return +	  * @return corresponding directory on the file system +	  */ +	virtual const utility::file::path folderPathToFileSystemPath( +		const folder::path& path, +		const DirectoryType type +	) const = 0; + +	/** List subfolders in the specified folder. +	  * +	  * @param root root folder in which to start the search +	  * @param recursive if set to true, all the descendant are +	  * returned; if set to false, only direct children are returned. +	  * @return list of subfolders +	  */ +	virtual const std::vector <folder::path> listFolders( +		const folder::path& root, +		const bool recursive +	) const = 0; + + +	/** Try to detect the format of the specified Maildir store. +	  * If the format cannot be detected, a compatible implementation +	  * will be returned. +	  * +	  * @param store of which to detect format +	  * @return a Maildir format implementation for the specified store +	  */ +	static shared_ptr <maildirFormat> detect(const shared_ptr <maildirStore>& store); + +protected: + +	static const utility::file::path::component TMP_DIR;  /**< Ensure reliable delivery (not to be listed). */ +	static const utility::file::path::component CUR_DIR;  /**< No longer new messages. */ +	static const utility::file::path::component NEW_DIR;  /**< Unread messages. */ + + +	maildirFormat(const shared_ptr <context>& ctx); + + +	/** Returns the current context. +	  * +	  * @return current context +	  */ +	shared_ptr <context> getContext() const; + +	/** Quick checks whether this implementation can read the Maildir +	  * format in the specified directory. +	  * +	  * @return true if the implementation supports the specified +	  * Maildir, or false otherwise +	  */ +	virtual bool supports() const = 0; + +private: + +	shared_ptr <context> m_context; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/maildir/maildirMessage.cpp b/vmime-master/src/vmime/net/maildir/maildirMessage.cpp new file mode 100644 index 0000000..ae99c59 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirMessage.cpp @@ -0,0 +1,410 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirMessage.hpp" +#include "vmime/net/maildir/maildirMessagePart.hpp" +#include "vmime/net/maildir/maildirMessageStructure.hpp" +#include "vmime/net/maildir/maildirFolder.hpp" +#include "vmime/net/maildir/maildirUtils.hpp" +#include "vmime/net/maildir/maildirStore.hpp" + +#include "vmime/message.hpp" + +#include "vmime/exception.hpp" +#include "vmime/platform.hpp" + +#include "vmime/utility/outputStreamAdapter.hpp" +#include "vmime/utility/stringUtils.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +maildirMessage::maildirMessage(const shared_ptr <maildirFolder>& folder, const size_t num) +	: m_folder(folder), +	  m_num(num), +	  m_size(-1), +	  m_flags(FLAG_UNDEFINED), +	  m_expunged(false), +	  m_structure(null) { + +	folder->registerMessage(this); +} + + +maildirMessage::~maildirMessage() { + +	try { + +		shared_ptr <maildirFolder> folder = m_folder.lock(); + +		if (folder) { +			folder->unregisterMessage(this); +		} + +	} catch (...) { + +		// Don't throw in destructor +	} +} + + +void maildirMessage::onFolderClosed() { + +	m_folder.reset(); +} + + +size_t maildirMessage::getNumber() const { + +	return m_num; +} + + +const message::uid maildirMessage::getUID() const { + +	return m_uid; +} + + +size_t maildirMessage::getSize() const { + +	if (m_size == static_cast <size_t>(-1)) { +		throw exceptions::unfetched_object(); +	} + +	return m_size; +} + + +bool maildirMessage::isExpunged() const { + +	return m_expunged; +} + + +shared_ptr <const messageStructure> maildirMessage::getStructure() const { + +	if (!m_structure) { +		throw exceptions::unfetched_object(); +	} + +	return m_structure; +} + + +shared_ptr <messageStructure> maildirMessage::getStructure() { + +	if (!m_structure) { +		throw exceptions::unfetched_object(); +	} + +	return m_structure; +} + + +shared_ptr <const header> maildirMessage::getHeader() const { + +	if (!m_header) { +		throw exceptions::unfetched_object(); +	} + +	return m_header; +} + + +int maildirMessage::getFlags() const { + +	if (m_flags == FLAG_UNDEFINED) { +		throw exceptions::unfetched_object(); +	} + +	return m_flags; +} + + +void maildirMessage::setFlags(const int flags, const int mode) { + +	shared_ptr <maildirFolder> folder = m_folder.lock(); + +	if (!folder) { +		throw exceptions::folder_not_found(); +	} + +	folder->setMessageFlags(messageSet::byNumber(m_num), flags, mode); +} + + +void maildirMessage::extract( +	utility::outputStream& os, +	utility::progressListener* progress, +	const size_t start, +	const size_t length, +	const bool peek +) const { + +	extractImpl(os, progress, 0, m_size, start, length, peek); +} + + +void maildirMessage::extractPart( +	const shared_ptr <const messagePart>& p, +	utility::outputStream& os, +	utility::progressListener* progress, +	const size_t start, +	const size_t length, +	const bool peek +) const { + +	shared_ptr <const maildirMessagePart> mp = dynamicCast <const maildirMessagePart>(p); + +	extractImpl( +		os, progress, mp->getBodyParsedOffset(), mp->getBodyParsedLength(), +		start, length, peek +	); +} + + +void maildirMessage::extractImpl( +	utility::outputStream& os, +	utility::progressListener* progress, +	const size_t start, +	const size_t length, +	const size_t partialStart, +	const size_t partialLength, +	const bool /* peek */ +) const { + +	shared_ptr <const maildirFolder> folder = m_folder.lock(); + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	const utility::file::path path = folder->getMessageFSPath(m_num); +	shared_ptr <utility::file> file = fsf->create(path); + +	shared_ptr <utility::fileReader> reader = file->getFileReader(); +	shared_ptr <utility::inputStream> is = reader->getInputStream(); + +	is->skip(start + partialStart); + +	byte_t buffer[8192]; +	size_t remaining = +		(partialLength == static_cast <size_t>(-1) +			? length +			: std::min(partialLength, length) +		); + +	const size_t total = remaining; +	size_t current = 0; + +	if (progress) { +		progress->start(total); +	} + +	while (!is->eof() && remaining > 0) { + +		const size_t read = is->read(buffer, std::min(remaining, sizeof(buffer))); + +		remaining -= read; +		current += read; + +		os.write(buffer, read); + +		if (progress) { +			progress->progress(current, total); +		} +	} + +	if (progress) { +		progress->stop(total); +	} + +	// TODO: mark as read unless 'peek' is set +} + + +void maildirMessage::fetchPartHeader(const shared_ptr <messagePart>& p) { + +	shared_ptr <maildirFolder> folder = m_folder.lock(); + +	shared_ptr <maildirMessagePart> mp = dynamicCast <maildirMessagePart>(p); + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	const utility::file::path path = folder->getMessageFSPath(m_num); +	shared_ptr <utility::file> file = fsf->create(path); + +	shared_ptr <utility::fileReader> reader = file->getFileReader(); +	shared_ptr <utility::inputStream> is = reader->getInputStream(); + +	is->skip(mp->getHeaderParsedOffset()); + +	byte_t buffer[1024]; +	size_t remaining = mp->getHeaderParsedLength(); + +	string contents; +	contents.reserve(remaining); + +	while (!is->eof() && remaining > 0) { + +		const size_t read = is->read(buffer, std::min(remaining, sizeof(buffer))); + +		remaining -= read; + +		vmime::utility::stringUtils::appendBytesToString(contents, buffer, read); +	} + +	mp->getOrCreateHeader().parse(contents); +} + + +void maildirMessage::fetch(const shared_ptr <maildirFolder>& msgFolder, const fetchAttributes& options) { + +	shared_ptr <maildirFolder> folder = m_folder.lock(); + +	if (folder != msgFolder) { +		throw exceptions::folder_not_found(); +	} + +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	const utility::file::path path = folder->getMessageFSPath(m_num); +	shared_ptr <utility::file> file = fsf->create(path); + +	if (options.has(fetchAttributes::FLAGS)) { +		m_flags = maildirUtils::extractFlags(path.getLastComponent()); +	} + +	if (options.has(fetchAttributes::SIZE)) { +		m_size = file->getLength(); +	} + +	if (options.has(fetchAttributes::UID)) { +		m_uid = maildirUtils::extractId(path.getLastComponent()).getBuffer(); +	} + +	if (options.has(fetchAttributes::ENVELOPE | fetchAttributes::CONTENT_INFO | +	                fetchAttributes::FULL_HEADER | fetchAttributes::STRUCTURE | +	                fetchAttributes::IMPORTANCE)) { + +		string contents; + +		shared_ptr <utility::fileReader> reader = file->getFileReader(); +		shared_ptr <utility::inputStream> is = reader->getInputStream(); + +		// Need whole message contents for structure +		if (options.has(fetchAttributes::STRUCTURE)) { + +			byte_t buffer[16384]; + +			contents.reserve(file->getLength()); + +			while (!is->eof()) { +				const size_t read = is->read(buffer, sizeof(buffer)); +				vmime::utility::stringUtils::appendBytesToString(contents, buffer, read); +			} + +		// Need only header +		} else { + +			byte_t buffer[1024]; + +			contents.reserve(4096); + +			while (!is->eof()) { + +				const size_t read = is->read(buffer, sizeof(buffer)); +				vmime::utility::stringUtils::appendBytesToString(contents, buffer, read); + +				const size_t sep1 = contents.rfind("\r\n\r\n"); +				const size_t sep2 = contents.rfind("\n\n"); + +				if (sep1 != string::npos) { +					contents.erase(contents.begin() + sep1 + 4, contents.end()); +					break; +				} else if (sep2 != string::npos) { +					contents.erase(contents.begin() + sep2 + 2, contents.end()); +					break; +				} +			} +		} + +		vmime::message msg; +		msg.parse(contents); + +		// Extract structure +		if (options.has(fetchAttributes::STRUCTURE)) { +			m_structure = make_shared <maildirMessageStructure>(shared_ptr <maildirMessagePart>(), msg); +		} + +		// Extract some header fields or whole header +		if (options.has(fetchAttributes::ENVELOPE | +		                fetchAttributes::CONTENT_INFO | +		                fetchAttributes::FULL_HEADER | +		                fetchAttributes::IMPORTANCE)) { + +			getOrCreateHeader()->copyFrom(*(msg.getHeader())); +		} +	} +} + + +shared_ptr <header> maildirMessage::getOrCreateHeader() { + +	if (m_header) { +		return m_header; +	} else { +		return (m_header = make_shared <header>()); +	} +} + + +shared_ptr <vmime::message> maildirMessage::getParsedMessage() { + +	std::ostringstream oss; +	utility::outputStreamAdapter os(oss); + +	extract(os); + +	shared_ptr <vmime::message> msg = make_shared <vmime::message>(); +	msg->parse(oss.str()); + +	return msg; +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + diff --git a/vmime-master/src/vmime/net/maildir/maildirMessage.hpp b/vmime-master/src/vmime/net/maildir/maildirMessage.hpp new file mode 100644 index 0000000..8cd0aac --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirMessage.hpp @@ -0,0 +1,137 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/message.hpp" +#include "vmime/net/folder.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +class maildirFolder; + + +/** maildir message implementation. +  */ +class VMIME_EXPORT maildirMessage : public message { + +	friend class maildirFolder; + +	maildirMessage(const maildirMessage&) : message() { } + +public: + +	maildirMessage(const shared_ptr <maildirFolder>& folder, const size_t num); + +	~maildirMessage(); + + +	size_t getNumber() const; + +	const uid getUID() const; + +	size_t getSize() const; + +	bool isExpunged() const; + +	shared_ptr <const messageStructure> getStructure() const; +	shared_ptr <messageStructure> getStructure(); + +	shared_ptr <const header> getHeader() const; + +	int getFlags() const; +	void setFlags(const int flags, const int mode = FLAG_MODE_SET); + +	void extract( +		utility::outputStream& os, +		utility::progressListener* progress = NULL, +		const size_t start = 0, +		const size_t length = -1, +		const bool peek = false +	) const; + +	void extractPart( +		const shared_ptr <const messagePart>& p, +		utility::outputStream& os, +		utility::progressListener* progress = NULL, +		const size_t start = 0, +		const size_t length = -1, +		const bool peek = false +	) const; + +	void fetchPartHeader(const shared_ptr <messagePart>& p); + +	shared_ptr <vmime::message> getParsedMessage(); + +private: + +	void fetch(const shared_ptr <maildirFolder>& folder, const fetchAttributes& options); + +	void onFolderClosed(); + +	shared_ptr <header> getOrCreateHeader(); + +	void extractImpl( +		utility::outputStream& os, +		utility::progressListener* progress, +		const size_t start, +		const size_t length, +		const size_t partialStart, +		const size_t partialLength, +		const bool peek +	) const; + + +	weak_ptr <maildirFolder> m_folder; + +	size_t m_num; +	size_t m_size; +	int m_flags; +	bool m_expunged; +	uid m_uid; + +	shared_ptr <header> m_header; +	shared_ptr <messageStructure> m_structure; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp b/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp new file mode 100644 index 0000000..7448d7e --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp @@ -0,0 +1,178 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirMessagePart.hpp" +#include "vmime/net/maildir/maildirMessageStructure.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +maildirMessagePart::maildirMessagePart( +	const shared_ptr <maildirMessagePart>& parent, +	const size_t number, +	const bodyPart& part +) +	: m_parent(parent), +	  m_header(null), +	  m_number(number) { + +	m_headerParsedOffset = part.getHeader()->getParsedOffset(); +	m_headerParsedLength = part.getHeader()->getParsedLength(); + +	m_bodyParsedOffset = part.getBody()->getParsedOffset(); +	m_bodyParsedLength = part.getBody()->getParsedLength(); + +	m_size = part.getBody()->getContents()->getLength(); + +	m_mediaType = part.getBody()->getContentType(); + +	auto cdispField = part.getHeader()->ContentDisposition(); +	if (cdispField) { +		m_dispType = dynamic_cast <const contentDisposition&>(*cdispField->getValue()); +	} +} + + +maildirMessagePart::~maildirMessagePart() { + +} + + +void maildirMessagePart::initStructure(const bodyPart& part) { + +	if (part.getBody()->getPartList().size() == 0) { + +		m_structure = null; + +	} else { + +		m_structure = make_shared <maildirMessageStructure>( +			dynamicCast <maildirMessagePart>(shared_from_this()), part.getBody()->getPartList() +		); +	} +} + + +shared_ptr <const messageStructure> maildirMessagePart::getStructure() const { + +	if (m_structure) { +		return m_structure; +	} else { +		return maildirMessageStructure::emptyStructure(); +	} +} + + +shared_ptr <messageStructure> maildirMessagePart::getStructure() { + +	if (m_structure) { +		return m_structure; +	} else { +		return maildirMessageStructure::emptyStructure(); +	} +} + + +const mediaType& maildirMessagePart::getType() const { + +	return m_mediaType; +} + + +const contentDisposition &maildirMessagePart::getDisposition() const { + +	return m_dispType; +} + + +size_t maildirMessagePart::getSize() const { + +	return m_size; +} + + +size_t maildirMessagePart::getNumber() const { + +	return m_number; +} + + +shared_ptr <const header> maildirMessagePart::getHeader() const { + +	if (!m_header) { +		throw exceptions::unfetched_object(); +	} else { +		return m_header; +	} +} + + +header& maildirMessagePart::getOrCreateHeader() { + +	if (m_header) { +		return *m_header; +	} else { +		return *(m_header = make_shared <header>()); +	} +} + + +size_t maildirMessagePart::getHeaderParsedOffset() const { + +	return m_headerParsedOffset; +} + + +size_t maildirMessagePart::getHeaderParsedLength() const { + +	return m_headerParsedLength; +} + + +size_t maildirMessagePart::getBodyParsedOffset() const { + +	return m_bodyParsedOffset; +} + + +size_t maildirMessagePart::getBodyParsedLength() const { + +	return m_bodyParsedLength; +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR diff --git a/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp b/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp new file mode 100644 index 0000000..5ecc739 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp @@ -0,0 +1,106 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/message.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +class maildirMessageStructure; + + +class maildirMessagePart : public messagePart +{ +public: + +	maildirMessagePart( +		const shared_ptr <maildirMessagePart>& parent, +		const size_t number, +		const bodyPart& part +	); + +	~maildirMessagePart(); + + +	shared_ptr <const messageStructure> getStructure() const; +	shared_ptr <messageStructure> getStructure(); + +	weak_ptr <const maildirMessagePart> getParent() const { return (m_parent); } + +	const mediaType& getType() const; +	const contentDisposition &getDisposition() const; +	size_t getSize() const; +	size_t getNumber() const; + +	shared_ptr <const header> getHeader() const; + +	header& getOrCreateHeader(); + +	size_t getHeaderParsedOffset() const; +	size_t getHeaderParsedLength() const; + +	size_t getBodyParsedOffset() const; +	size_t getBodyParsedLength() const; + +	void initStructure(const bodyPart& part); + +private: + +	shared_ptr <maildirMessageStructure> m_structure; +	weak_ptr <maildirMessagePart> m_parent; +	shared_ptr <header> m_header; + +	size_t m_number; +	size_t m_size; +	mediaType m_mediaType; +	contentDisposition m_dispType; + +	size_t m_headerParsedOffset; +	size_t m_headerParsedLength; + +	size_t m_bodyParsedOffset; +	size_t m_bodyParsedLength; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp new file mode 100644 index 0000000..1e2f2cc --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp @@ -0,0 +1,104 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirMessageStructure.hpp" +#include "vmime/net/maildir/maildirMessagePart.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +shared_ptr <maildirMessageStructure> maildirMessageStructure::m_emptyStructure = make_shared <maildirMessageStructure>(); + + +maildirMessageStructure::maildirMessageStructure() +{ +} + + +maildirMessageStructure::maildirMessageStructure( +	const shared_ptr <maildirMessagePart>& parent, +	const bodyPart& part +) { + +	shared_ptr <maildirMessagePart> mpart = make_shared <maildirMessagePart>(parent, 0, part); +	mpart->initStructure(part); + +	m_parts.push_back(mpart); +} + + +maildirMessageStructure::maildirMessageStructure( +	const shared_ptr <maildirMessagePart>& parent, +	const std::vector <shared_ptr <const vmime::bodyPart> >& list +) { + +	for (size_t i = 0 ; i < list.size() ; ++i) { + +		shared_ptr <maildirMessagePart> mpart = make_shared <maildirMessagePart>(parent, i, *list[i]); +		mpart->initStructure(*list[i]); + +		m_parts.push_back(mpart); +	} +} + + +shared_ptr <const messagePart> maildirMessageStructure::getPartAt(const size_t x) const { + +	return m_parts[x]; +} + + +shared_ptr <messagePart> maildirMessageStructure::getPartAt(const size_t x) { + +	return m_parts[x]; +} + + +size_t maildirMessageStructure::getPartCount() const { + +	return m_parts.size(); +} + + +// static +shared_ptr <maildirMessageStructure> maildirMessageStructure::emptyStructure() { + +	return m_emptyStructure; +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR diff --git a/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp new file mode 100644 index 0000000..1a20ea4 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp @@ -0,0 +1,82 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/message.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +class maildirMessagePart; + + +class maildirMessageStructure : public messageStructure { + +public: + +	maildirMessageStructure(); +	maildirMessageStructure( +		const shared_ptr <maildirMessagePart>& parent, +		const bodyPart& part +	); +	maildirMessageStructure( +		const shared_ptr <maildirMessagePart>& parent, +		const std::vector <shared_ptr <const vmime::bodyPart> >& list +	); + + +	shared_ptr <const messagePart> getPartAt(const size_t x) const; +	shared_ptr <messagePart> getPartAt(const size_t x); + +	size_t getPartCount() const; + +	static shared_ptr <maildirMessageStructure> emptyStructure(); + +private: + +	static shared_ptr <maildirMessageStructure> m_emptyStructure; + +	std::vector <shared_ptr <maildirMessagePart> > m_parts; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp new file mode 100644 index 0000000..f9d92d3 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp @@ -0,0 +1,76 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirServiceInfos.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +maildirServiceInfos::maildirServiceInfos() { + +} + + +const string maildirServiceInfos::getPropertyPrefix() const { + +	return "store.maildir."; +} + + +const maildirServiceInfos::props& maildirServiceInfos::getProperties() const { + +	static props maildirProps = { +		property(serviceInfos::property::SERVER_ROOTPATH, serviceInfos::property::FLAG_REQUIRED) +	}; + +	return maildirProps; +} + + +const std::vector <serviceInfos::property> maildirServiceInfos::getAvailableProperties() const { + +	std::vector <property> list; +	const props& p = getProperties(); + +	list.push_back(p.PROPERTY_SERVER_ROOTPATH); + +	return list; +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + diff --git a/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp new file mode 100644 index 0000000..827a7d7 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp @@ -0,0 +1,69 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/serviceInfos.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +/** Information about maildir service. +  */ +class VMIME_EXPORT maildirServiceInfos : public serviceInfos { + +public: + +	maildirServiceInfos(); + +	struct props { +		serviceInfos::property PROPERTY_SERVER_ROOTPATH; +	}; + +	const props& getProperties() const; + +	const string getPropertyPrefix() const; +	const std::vector <serviceInfos::property> getAvailableProperties() const; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/maildir/maildirStore.cpp b/vmime-master/src/vmime/net/maildir/maildirStore.cpp new file mode 100644 index 0000000..a994f45 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirStore.cpp @@ -0,0 +1,294 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirStore.hpp" + +#include "vmime/net/maildir/maildirFolder.hpp" +#include "vmime/net/maildir/maildirFormat.hpp" + +#include "vmime/exception.hpp" +#include "vmime/platform.hpp" + +#include "vmime/net/defaultConnectionInfos.hpp" + + +// Helpers for service properties +#define GET_PROPERTY(type, prop) \ +	(getInfos().getPropertyValue <type>(getSession(), \ +		dynamic_cast <const maildirServiceInfos&>(getInfos()).getProperties().prop)) +#define HAS_PROPERTY(prop) \ +	(getInfos().hasProperty(getSession(), \ +		dynamic_cast <const maildirServiceInfos&>(getInfos()).getProperties().prop)) + + +namespace vmime { +namespace net { +namespace maildir { + + +maildirStore::maildirStore( +	const shared_ptr <session>& sess, +	const shared_ptr <security::authenticator>& auth +) +	: store(sess, getInfosInstance(), auth), +	  m_connected(false) { + +} + + +maildirStore::~maildirStore() { + +	try { + +		if (isConnected()) { +			disconnect(); +		} + +	} catch (...) { + +		// Don't throw in destructor +	} +} + + +const string maildirStore::getProtocolName() const { + +	return "maildir"; +} + + +shared_ptr <folder> maildirStore::getRootFolder() { + +	if (!isConnected()) { +		throw exceptions::illegal_state("Not connected"); +	} + +	return shared_ptr <maildirFolder>( +		new maildirFolder( +			folder::path(), +			dynamicCast <maildirStore>(shared_from_this()) +		) +	); +} + + +shared_ptr <folder> maildirStore::getDefaultFolder() { + +	if (!isConnected()) { +		throw exceptions::illegal_state("Not connected"); +	} + +	return shared_ptr <maildirFolder>( +		new maildirFolder( +			folder::path::component("inbox"), +			dynamicCast <maildirStore>(shared_from_this()) +		) +	); +} + + +shared_ptr <folder> maildirStore::getFolder(const folder::path& path) { + +	if (!isConnected()) { +		throw exceptions::illegal_state("Not connected"); +	} + +	return shared_ptr <maildirFolder>( +		new maildirFolder( +			path, +			dynamicCast <maildirStore>(shared_from_this()) +		) +	); +} + + +bool maildirStore::isValidFolderName(const folder::path::component& name) const { + +	if (!platform::getHandler()->getFileSystemFactory()->isValidPathComponent(name)) { +		return false; +	} + +	const string& buf = name.getBuffer(); + +	// Name cannot start/end with spaces +	if (utility::stringUtils::trim(buf) != buf) { +		return false; +	} + +	// Name cannot start with '.' +	const size_t length = buf.length(); +	size_t pos = 0; + +	while ((pos < length) && (buf[pos] == '.')) { +		++pos; +	} + +	return (pos == 0); +} + + +void maildirStore::connect() { + +	if (isConnected()) { +		throw exceptions::already_connected(); +	} + +	// Get root directory +	shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); + +	m_fsPath = fsf->stringToPath(GET_PROPERTY(string, PROPERTY_SERVER_ROOTPATH)); + +	shared_ptr <utility::file> rootDir = fsf->create(m_fsPath); + +	// Try to create the root directory if it does not exist +	if (!(rootDir->exists() && rootDir->isDirectory())) { + +		try { +			rootDir->createDirectory(); +		} catch (exceptions::filesystem_exception& e) { +			throw exceptions::connection_error("Cannot create root directory.", e); +		} +	} + +	m_format = maildirFormat::detect(dynamicCast <maildirStore>(shared_from_this())); + +	m_connected = true; +} + + +bool maildirStore::isConnected() const { + +	return m_connected; +} + + +bool maildirStore::isSecuredConnection() const { + +	return false; +} + + +shared_ptr <connectionInfos> maildirStore::getConnectionInfos() const { + +	return make_shared <defaultConnectionInfos>("localhost", static_cast <port_t>(0)); +} + + +void maildirStore::disconnect() { + +	for (std::list <maildirFolder*>::iterator it = m_folders.begin() ; +	     it != m_folders.end() ; ++it) { + +		(*it)->onStoreDisconnected(); +	} + +	m_folders.clear(); + +	m_connected = false; +} + + +void maildirStore::noop() { + +	// Nothing to do. +} + + +shared_ptr <maildirFormat> maildirStore::getFormat() { + +	return m_format; +} + + +shared_ptr <const maildirFormat> maildirStore::getFormat() const { + +	return m_format; +} + + +void maildirStore::registerFolder(maildirFolder* folder) { + +	m_folders.push_back(folder); +} + + +void maildirStore::unregisterFolder(maildirFolder* folder) { + +	std::list <maildirFolder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder); + +	if (it != m_folders.end()) { +		m_folders.erase(it); +	} +} + + +const utility::path& maildirStore::getFileSystemPath() const { + +	return m_fsPath; +} + + +int maildirStore::getCapabilities() const { + +	return CAPABILITY_CREATE_FOLDER | +	       CAPABILITY_RENAME_FOLDER | +	       CAPABILITY_ADD_MESSAGE | +	       CAPABILITY_COPY_MESSAGE | +	       CAPABILITY_DELETE_MESSAGE | +	       CAPABILITY_PARTIAL_FETCH | +	       CAPABILITY_MESSAGE_FLAGS | +	       CAPABILITY_EXTRACT_PART; +} + + + +// Service infos + +maildirServiceInfos maildirStore::sm_infos; + + +const serviceInfos& maildirStore::getInfosInstance() { + +	return sm_infos; +} + + +const serviceInfos& maildirStore::getInfos() const { + +	return sm_infos; +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + diff --git a/vmime-master/src/vmime/net/maildir/maildirStore.hpp b/vmime-master/src/vmime/net/maildir/maildirStore.hpp new file mode 100644 index 0000000..13255c0 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirStore.hpp @@ -0,0 +1,123 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/store.hpp" +#include "vmime/net/socket.hpp" +#include "vmime/net/folder.hpp" + +#include "vmime/net/maildir/maildirFormat.hpp" +#include "vmime/net/maildir/maildirServiceInfos.hpp" + +#include "vmime/utility/file.hpp" + +#include <ostream> + + +namespace vmime { +namespace net { +namespace maildir { + + +class maildirFolder; + + +/** maildir store service. +  */ +class VMIME_EXPORT maildirStore : public store { + +	friend class maildirFolder; + +public: + +	maildirStore( +		const shared_ptr <session>& sess, +		const shared_ptr <security::authenticator>& auth +	); + +	~maildirStore(); + +	const string getProtocolName() const; + +	shared_ptr <folder> getDefaultFolder(); +	shared_ptr <folder> getRootFolder(); +	shared_ptr <folder> getFolder(const folder::path& path); + +	bool isValidFolderName(const folder::path::component& name) const; + +	static const serviceInfos& getInfosInstance(); +	const serviceInfos& getInfos() const; + +	void connect(); +	bool isConnected() const; +	void disconnect(); + +	void noop(); + +	const utility::path& getFileSystemPath() const; + +	int getCapabilities() const; + +	bool isSecuredConnection() const; +	shared_ptr <connectionInfos> getConnectionInfos() const; + +	shared_ptr <maildirFormat> getFormat(); +	shared_ptr <const maildirFormat> getFormat() const; + +private: + +	void registerFolder(maildirFolder* folder); +	void unregisterFolder(maildirFolder* folder); + + +	std::list <maildirFolder*> m_folders; + +	shared_ptr <maildirFormat> m_format; + +	bool m_connected; + +	utility::path m_fsPath; + + +	// Service infos +	static maildirServiceInfos sm_infos; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/maildir/maildirUtils.cpp b/vmime-master/src/vmime/net/maildir/maildirUtils.cpp new file mode 100644 index 0000000..9942e56 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirUtils.cpp @@ -0,0 +1,288 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirUtils.hpp" +#include "vmime/net/maildir/maildirStore.hpp" + +#include "vmime/utility/random.hpp" +#include "vmime/platform.hpp" + +#include "vmime/exception.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +bool maildirUtils::isMessageFile(const utility::file& file) { + +	// Ignore files which name begins with '.' +	if (file.isFile() && +	    file.getFullPath().getLastComponent().getBuffer().length() >= 1 && +	    file.getFullPath().getLastComponent().getBuffer()[0] != '.') { + +		return true; +	} + +	return false; +} + + +// NOTE ABOUT ID/FLAGS SEPARATOR +// ----------------------------- +// In the maildir specification, the character ':' is used to separate +// the unique identifier and the message flags. +// +// On Windows (and particularly FAT file systems), ':' is not allowed +// in a filename, so we use a dash ('-') instead. This is the solution +// used by Mutt/Win32, so we also use it here. +// +// To be compatible between implementations, we check for both +// characters when reading file names. + + +const utility::file::path::component maildirUtils::extractId( +	const utility::file::path::component& filename +) { + +	size_t sep = filename.getBuffer().rfind(':');  // try colon + +	if (sep == string::npos) { +		sep = filename.getBuffer().rfind('-');  // try dash (Windows) +		if (sep == string::npos) return (filename); +	} + +	return utility::path::component( +		string(filename.getBuffer().begin(), filename.getBuffer().begin() + sep) +	); +} + + +int maildirUtils::extractFlags(const utility::file::path::component& comp) { + +	size_t sep = comp.getBuffer().rfind(':');  // try colon + +	if (sep == string::npos) { +		sep = comp.getBuffer().rfind('-');  // try dash (Windows) +		if (sep == string::npos) return 0; +	} + +	const string flagsString(comp.getBuffer().begin() + sep + 1, comp.getBuffer().end()); +	const size_t count = flagsString.length(); + +	int flags = 0; + +	for (size_t i = 0 ; i < count ; ++i) { + +		switch (flagsString[i]) { +			case 'R': case 'r': flags |= message::FLAG_REPLIED; break; +			case 'S': case 's': flags |= message::FLAG_SEEN; break; +			case 'T': case 't': flags |= message::FLAG_DELETED; break; +			case 'F': case 'f': flags |= message::FLAG_MARKED; break; +			case 'P': case 'p': flags |= message::FLAG_PASSED; break; +			case 'D': case 'd': flags |= message::FLAG_DRAFT; break; +		} +	} + +	return flags; +} + + +const utility::file::path::component maildirUtils::buildFlags(const int flags) { + +	string str; +	str.reserve(8); + +	str += "2,"; + +	if (flags & message::FLAG_MARKED)  str += "F"; +	if (flags & message::FLAG_PASSED)  str += "P"; +	if (flags & message::FLAG_REPLIED) str += "R"; +	if (flags & message::FLAG_SEEN)    str += "S"; +	if (flags & message::FLAG_DELETED) str += "T"; +	if (flags & message::FLAG_DRAFT)   str += "D"; + +	return utility::file::path::component(str); +} + + +const utility::file::path::component maildirUtils::buildFilename( +	const utility::file::path::component& id, +	const int flags +) { + +	if (flags == message::FLAG_RECENT) { +		return id; +	} else { +		return buildFilename(id, buildFlags(flags)); +	} +} + + +const utility::file::path::component maildirUtils::buildFilename( +	const utility::file::path::component& id, +	const utility::file::path::component& flags +) { + +#if VMIME_PLATFORM_IS_WINDOWS +	static const char DELIMITER[] = "-"; +#else +	static const char DELIMITER[] = ":"; +#endif + +	return utility::path::component(id.getBuffer() + DELIMITER + flags.getBuffer()); +} + + +const utility::file::path::component maildirUtils::generateId() { + +	std::ostringstream oss; +	oss.imbue(std::locale::classic()); + +	oss << utility::random::getTime(); +	oss << "."; +	oss << utility::random::getProcess(); +	oss << "."; +	oss << utility::random::getString(6); +	oss << "."; +	oss << platform::getHandler()->getHostName(); + +	return utility::file::path::component(oss.str()); +} + + +void maildirUtils::recursiveFSDelete(const shared_ptr <utility::file>& dir) { + +	shared_ptr <utility::fileIterator> files = dir->getFiles(); + +	// First, delete files and subdirectories in this directory +	while (files->hasMoreElements()) { + +		shared_ptr <utility::file> file = files->nextElement(); + +		if (file->isDirectory()) { + +			maildirUtils::recursiveFSDelete(file); + +		} else { + +			try { +				file->remove(); +			} catch (exceptions::filesystem_exception&) { +				// Ignore +			} +		} +	} + +	// Then, delete this (empty) directory +	try { +		dir->remove(); +	} catch (exceptions::filesystem_exception&) { +		// Ignore +	} +} + + + +class maildirMessageSetEnumerator : public messageSetEnumerator { + +public: + +	maildirMessageSetEnumerator(const size_t msgCount) +		: m_msgCount(msgCount) { + +	} + +	void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) { + +		size_t last = range.getLast(); +		if (last == size_t(-1)) last = m_msgCount; + +		for (size_t i = range.getFirst() ; i <= last ; ++i) { +			list.push_back(i); +		} +	} + +	void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) { + +		// Not supported +	} + +public: + +	std::vector <size_t> list; + +private: + +	size_t m_msgCount; +}; + + +// static +const std::vector <size_t> maildirUtils::messageSetToNumberList( +	const messageSet& msgs, +	const size_t msgCount +) { + +	maildirMessageSetEnumerator en(msgCount); +	msgs.enumerate(en); + +	return en.list; +} + + + +// +// messageIdComparator +// + +maildirUtils::messageIdComparator::messageIdComparator( +	const utility::file::path::component& comp +) +	: m_comp(maildirUtils::extractId(comp)) { + +} + + +bool maildirUtils::messageIdComparator::operator()( +	const utility::file::path::component& other +) const { + +	return m_comp == maildirUtils::extractId(other); +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + diff --git a/vmime-master/src/vmime/net/maildir/maildirUtils.hpp b/vmime-master/src/vmime/net/maildir/maildirUtils.hpp new file mode 100644 index 0000000..94ab998 --- /dev/null +++ b/vmime-master/src/vmime/net/maildir/maildirUtils.hpp @@ -0,0 +1,160 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/utility/file.hpp" +#include "vmime/utility/path.hpp" + +#include "vmime/net/messageSet.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +class maildirStore; + + +/** Miscellaneous helpers functions for maildir messaging system. +  */ +class VMIME_EXPORT maildirUtils { + +public: + +	/** Comparator for message filenames, based only on the +	  * unique identifier part of the filename. +	  */ +	class messageIdComparator { + +	public: + +		messageIdComparator(const utility::file::path::component& comp); + +		bool operator()(const utility::file::path::component& other) const; + +	private: + +		const utility::file::path::component m_comp; +	}; + +	/** Test whether the specified file-system object is a message. +	  * +	  * @param file reference to a file-system object +	  * @return true if the specified object is a message file, +	  * false otherwise +	  */ +	static bool isMessageFile(const utility::file& file); + +	/** Extract the unique identifier part of the message filename. +	  * Eg: for the filename "1071577232.28549.m03s:2,RS", it will +	  * return "1071577232.28549.m03s". +	  * +	  * @param filename filename part +	  * @return part of the filename that corresponds to the unique +	  * identifier of the message +	  */ +	static const utility::file::path::component extractId(const utility::file::path::component& filename); + +	/** Extract message flags from the specified message filename. +	  * Eg: for the filename "1071577232.28549.m03s:2,RS", it will +	  * return (message::FLAG_SEEN | message::FLAG_REPLIED). +	  * +	  * @param comp filename part +	  * @return message flags extracted from the specified filename +	  */ +	static int extractFlags(const utility::file::path::component& comp); + +	/** Return a string representing the specified message flags. +	  * Eg: for (message::FLAG_SEEN | message::FLAG_REPLIED), it will +	  * return "RS". +	  * +	  * @param flags set of flags +	  * @return message flags in a string representation +	  */ +	static const utility::file::path::component buildFlags(const int flags); + +	/** Build a filename with the specified id and flags. +	  * +	  * @param id id part of the filename +	  * @param flags flags part of the filename +	  * @return message filename +	  */ +	static const utility::file::path::component buildFilename( +		const utility::file::path::component& id, +		const utility::file::path::component& flags +	); + +	/** Build a filename with the specified id and flags. +	  * +	  * @param id id part of the filename +	  * @param flags set of flags +	  * @return message filename +	  */ +	static const utility::file::path::component buildFilename( +		const utility::file::path::component& id, +		const int flags +	); + +	/** Generate a new unique message identifier. +	  * +	  * @return unique message id +	  */ +	static const utility::file::path::component generateId(); + +	/** Recursively delete a directory on the file system. +	  * +	  * @param dir directory to delete +	  */ +	static void recursiveFSDelete(const shared_ptr <utility::file>& dir); + +	/** Returns a list of message numbers given a message set. +	  * +	  * @param msgs message set +	  * @param msgCount number of messages in folder +	  * @return list of message numbers +	  */ +	static const std::vector <size_t> messageSetToNumberList( +		const messageSet& msgs, +		const size_t msgCount +	); +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED | 
