diff options
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 |