diff --git a/ChangeLog b/ChangeLog index e15ffb59..4cd1f713 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ VERSION 0.8.2cvs ================ +2007-03-02 Vincent Richard + + * Maildir: added support for "Courier" Maildir. + 2006-12-20 Vincent Richard * Started version 0.8.2. diff --git a/SConstruct b/SConstruct index b8f74074..5d4e4fb0 100644 --- a/SConstruct +++ b/SConstruct @@ -269,7 +269,10 @@ libvmime_messaging_proto_sources = [ 'net/maildir/maildirStore.cpp', 'net/maildir/maildirStore.hpp', 'net/maildir/maildirFolder.cpp', 'net/maildir/maildirFolder.hpp', 'net/maildir/maildirMessage.cpp', 'net/maildir/maildirMessage.hpp', - 'net/maildir/maildirUtils.cpp', 'net/maildir/maildirUtils.hpp' + 'net/maildir/maildirUtils.cpp', 'net/maildir/maildirUtils.hpp', + 'net/maildir/maildirFormat.cpp', 'net/maildir/maildirFormat.hpp', + 'net/maildir/format/kmailMaildirFormat.cpp', 'net/maildir/format/kmailMaildirFormat.hpp', + 'net/maildir/format/courierMaildirFormat.cpp', 'net/maildir/format/courierMaildirFormat.hpp' ] ], [ @@ -366,7 +369,8 @@ libvmimetest_sources = [ 'tests/security/digest/sha1Test.cpp', # =============================== Net ================================ 'tests/net/smtp/SMTPTransportTest.cpp', - 'tests/net/smtp/SMTPResponseTest.cpp' + 'tests/net/smtp/SMTPResponseTest.cpp', + 'tests/net/maildir/maildirStoreTest.cpp' ] libvmime_autotools = [ diff --git a/src/net/maildir/format/courierMaildirFormat.cpp b/src/net/maildir/format/courierMaildirFormat.cpp new file mode 100644 index 00000000..627a7279 --- /dev/null +++ b/src/net/maildir/format/courierMaildirFormat.cpp @@ -0,0 +1,533 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// 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 2 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/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(ref ctx) + : maildirFormat(ctx) +{ +} + + +const string courierMaildirFormat::getName() const +{ + return "courier"; +} + + +void courierMaildirFormat::createFolder(const folder::path& path) +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) + throw exceptions::invalid_folder_name(); + + ref rootDir = fsf->create + (folderPathToFileSystemPath(path, ROOT_DIRECTORY)); + + ref newDir = fsf->create + (folderPathToFileSystemPath(path, NEW_DIRECTORY)); + ref tmpDir = fsf->create + (folderPathToFileSystemPath(path, TMP_DIRECTORY)); + ref curDir = fsf->create + (folderPathToFileSystemPath(path, CUR_DIRECTORY)); + + rootDir->createDirectory(true); + + newDir->createDirectory(false); + tmpDir->createDirectory(false); + curDir->createDirectory(false); + + ref maildirFile = fsf->create + (folderPathToFileSystemPath(path, ROOT_DIRECTORY) + / utility::file::path::component("maildirfolder")); + + maildirFile->createFile(); +} + + +void courierMaildirFormat::destroyFolder(const folder::path& path) +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + // Recursively delete directories of subfolders + const std::vector folders = listFolders(path, true); + + for (unsigned int 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 folders = listFolders(oldPath, true); + + for (unsigned int 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) +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + const utility::file::path oldFSPath = + folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY); + + const utility::file::path newFSPath = + folderPathToFileSystemPath(newPath, ROOT_DIRECTORY); + + ref rootDir = fsf->create(oldFSPath); + rootDir->rename(newFSPath); +} + + +const bool courierMaildirFormat::folderExists(const folder::path& path) const +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + ref rootDir = fsf->create + (folderPathToFileSystemPath(path, ROOT_DIRECTORY)); + + ref newDir = fsf->create + (folderPathToFileSystemPath(path, NEW_DIRECTORY)); + ref tmpDir = fsf->create + (folderPathToFileSystemPath(path, TMP_DIRECTORY)); + ref curDir = fsf->create + (folderPathToFileSystemPath(path, CUR_DIRECTORY)); + + ref 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; +} + + +const bool courierMaildirFormat::folderHasSubfolders(const folder::path& path) const +{ + std::vector 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 (int 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 courierMaildirFormat::listFolders + (const folder::path& root, const bool recursive) const +{ + // First, list directories + std::vector dirs; + listDirectories(root, dirs, false); + + // Then, map directories to folders + std::vector folders; + + for (unsigned int i = 0, n = dirs.size() ; i < n ; ++i) + { + const string dir = dirs[i].substr(1) + "."; + folder::path path; + + for (string::size_type 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; +} + + +const bool courierMaildirFormat::listDirectories(const folder::path& root, + std::vector & dirs, const bool onlyTestForExistence) const +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + ref 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 (int i = 0, n = root.getSize() ; i < n ; ++i) + base += "." + toModifiedUTF7(root[i]); + } + + // Enumerate directories + ref it = rootDir->getFiles(); + + while (it->hasMoreElements()) + { + ref 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 +const 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))); +} + + +const bool courierMaildirFormat::supports() const +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + ref rootDir = fsf->create + (getContext()->getStore()->getFileSystemPath()); + + if (rootDir->exists()) + { + // Try to find a file named "maildirfolder", which indicates + // the Maildir is in Courier format + ref it = rootDir->getFiles(); + + while (it->hasMoreElements()) + { + ref file = it->nextElement(); + + if (isSubfolderDirectory(*file)) + { + ref folderFile = fsf->create + (file->getFullPath() / utility::file::path::component("maildirfolder")); + + if (folderFile->exists() && folderFile->isFile()) + return true; + } + } + } + + return false; +} + + +} // format +} // maildir +} // net +} // vmime + diff --git a/src/net/maildir/format/kmailMaildirFormat.cpp b/src/net/maildir/format/kmailMaildirFormat.cpp new file mode 100644 index 00000000..51f834c0 --- /dev/null +++ b/src/net/maildir/format/kmailMaildirFormat.cpp @@ -0,0 +1,310 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// 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 2 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/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(ref ctx) + : maildirFormat(ctx) +{ +} + + +const string kmailMaildirFormat::getName() const +{ + return "kmail"; +} + + +void kmailMaildirFormat::createFolder(const folder::path& path) +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) + throw exceptions::invalid_folder_name(); + + ref rootDir = fsf->create + (folderPathToFileSystemPath(path, ROOT_DIRECTORY)); + + ref newDir = fsf->create + (folderPathToFileSystemPath(path, NEW_DIRECTORY)); + ref tmpDir = fsf->create + (folderPathToFileSystemPath(path, TMP_DIRECTORY)); + ref 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 + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + maildirUtils::recursiveFSDelete(fsf->create + (folderPathToFileSystemPath(path, ROOT_DIRECTORY))); // root + + maildirUtils::recursiveFSDelete(fsf->create + (folderPathToFileSystemPath(path, CONTAINER_DIRECTORY))); // container +} + + +const bool kmailMaildirFormat::folderExists(const folder::path& path) const +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + ref rootDir = fsf->create + (folderPathToFileSystemPath(path, ROOT_DIRECTORY)); + + ref newDir = fsf->create + (folderPathToFileSystemPath(path, NEW_DIRECTORY)); + ref tmpDir = fsf->create + (folderPathToFileSystemPath(path, TMP_DIRECTORY)); + ref 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 int count = (type == CONTAINER_DIRECTORY + ? path.getSize() : path.getSize() - 1); + + // Parent folders + for (int 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 kmailMaildirFormat::listFolders + (const folder::path& root, const bool recursive) const +{ + std::vector list; + listFoldersImpl(list, root, recursive); + + return list; +} + + +void kmailMaildirFormat::listFoldersImpl + (std::vector & list, const folder::path& root, const bool recursive) const +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + ref rootDir = fsf->create(folderPathToFileSystemPath(root, + root.isEmpty() ? ROOT_DIRECTORY : CONTAINER_DIRECTORY)); + + if (rootDir->exists()) + { + ref it = rootDir->getFiles(); + + while (it->hasMoreElements()) + { + ref 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 +const 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) +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + ref rootDir = fsf->create + (folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY)); + ref 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; + } +} + + +const bool kmailMaildirFormat::folderHasSubfolders(const folder::path& path) const +{ + utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + + ref rootDir = fsf->create + (folderPathToFileSystemPath(path, CONTAINER_DIRECTORY)); + + ref it = rootDir->getFiles(); + + while (it->hasMoreElements()) + { + ref file = it->nextElement(); + + if (isSubfolderDirectory(*file)) + return true; + } + + return false; +} + + +const bool kmailMaildirFormat::supports() const +{ + // This is the default + return true; +} + + +} // format +} // maildir +} // net +} // vmime + diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp index e838c775..f994a8c6 100644 --- a/src/net/maildir/maildirFolder.cpp +++ b/src/net/maildir/maildirFolder.cpp @@ -22,6 +22,7 @@ #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/utility/smartPtr.hpp" @@ -91,23 +92,8 @@ const int maildirFolder::getFlags() { int flags = 0; - utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - - ref rootDir = fsf->create - (maildirUtils::getFolderFSPath(m_store.acquire(), m_path, maildirUtils::FOLDER_PATH_CONTAINER)); - - ref it = rootDir->getFiles(); - - while (it->hasMoreElements()) - { - ref file = it->nextElement(); - - if (maildirUtils::isSubfolderDirectory(*file)) - { - flags |= FLAG_CHILDREN; // Contains at least one sub-folder - break; - } - } + if (m_store.acquire()->getFormat()->folderHasSubfolders(m_path)) + flags |= FLAG_CHILDREN; // Contains at least one sub-folder return (flags); } @@ -207,26 +193,7 @@ void maildirFolder::create(const int /* type */) // Create directory on file system try { - utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - - if (!fsf->isValidPath(maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_ROOT))) - throw exceptions::invalid_folder_name(); - - ref rootDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_ROOT)); - - ref newDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_NEW)); - ref tmpDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_TMP)); - ref curDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_CUR)); - - rootDir->createDirectory(true); - - newDir->createDirectory(false); - tmpDir->createDirectory(false); - curDir->createDirectory(false); + store->getFormat()->createFolder(m_path); } catch (exceptions::filesystem_exception& e) { @@ -251,18 +218,10 @@ void maildirFolder::destroy() else if (isOpen()) throw exceptions::illegal_state("Folder is open"); - // Delete 'folder' and '.folder.directory' directories - utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - - ref rootDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_ROOT)); - ref contDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_CONTAINER)); - + // Delete folder try { - maildirUtils::recursiveFSDelete(rootDir); - maildirUtils::recursiveFSDelete(contDir); + store->getFormat()->destroyFolder(m_path); } catch (std::exception&) { @@ -282,22 +241,7 @@ const bool maildirFolder::exists() { ref store = m_store.acquire(); - utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - - ref rootDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_ROOT)); - - ref newDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_NEW)); - ref tmpDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_TMP)); - ref curDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_CUR)); - - return (rootDir->exists() && rootDir->isDirectory() && - newDir->exists() && newDir->isDirectory() && - tmpDir->exists() && tmpDir->isDirectory() && - curDir->exists() && curDir->isDirectory()); + return store->getFormat()->folderExists(m_path); } @@ -318,12 +262,12 @@ void maildirFolder::scanFolder() utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - utility::file::path newDirPath = maildirUtils::getFolderFSPath - (store, m_path, maildirUtils::FOLDER_PATH_NEW); + utility::file::path newDirPath = store->getFormat()->folderPathToFileSystemPath + (m_path, maildirFormat::NEW_DIRECTORY); ref newDir = fsf->create(newDirPath); - utility::file::path curDirPath = maildirUtils::getFolderFSPath - (store, m_path, maildirUtils::FOLDER_PATH_CUR); + utility::file::path curDirPath = store->getFormat()->folderPathToFileSystemPath + (m_path, maildirFormat::CUR_DIRECTORY); ref curDir = fsf->create(curDirPath); // New received messages (new/) @@ -531,39 +475,17 @@ void maildirFolder::listFolders(std::vector >& list, const bool re try { - utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); + std::vector pathList = + store->getFormat()->listFolders(m_path, recursive); - ref rootDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, - m_path.isEmpty() ? maildirUtils::FOLDER_PATH_ROOT - : maildirUtils::FOLDER_PATH_CONTAINER)); + list.reserve(pathList.size()); - if (rootDir->exists()) + for (unsigned int i = 0, n = pathList.size() ; i < n ; ++i) { - ref it = rootDir->getFiles(); + ref subFolder = + vmime::create (pathList[i], store); - while (it->hasMoreElements()) - { - ref file = it->nextElement(); - - if (maildirUtils::isSubfolderDirectory(*file)) - { - const utility::path subPath = - m_path / file->getFullPath().getLastComponent(); - - ref subFolder = - vmime::create (subPath, store); - - list.push_back(subFolder); - - if (recursive) - subFolder->listFolders(list, true); - } - } - } - else - { - // No sub-folder + list.push_back(subFolder); } } catch (exceptions::filesystem_exception& e) @@ -585,50 +507,12 @@ void maildirFolder::rename(const folder::path& newPath) throw exceptions::invalid_folder_name(); // Rename the directory on the file system - utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - - ref rootDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_ROOT)); - ref contDir = fsf->create - (maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_CONTAINER)); - try { - const utility::file::path newRootPath = - maildirUtils::getFolderFSPath(store, newPath, maildirUtils::FOLDER_PATH_ROOT); - const utility::file::path newContPath = - maildirUtils::getFolderFSPath(store, newPath, maildirUtils::FOLDER_PATH_CONTAINER); - - 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 - } + store->getFormat()->renameFolder(m_path, newPath); } - catch (exceptions::filesystem_exception& e) + catch (vmime::exception& e) { - // Revert to old location - const utility::file::path rootPath = - maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_ROOT); - const utility::file::path contPath = - maildirUtils::getFolderFSPath(store, m_path, maildirUtils::FOLDER_PATH_CONTAINER); - - try - { - rootDir->rename(rootPath); - contDir->rename(contPath); - } - catch (exceptions::filesystem_exception& e) - { - // Ignore - } - throw exceptions::command_error("RENAME", "", "", e); } @@ -874,8 +758,8 @@ void maildirFolder::setMessageFlagsImpl utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - utility::file::path curDirPath = maildirUtils::getFolderFSPath - (store, m_path, maildirUtils::FOLDER_PATH_CUR); + utility::file::path curDirPath = store->getFormat()-> + folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); for (std::vector ::const_iterator it = nums.begin() ; it != nums.end() ; ++it) @@ -946,10 +830,10 @@ void maildirFolder::addMessage(utility::inputStream& is, const int size, utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - utility::file::path tmpDirPath = maildirUtils::getFolderFSPath - (store, m_path, maildirUtils::FOLDER_PATH_TMP); - utility::file::path curDirPath = maildirUtils::getFolderFSPath - (store, m_path, maildirUtils::FOLDER_PATH_CUR); + utility::file::path tmpDirPath = store->getFormat()-> + folderPathToFileSystemPath(m_path, maildirFormat::TMP_DIRECTORY); + utility::file::path curDirPath = store->getFormat()-> + folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); const utility::file::path::component filename = maildirUtils::buildFilename(maildirUtils::generateId(), @@ -1165,13 +1049,13 @@ void maildirFolder::copyMessagesImpl(const folder::path& dest, const std::vector utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - utility::file::path curDirPath = maildirUtils::getFolderFSPath - (store, m_path, maildirUtils::FOLDER_PATH_CUR); + utility::file::path curDirPath = store->getFormat()->folderPathToFileSystemPath + (m_path, maildirFormat::CUR_DIRECTORY); - utility::file::path destCurDirPath = maildirUtils::getFolderFSPath - (store, dest, maildirUtils::FOLDER_PATH_CUR); - utility::file::path destTmpDirPath = maildirUtils::getFolderFSPath - (store, dest, maildirUtils::FOLDER_PATH_TMP); + 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 @@ -1307,8 +1191,8 @@ void maildirFolder::expunge() utility::fileSystemFactory* fsf = platform::getHandler()->getFileSystemFactory(); - utility::file::path curDirPath = maildirUtils::getFolderFSPath - (store, m_path, maildirUtils::FOLDER_PATH_CUR); + utility::file::path curDirPath = store->getFormat()-> + folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); std::vector nums; int unreadCount = 0; @@ -1461,8 +1345,8 @@ const int maildirFolder::getFetchCapabilities() const const utility::file::path maildirFolder::getMessageFSPath(const int number) const { - utility::file::path curDirPath = maildirUtils::getFolderFSPath - (m_store.acquire(), m_path, maildirUtils::FOLDER_PATH_CUR); + utility::file::path curDirPath = m_store.acquire()->getFormat()-> + folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); return (curDirPath / m_messageInfos[number - 1].path); } diff --git a/src/net/maildir/maildirFormat.cpp b/src/net/maildir/maildirFormat.cpp new file mode 100644 index 00000000..6fdf185d --- /dev/null +++ b/src/net/maildir/maildirFormat.cpp @@ -0,0 +1,100 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// 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 2 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/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(ref store) + : m_store(store) +{ +} + + +ref maildirFormat::context::getStore() const +{ + return m_store; +} + + +// +// maildirFormat +// + +maildirFormat::maildirFormat(ref ctx) + : m_context(ctx) +{ +} + + +ref maildirFormat::getContext() +{ + return m_context; +} + + +ref maildirFormat::getContext() const +{ + return m_context; +} + + +// static +ref maildirFormat::detect(ref store) +{ + ref ctx = create (store); + + // Try Courier format + ref fmt = create (ctx); + + if (fmt->supports()) + return fmt; + + // Default is KMail format + return create (ctx); +} + + +} // maildir +} // net +} // vmime + diff --git a/src/net/maildir/maildirStore.cpp b/src/net/maildir/maildirStore.cpp index 74d0b595..566d9359 100644 --- a/src/net/maildir/maildirStore.cpp +++ b/src/net/maildir/maildirStore.cpp @@ -20,6 +20,7 @@ #include "vmime/net/maildir/maildirStore.hpp" #include "vmime/net/maildir/maildirFolder.hpp" +#include "vmime/net/maildir/maildirFormat.hpp" #include "vmime/utility/smartPtr.hpp" @@ -146,6 +147,8 @@ void maildirStore::connect() } } + m_format = maildirFormat::detect(thisRef().dynamicCast ()); + m_connected = true; } @@ -188,6 +191,18 @@ void maildirStore::noop() } +ref maildirStore::getFormat() +{ + return m_format; +} + + +ref maildirStore::getFormat() const +{ + return m_format; +} + + void maildirStore::registerFolder(maildirFolder* folder) { m_folders.push_back(folder); diff --git a/src/net/maildir/maildirUtils.cpp b/src/net/maildir/maildirUtils.cpp index f1f2300c..04d8f680 100644 --- a/src/net/maildir/maildirUtils.cpp +++ b/src/net/maildir/maildirUtils.cpp @@ -30,67 +30,6 @@ namespace net { namespace maildir { -const vmime::word maildirUtils::TMP_DIR("tmp", vmime::charset(vmime::charsets::US_ASCII)); // ensure reliable delivery (not to be listed) -const vmime::word maildirUtils::CUR_DIR("cur", vmime::charset(vmime::charsets::US_ASCII)); // no longer new messages -const vmime::word maildirUtils::NEW_DIR("new", vmime::charset(vmime::charsets::US_ASCII)); // unread messages - - -const utility::file::path maildirUtils::getFolderFSPath - (ref store, const utility::path& folderPath, - const FolderFSPathMode mode) -{ - // Root path - utility::file::path path(store->getFileSystemPath()); - - const int count = (mode == FOLDER_PATH_CONTAINER - ? folderPath.getSize() : folderPath.getSize() - 1); - - // Parent folders - for (int i = 0 ; i < count ; ++i) - { - utility::file::path::component comp(folderPath[i]); - - // TODO: may not work with all encodings... - comp.setBuffer("." + comp.getBuffer() + ".directory"); - - path /= comp; - } - - // Last component - if (folderPath.getSize() != 0 && - mode != FOLDER_PATH_CONTAINER) - { - path /= folderPath.getLastComponent(); - - switch (mode) - { - case FOLDER_PATH_ROOT: break; // Nothing to do - case FOLDER_PATH_NEW: path /= NEW_DIR; break; - case FOLDER_PATH_CUR: path /= CUR_DIR; break; - case FOLDER_PATH_TMP: path /= TMP_DIR; break; - case FOLDER_PATH_CONTAINER: break; // Can't happen... - } - } - - return (path); -} - - -const bool maildirUtils::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); -} - - const bool maildirUtils::isMessageFile(const utility::file& file) { // Ignore files which name begins with '.' diff --git a/src/utility/path.cpp b/src/utility/path.cpp index 21c02b7a..abbba853 100644 --- a/src/utility/path.cpp +++ b/src/utility/path.cpp @@ -149,6 +149,12 @@ const bool path::isEmpty() const } +const bool path::isRoot() const +{ + return (m_list.empty()); +} + + const path::component path::getLastComponent() const { return (m_list[m_list.size() - 1]); diff --git a/tests/net/maildir/maildirStoreTest.cpp b/tests/net/maildir/maildirStoreTest.cpp new file mode 100644 index 00000000..ad61c2f9 --- /dev/null +++ b/tests/net/maildir/maildirStoreTest.cpp @@ -0,0 +1,578 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// 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 2 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 "tests/testUtils.hpp" + +#include "vmime/platform.hpp" + +#include "vmime/net/maildir/maildirStore.hpp" +#include "vmime/net/maildir/maildirFormat.hpp" + + +#define VMIME_TEST_SUITE maildirStoreTest +#define VMIME_TEST_SUITE_MODULE "Net/Maildir" + + +// Shortcuts and helpers +typedef vmime::utility::file::path fspath; +typedef vmime::utility::file::path::component fspathc; + +typedef vmime::net::folder::path fpath; +typedef vmime::net::folder::path::component fpathc; + + +const fpath operator/(const fpath& path, const std::string& c) +{ + return path / fpathc(c); +} + + +/** Test messages */ +static const vmime::string TEST_MESSAGE_1 = + "From: \r\n" + "Subject: VMime Test\r\n" + "Date: Thu, 01 Mar 2007 09:49:35 +0100\r\n" + "\r\n" + "Hello, world!"; + + +/** Maildir trees used in tests. + * Structure: + * + * . + * |-- Folder + * | `-- SubFolder + * | |-- SubSubFolder1 + * | `-- SubSubFolder2 + * `-- Folder2 + * + */ + +// KMail format +static const vmime::string TEST_MAILDIR_KMAIL[] = // directories to create +{ + "/Folder", + "/Folder/new", + "/Folder/tmp", + "/Folder/cur", + "/.Folder.directory", + "/.Folder.directory/SubFolder", + "/.Folder.directory/SubFolder/new", + "/.Folder.directory/SubFolder/tmp", + "/.Folder.directory/SubFolder/cur", + "/.Folder.directory/.SubFolder.directory", + "/.Folder.directory/.SubFolder.directory/SubSubFolder1", + "/.Folder.directory/.SubFolder.directory/SubSubFolder1/new", + "/.Folder.directory/.SubFolder.directory/SubSubFolder1/tmp", + "/.Folder.directory/.SubFolder.directory/SubSubFolder1/cur", + "/.Folder.directory/.SubFolder.directory/SubSubFolder2", + "/.Folder.directory/.SubFolder.directory/SubSubFolder2/new", + "/.Folder.directory/.SubFolder.directory/SubSubFolder2/tmp", + "/.Folder.directory/.SubFolder.directory/SubSubFolder2/cur", + "/Folder2", + "/Folder2/new", + "/Folder2/tmp", + "/Folder2/cur", + "*" // end +}; + +static const vmime::string TEST_MAILDIRFILES_KMAIL[] = // files to create and their contents +{ + "/.Folder.directory/.SubFolder.directory/SubSubFolder2/cur/1043236113.351.EmqD:S", TEST_MESSAGE_1, + "*" // end +}; + +// Courier format +static const vmime::string TEST_MAILDIR_COURIER[] = // directories to create +{ + "/.Folder", + "/.Folder/new", + "/.Folder/tmp", + "/.Folder/cur", + "/.Folder.SubFolder", + "/.Folder.SubFolder", + "/.Folder.SubFolder/new", + "/.Folder.SubFolder/tmp", + "/.Folder.SubFolder/cur", + "/.Folder.SubFolder.SubSubFolder1", + "/.Folder.SubFolder.SubSubFolder1/new", + "/.Folder.SubFolder.SubSubFolder1/tmp", + "/.Folder.SubFolder.SubSubFolder1/cur", + "/.Folder.SubFolder.SubSubFolder2", + "/.Folder.SubFolder.SubSubFolder2/new", + "/.Folder.SubFolder.SubSubFolder2/tmp", + "/.Folder.SubFolder.SubSubFolder2/cur", + "/.Folder2", + "/.Folder2/new", + "/.Folder2/tmp", + "/.Folder2/cur", + "*" // end +}; + +static const vmime::string TEST_MAILDIRFILES_COURIER[] = // files to create and their contents +{ + "/.Folder/maildirfolder", "", + "/.Folder.SubFolder/maildirfolder", "", + "/.Folder.SubFolder.SubSubFolder1/maildirfolder", "", + "/.Folder.SubFolder.SubSubFolder2/maildirfolder", "", + "/.Folder.SubFolder.SubSubFolder2/cur/1043236113.351.EmqD:S", TEST_MESSAGE_1, + "/.Folder2/maildirfolder", "", + "*" // end +}; + + + +VMIME_TEST_SUITE_BEGIN + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testDetectFormat_KMail) + VMIME_TEST(testDetectFormat_Courier) + + VMIME_TEST(testListRootFolders_KMail) + VMIME_TEST(testListAllFolders_KMail) + + VMIME_TEST(testListRootFolders_Courier) + VMIME_TEST(testListAllFolders_Courier) + + VMIME_TEST(testListMessages_KMail) + VMIME_TEST(testListMessages_Courier) + + VMIME_TEST(testRenameFolder_KMail) + VMIME_TEST(testRenameFolder_Courier) + + VMIME_TEST(testDestroyFolder_KMail) + VMIME_TEST(testDestroyFolder_Courier) + + VMIME_TEST(testFolderExists_KMail) + VMIME_TEST(testFolderExists_Courier) + + VMIME_TEST(testCreateFolder_KMail) + VMIME_TEST(testCreateFolder_Courier) + VMIME_TEST_LIST_END + + +public: + + maildirStoreTest() + { + // Temporary directory + m_tempPath = fspath() / fspathc("tmp") // Use /tmp + / fspathc("vmime" + vmime::utility::stringUtils::toString(std::time(NULL)) + + vmime::utility::stringUtils::toString(std::rand())); + } + + void tearDown() + { + // In case of an uncaught exception + destroyMaildir(); + } + + void testDetectFormat_KMail() + { + createMaildir(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + + vmime::ref store = + vmime::dynamicCast (createAndConnectStore()); + + VASSERT_EQ("*", "kmail", store->getFormat()->getName()); + + destroyMaildir(); + } + + void testDetectFormat_Courier() + { + createMaildir(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + + vmime::ref store = + vmime::dynamicCast (createAndConnectStore()); + + VASSERT_EQ("*", "courier", store->getFormat()->getName()); + + destroyMaildir(); + } + + + void testListRootFolders_KMail() + { + testListRootFoldersImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testListRootFolders_Courier() + { + testListRootFoldersImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testListRootFoldersImpl(const vmime::string* const dirs, const vmime::string* const files) + { + createMaildir(dirs, files); + + // Connect to store + vmime::ref store = createAndConnectStore(); + vmime::ref rootFolder = store->getRootFolder(); + + // Get root folders, not recursive + const std::vector > + rootFolders = rootFolder->getFolders(false); + + VASSERT_EQ("1", 2, rootFolders.size()); + VASSERT("2", findFolder(rootFolders, fpath() / "Folder") != NULL); + VASSERT("3", findFolder(rootFolders, fpath() / "Folder2") != NULL); + + destroyMaildir(); + } + + + void testListAllFolders_KMail() + { + testListAllFoldersImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testListAllFolders_Courier() + { + testListAllFoldersImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testListAllFoldersImpl(const vmime::string* const dirs, const vmime::string* const files) + { + createMaildir(dirs, files); + + // Connect to store + vmime::ref store = createAndConnectStore(); + vmime::ref rootFolder = store->getRootFolder(); + + // Get all folders, recursive + const std::vector > + allFolders = rootFolder->getFolders(true); + + VASSERT_EQ("1", 5, allFolders.size()); + VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL); + VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") != NULL); + VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") != NULL); + VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") != NULL); + VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL); + + destroyMaildir(); + } + + + void testListMessages_KMail() + { + testListMessagesImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testListMessages_Courier() + { + testListMessagesImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testListMessagesImpl(const vmime::string* const dirs, const vmime::string* const files) + { + createMaildir(dirs, files); + + vmime::ref store = createAndConnectStore(); + vmime::ref rootFolder = store->getRootFolder(); + + vmime::ref folder = store->getFolder + (fpath() / "Folder" / "SubFolder" / "SubSubFolder2"); + + int count, unseen; + folder->status(count, unseen); + + VASSERT_EQ("Message count", 1, count); + + folder->open(vmime::net::folder::MODE_READ_ONLY); + + vmime::ref msg = folder->getMessage(1); + + folder->fetchMessage(msg, vmime::net::folder::FETCH_SIZE); + + VASSERT_EQ("Message size", TEST_MESSAGE_1.length(), msg->getSize()); + + std::ostringstream oss; + vmime::utility::outputStreamAdapter os(oss); + msg->extract(os); + + VASSERT_EQ("Message contents", TEST_MESSAGE_1, oss.str()); + + folder->close(false); + + destroyMaildir(); + } + + + void testRenameFolder_KMail() + { + testRenameFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testRenameFolder_Courier() + { + testRenameFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testRenameFolderImpl(const vmime::string* const dirs, const vmime::string* const files) + { + createMaildir(dirs, files); + + vmime::ref store = createAndConnectStore(); + vmime::ref rootFolder = store->getRootFolder(); + + // Rename "Folder/SubFolder" to "Folder/foo" + vmime::ref folder = store->getFolder + (fpath() / "Folder" / "SubFolder"); + + folder->rename(fpath() / "Folder" / "foo"); + + // Ensure folder and its subfolders have been renamed + const std::vector > + allFolders = rootFolder->getFolders(true); + + VASSERT_EQ("1", 5, allFolders.size()); + VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL); + VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") == NULL); + VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") == NULL); + VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") == NULL); + VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL); + VASSERT("7", findFolder(allFolders, fpath() / "Folder" / "foo") != NULL); + VASSERT("8", findFolder(allFolders, fpath() / "Folder" / "foo" / "SubSubFolder1") != NULL); + VASSERT("9", findFolder(allFolders, fpath() / "Folder" / "foo" / "SubSubFolder2") != NULL); + + destroyMaildir(); + } + + + void testDestroyFolder_KMail() + { + testDestroyFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testDestroyFolder_Courier() + { + testDestroyFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testDestroyFolderImpl(const vmime::string* const dirs, const vmime::string* const files) + { + createMaildir(dirs, files); + + vmime::ref store = createAndConnectStore(); + vmime::ref rootFolder = store->getRootFolder(); + + // Destroy "Folder/SubFolder" (total: 3 folders) + vmime::ref folder = store->getFolder + (fpath() / "Folder" / "SubFolder"); + + folder->destroy(); + + // Ensure folder and its subfolders have been deleted and other folders still exist + const std::vector > + allFolders = rootFolder->getFolders(true); + + VASSERT_EQ("1", 2, allFolders.size()); + VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL); + VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") == NULL); + VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") == NULL); + VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") == NULL); + VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL); + + destroyMaildir(); + } + + + void testFolderExists_KMail() + { + testFolderExistsImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testFolderExists_Courier() + { + testFolderExistsImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testFolderExistsImpl(const vmime::string* const dirs, const vmime::string* const files) + { + createMaildir(dirs, files); + + vmime::ref store = createAndConnectStore(); + vmime::ref rootFolder = store->getRootFolder(); + + VASSERT("1", store->getFolder(fpath() / "Folder" / "SubFolder")->exists()); + VASSERT("2", !store->getFolder(fpath() / "Folder" / "SubSubFolder1")->exists()); + VASSERT("3", store->getFolder(fpath() / "Folder2")->exists()); + VASSERT("4", store->getFolder(fpath() / "Folder" / "SubFolder" / "SubSubFolder2")->exists()); + + destroyMaildir(); + } + + + void testCreateFolder_KMail() + { + testCreateFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL); + } + + void testCreateFolder_Courier() + { + testCreateFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + } + + void testCreateFolderImpl(const vmime::string* const dirs, const vmime::string* const files) + { + createMaildir(dirs, files); + + vmime::ref store = createAndConnectStore(); + vmime::ref rootFolder = store->getRootFolder(); + + VASSERT("Before", !store->getFolder(fpath() / "Folder" / "NewFolder")->exists()); + + VASSERT_NO_THROW("Creation", store->getFolder(fpath() / "Folder" / "NewFolder")-> + create(vmime::net::folder::TYPE_CONTAINS_MESSAGES)); + + VASSERT("After", store->getFolder(fpath() / "Folder" / "NewFolder")->exists()); + + destroyMaildir(); + } + +private: + + vmime::utility::file::path m_tempPath; + + + vmime::ref createAndConnectStore() + { + vmime::ref session = + vmime::create (); + + vmime::ref store = + session->getStore(getStoreURL()); + + store->connect(); + + return store; + } + + const vmime::ref findFolder + (const std::vector >& folders, + const vmime::net::folder::path& path) + { + for (unsigned int i = 0, n = folders.size() ; i < n ; ++i) + { + if (folders[i]->getFullPath() == path) + return folders[i]; + } + + return NULL; + } + + const vmime::utility::url getStoreURL() + { + vmime::utility::fileSystemFactory* fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + vmime::utility::url url(std::string("maildir://localhost") + + fsf->pathToString(m_tempPath)); + + return url; + } + + void createMaildir(const vmime::string* const dirs, const vmime::string* const files) + { + vmime::utility::fileSystemFactory* fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + vmime::ref rootDir = fsf->create(m_tempPath); + rootDir->createDirectory(false); + + for (vmime::string const* dir = dirs ; *dir != "*" ; ++dir) + { + vmime::ref fdir = fsf->create(m_tempPath / fsf->stringToPath(*dir)); + fdir->createDirectory(false); + } + + for (vmime::string const* file = files ; *file != "*" ; file += 2) + { + const vmime::string& contents = *(file + 1); + + vmime::ref ffile = fsf->create(m_tempPath / fsf->stringToPath(*file)); + ffile->createFile(); + + vmime::ref fileWriter = ffile->getFileWriter(); + vmime::ref os = fileWriter->getOutputStream(); + + os->write(contents.data(), contents.length()); + os->flush(); + + fileWriter = NULL; + } + + } + + void destroyMaildir() + { + vmime::utility::fileSystemFactory* fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + recursiveDelete(fsf->create(m_tempPath)); + } + + void recursiveDelete(vmime::ref dir) + { + if (!dir->exists() || !dir->isDirectory()) + return; + + vmime::ref files = dir->getFiles(); + + // First, delete files and subdirectories in this directory + while (files->hasMoreElements()) + { + vmime::ref file = files->nextElement(); + + if (file->isDirectory()) + { + recursiveDelete(file); + } + else + { + try + { + file->remove(); + } + catch (vmime::exceptions::filesystem_exception&) + { + // Ignore + } + } + } + + // Then, delete this (empty) directory + try + { + dir->remove(); + } + catch (vmime::exceptions::filesystem_exception&) + { + // Ignore + } + } + +VMIME_TEST_SUITE_END + diff --git a/vmime/base.hpp b/vmime/base.hpp index 0d824a95..8e8c7ec2 100644 --- a/vmime/base.hpp +++ b/vmime/base.hpp @@ -246,6 +246,17 @@ namespace vmime return x.clone().template dynamicCast (); } + + /** Downcast helper. + * Usage: vmime::dynamicCast (obj), where 'obj' is of + * type Type, and DerivedType is derived from Type. + */ + template + ref dynamicCast(ref y) + { + return y.dynamicCast (); + } + } // vmime diff --git a/vmime/net/maildir/format/courierMaildirFormat.hpp b/vmime/net/maildir/format/courierMaildirFormat.hpp new file mode 100644 index 00000000..1dee2dfd --- /dev/null +++ b/vmime/net/maildir/format/courierMaildirFormat.hpp @@ -0,0 +1,113 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// 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 2 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/net/maildir/maildirFormat.hpp" + + +namespace vmime { +namespace net { +namespace maildir { +namespace format { + + +/** Reads Courier/QMail Maildir format. + */ + +class courierMaildirFormat : public maildirFormat +{ +public: + + courierMaildirFormat(ref 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); + + const bool folderExists(const folder::path& path) const; + const bool folderHasSubfolders(const folder::path& path) const; + + const utility::file::path folderPathToFileSystemPath + (const folder::path& path, const DirectoryType type) const; + + const std::vector listFolders + (const folder::path& root, const bool recursive) const; + +protected: + + const 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 const 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 + */ + const bool listDirectories(const folder::path& root, + std::vector & dirs, const bool onlyTestForExistence) const; +}; + + +} // format +} // maildir +} // net +} // vmime + + +#endif // VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED + diff --git a/vmime/net/maildir/format/kmailMaildirFormat.hpp b/vmime/net/maildir/format/kmailMaildirFormat.hpp new file mode 100644 index 00000000..8f6f8b32 --- /dev/null +++ b/vmime/net/maildir/format/kmailMaildirFormat.hpp @@ -0,0 +1,100 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// 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 2 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/net/maildir/maildirFormat.hpp" + + +namespace vmime { +namespace net { +namespace maildir { +namespace format { + + +/** Reads KMail Maildir format. + */ + +class kmailMaildirFormat : public maildirFormat +{ +public: + + kmailMaildirFormat(ref 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); + + const bool folderExists(const folder::path& path) const; + const bool folderHasSubfolders(const folder::path& path) const; + + const utility::file::path folderPathToFileSystemPath + (const folder::path& path, const DirectoryType type) const; + + const std::vector listFolders + (const folder::path& root, const bool recursive) const; + +protected: + + const bool supports() const; + + + /** Recursive implementation of listFolders(). + */ + void listFoldersImpl(std::vector & 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 const bool isSubfolderDirectory(const utility::file& file); +}; + + +} // format +} // maildir +} // net +} // vmime + + +#endif // VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED + diff --git a/vmime/net/maildir/maildirFormat.hpp b/vmime/net/maildir/maildirFormat.hpp new file mode 100644 index 00000000..fbefa504 --- /dev/null +++ b/vmime/net/maildir/maildirFormat.hpp @@ -0,0 +1,187 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2007 Vincent Richard +// +// 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 2 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/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 maildirFormat : public object +{ +public: + + class context : public object + { + public: + + context(ref store); + + ref getStore() const; + + private: + + ref 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 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 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 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 const 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 const 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 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 ref detect(ref 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(ref ctx); + + + /** Returns the current context. + * + * @return current context + */ + ref getContext(); + + /** Returns the current context (const version). + * + * @return current context + */ + ref 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 const bool supports() const = 0; + +private: + + ref m_context; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED + diff --git a/vmime/net/maildir/maildirStore.hpp b/vmime/net/maildir/maildirStore.hpp index 340ff679..3496a171 100644 --- a/vmime/net/maildir/maildirStore.hpp +++ b/vmime/net/maildir/maildirStore.hpp @@ -44,6 +44,7 @@ namespace maildir { class maildirFolder; +class maildirFormat; /** maildir store service. @@ -82,6 +83,9 @@ public: const bool isSecuredConnection() const; ref getConnectionInfos() const; + ref getFormat(); + ref getFormat() const; + private: void registerFolder(maildirFolder* folder); @@ -90,6 +94,8 @@ private: std::list m_folders; + ref m_format; + bool m_connected; utility::path m_fsPath; diff --git a/vmime/net/maildir/maildirUtils.hpp b/vmime/net/maildir/maildirUtils.hpp index 0cd035b4..de1524cf 100644 --- a/vmime/net/maildir/maildirUtils.hpp +++ b/vmime/net/maildir/maildirUtils.hpp @@ -60,36 +60,6 @@ public: const utility::file::path::component m_comp; }; - /** Mode for return value of getFolderFSPath(). */ - enum FolderFSPathMode - { - FOLDER_PATH_ROOT, /**< Root folder. Eg: ~/Mail/MyFolder */ - FOLDER_PATH_NEW, /**< Folder containing unread messages. Eg: ~/Mail/MyFolder/new */ - FOLDER_PATH_CUR, /**< Folder containing messages that have been seen. Eg: ~/Mail/MyFolder/cur */ - FOLDER_PATH_TMP, /**< Temporary folder used for reliable delivery. Eg: ~/Mail/MyFolder/tmp */ - FOLDER_PATH_CONTAINER /**< Container for sub-folders. Eg: ~/Mail/.MyFolder.directory */ - }; - - /** Return the path on the filesystem for the folder in specified store. - * - * @param store parent store - * @param folderPath path of the folder - * @param mode type of path to return (see FolderFSPathMode) - * @return filesystem path for the specified folder - */ - static const utility::file::path getFolderFSPath(ref store, - const utility::path& folderPath, const FolderFSPathMode mode); - - /** Test whether the specified file-system directory corresponds to - * a maildir sub-folder. The name of the directory should not start - * with '.' to be listed as a sub-folder. - * - * @param file reference to a file-system directory - * @return true if the specified directory is a maildir sub-folder, - * false otherwise - */ - static const bool isSubfolderDirectory(const utility::file& file); - /** Test whether the specified file-system object is a message. * * @param file reference to a file-system object @@ -153,12 +123,6 @@ public: * @param dir directory to delete */ static void recursiveFSDelete(ref dir); - -private: - - static const vmime::word TMP_DIR; - static const vmime::word CUR_DIR; - static const vmime::word NEW_DIR; }; diff --git a/vmime/utility/path.hpp b/vmime/utility/path.hpp index 857d9d13..e74d8d03 100644 --- a/vmime/utility/path.hpp +++ b/vmime/utility/path.hpp @@ -95,6 +95,12 @@ public: */ const bool isEmpty() const; + /** Test whether this path is the root (alias for isEmpty()). + * + * @return true if the path is the root + */ + const bool isRoot() const; + /** Return the last component of this path (const version). * * @return last component