diff --git a/src/vmime/net/folder.cpp b/src/vmime/net/folder.cpp index 1d6f3140..78ed5131 100644 --- a/src/vmime/net/folder.cpp +++ b/src/vmime/net/folder.cpp @@ -36,6 +36,18 @@ namespace vmime { namespace net { +int folder::getType() +{ + return getAttributes().getType(); +} + + +int folder::getFlags() +{ + return getAttributes().getFlags(); +} + + void folder::addMessageChangedListener(events::messageChangedListener* l) { m_messageChangedListeners.push_back(l); diff --git a/src/vmime/net/folder.hpp b/src/vmime/net/folder.hpp index 2db89f4b..da39f555 100644 --- a/src/vmime/net/folder.hpp +++ b/src/vmime/net/folder.hpp @@ -42,6 +42,7 @@ #include "vmime/net/events.hpp" #include "vmime/net/folderStatus.hpp" #include "vmime/net/fetchAttributes.hpp" +#include "vmime/net/folderAttributes.hpp" #include "vmime/utility/path.hpp" #include "vmime/utility/stream.hpp" @@ -91,33 +92,28 @@ public: MODE_READ_WRITE /**< Full access mode (read and write). */ }; - /** Folder types. - */ - enum Types - { - TYPE_CONTAINS_FOLDERS = (1 << 0), /**< Folder can contain folders. */ - TYPE_CONTAINS_MESSAGES = (1 << 1) /**< Folder can contain messages. */ - }; - - /** Folder flags. - */ - enum Flags - { - FLAG_HAS_CHILDREN = (1 << 0), /**< Folder contains subfolders. */ - FLAG_NO_OPEN = (1 << 1) /**< Folder cannot be open. */ - }; /** Return the type of this folder. * - * @return folder type (see folder::Types) + * \deprecated Use the getAttributes().getType() method instead + * + * @return folder type (see folderAttributes::Types enum) */ - virtual int getType() = 0; + int getType(); /** Return the flags of this folder. * - * @return folder flags (see folder::Flags) + * \deprecated Use the getAttributes().getFlags() method instead + * + * @return folder flags (see folderAttributes::Flags enum) */ - virtual int getFlags() = 0; + int getFlags(); + + /** Return the attributes of the folder. + * + * @return folder attributes (see folder::Flags) + */ + virtual const folderAttributes getAttributes() = 0; /** Return the mode in which the folder has been open. * @@ -159,10 +155,10 @@ public: /** Create this folder. * - * @param type folder type (see folder::Types) + * @param attribs attributes of the new folder * @throw exceptions::net_exception if an error occurs */ - virtual void create(const int type) = 0; + virtual void create(const folderAttributes& attribs) = 0; /** Test whether this folder exists. * diff --git a/src/vmime/net/folderAttributes.cpp b/src/vmime/net/folderAttributes.cpp new file mode 100644 index 00000000..027efddf --- /dev/null +++ b/src/vmime/net/folderAttributes.cpp @@ -0,0 +1,121 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2014 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 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 + + +#include "vmime/net/folderAttributes.hpp" + +#include + + +namespace vmime { +namespace net { + + +folderAttributes::folderAttributes() + : m_type(TYPE_CONTAINS_FOLDERS | TYPE_CONTAINS_MESSAGES), + m_flags(0), + m_specialUse(SPECIALUSE_NONE) +{ +} + + +folderAttributes::folderAttributes(const folderAttributes& attribs) + : m_type(attribs.m_type), + m_flags(attribs.m_flags), + m_userFlags(attribs.m_userFlags), + m_specialUse(attribs.m_specialUse) +{ +} + + +int folderAttributes::getType() const +{ + return m_type; +} + + +void folderAttributes::setType(const int type) +{ + m_type = type; +} + + +int folderAttributes::getSpecialUse() const +{ + return m_specialUse; +} + + +void folderAttributes::setSpecialUse(const int use) +{ + m_specialUse = use; +} + + +int folderAttributes::getFlags() const +{ + return m_flags; +} + + +void folderAttributes::setFlags(const int flags) +{ + m_flags = flags; +} + + +bool folderAttributes::hasFlag(const int flag) +{ + return (m_flags & flag) != 0; +} + + +const std::vector folderAttributes::getUserFlags() const +{ + return m_userFlags; +} + + +void folderAttributes::setUserFlags(const std::vector & flags) +{ + m_userFlags = flags; +} + + +bool folderAttributes::hasUserFlag(const string& flag) +{ + return std::find(m_userFlags.begin(), m_userFlags.end(), flag) != m_userFlags.end(); +} + + +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES + diff --git a/src/vmime/net/folderAttributes.hpp b/src/vmime/net/folderAttributes.hpp new file mode 100644 index 00000000..d6c51926 --- /dev/null +++ b/src/vmime/net/folderAttributes.hpp @@ -0,0 +1,179 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2014 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 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_FOLDERATTRIBUTES_HPP_INCLUDED +#define VMIME_NET_FOLDERATTRIBUTES_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES + + +#include + +#include "vmime/types.hpp" + + +namespace vmime { +namespace net { + + +/** Holds a set of attributes for a folder. + */ +class VMIME_EXPORT folderAttributes : public object +{ +public: + + /** Folder types. + */ + enum Types + { + TYPE_CONTAINS_FOLDERS = (1 << 0), /**< Folder can contain folders. */ + TYPE_CONTAINS_MESSAGES = (1 << 1) /**< Folder can contain messages. */ + }; + + /** Folder flags. + */ + enum Flags + { + FLAG_HAS_CHILDREN = (1 << 0), /**< Folder contains subfolders. */ + FLAG_NO_OPEN = (1 << 1) /**< Folder cannot be open. */ + }; + + /** Folder special uses. + * Not all protocols support this. At the current time, only IMAP supports this, + * if the server has the SPECIAL-USE capability. + */ + enum SpecialUses + { + SPECIALUSE_NONE, /**< User folder, no special use (or unknown). */ + SPECIALUSE_ALL, /**< Virtual folder containing all messages. */ + SPECIALUSE_ARCHIVE, /**< Folder is used to archives messages (server-dependent). */ + SPECIALUSE_DRAFTS, /**< Folder is used to hold draft messages - typically, messages + that are being composed but have not yet been sent. */ + SPECIALUSE_FLAGGED, /**< Virtual folder containing all messages which are marked + in some way as "important" or "flagged". */ + SPECIALUSE_JUNK, /**< Folder is used to hold junk mail. */ + SPECIALUSE_SENT, /**< Folder is is used to hold copies of messages that have + been sent. */ + SPECIALUSE_TRASH, /**< Folder is used to hold messages that have been deleted or + marked for deletion (may be a virtual folder). */ + SPECIALUSE_IMPORTANT /**< Folder contains messages that are likely important to the + user. */ + }; + + + /** Construct a new folderAttributes object with the default set of attributes. + */ + folderAttributes(); + + /** Construct a new folderAttributes object by copying an existing object. + * + * @param attribs object to copy + */ + folderAttributes(const folderAttributes& attribs); + + /** Return the type of the folder. + * + * @return combination of one ore more folder types (see folderAttributes::Types enum) + */ + int getType() const; + + /** Set the type of the folder. + * + * @param type combination of one ore more folder types (see folderAttributes::Types enum) + */ + void setType(const int type); + + /** Return the special use of the folder. + * Not all protocols support this. At the current time, only IMAP supports this, + * if the server has the SPECIAL-USE capability. + * + * @return a value which indicates a special use (see folderAttributes::SpecialUses enum) + */ + int getSpecialUse() const; + + /** Set the special use of the folder. + * Not all protocols support this. At the current time, only IMAP supports this, + * if the server has the SPECIAL-USE capability. + * + * @param use a value which indicates a special use (see folderAttributes::SpecialUses enum) + */ + void setSpecialUse(const int use); + + /** Return the standard (non-user) flags of the folder. + * + * @return combination of one ore more folder flags (see folderAttributes::Flags enum) + */ + int getFlags() const; + + /** Set the standard (non-user) flags of the folder. + * + * @param type combination of one ore more folder flags (see folderAttributes::Flags enum) + */ + void setFlags(const int flags); + + /** Return whether the specified folder flag(s) is/are set. + * + * @param flag combination of one ore more folder flags (see folderAttributes::Flags enum) + * @return true if the specified flags are all set, or false otherwise + */ + bool hasFlag(const int flag); + + /** Set the user-defined flags of the folder. + * + * @return a list of user-defined flags + */ + const std::vector getUserFlags() const; + + /** Set the user-defined flags of the folder. + * + * @param flags a list of user-defined flags + */ + void setUserFlags(const std::vector & flags); + + /** Return whether the specified user-defined flag is set. + * + * @return true if the specified flag is set, or false otherwise + */ + bool hasUserFlag(const string& flag); + +private: + + int m_type; + int m_flags; + std::vector m_userFlags; + int m_specialUse; +}; + + +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES + + +#endif // VMIME_NET_FOLDERATTRIBUTES_HPP_INCLUDED diff --git a/src/vmime/net/imap/IMAPFolder.cpp b/src/vmime/net/imap/IMAPFolder.cpp index 97a4c2e2..343ec35e 100644 --- a/src/vmime/net/imap/IMAPFolder.cpp +++ b/src/vmime/net/imap/IMAPFolder.cpp @@ -51,10 +51,10 @@ namespace net { namespace imap { -IMAPFolder::IMAPFolder(const folder::path& path, shared_ptr store, const int type, const int flags) +IMAPFolder::IMAPFolder(const folder::path& path, shared_ptr store, shared_ptr attribs) : m_store(store), m_connection(store->connection()), m_path(path), m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()), m_mode(-1), - m_open(false), m_type(type), m_flags(flags) + m_open(false), m_attribs(attribs) { store->registerFolder(this); @@ -90,7 +90,7 @@ int IMAPFolder::getMode() const } -int IMAPFolder::getType() +const folderAttributes IMAPFolder::getAttributes() { if (!isOpen()) throw exceptions::illegal_state("Folder not open"); @@ -98,34 +98,18 @@ int IMAPFolder::getType() // Root folder if (m_path.isEmpty()) { - return (TYPE_CONTAINS_FOLDERS); + folderAttributes attribs; + attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS); + attribs.setFlags(folderAttributes::FLAG_HAS_CHILDREN | folderAttributes::FLAG_NO_OPEN); + + return attribs; } else { - if (m_type == TYPE_UNDEFINED) + if (!m_attribs) testExistAndGetType(); - return (m_type); - } -} - - -int IMAPFolder::getFlags() -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - // Root folder - if (m_path.isEmpty()) - { - return (FLAG_HAS_CHILDREN | FLAG_NO_OPEN); - } - else - { - if (m_flags == FLAG_UNDEFINED) - testExistAndGetType(); - - return (m_flags); + return *m_attribs; } } @@ -245,11 +229,11 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable) case IMAPParser::mailbox_data::FLAGS: { - m_type = IMAPUtils::folderTypeFromFlags - (responseData->mailbox_data()->mailbox_flag_list()); + if (!m_attribs) + m_attribs = make_shared (); - m_flags = IMAPUtils::folderFlagsFromFlags - (connection, responseData->mailbox_data()->mailbox_flag_list()); + IMAPUtils::mailboxFlagsToFolderAttributes + (connection, responseData->mailbox_data()->mailbox_flag_list(), *m_attribs); break; } @@ -338,7 +322,7 @@ void IMAPFolder::onClose() } -void IMAPFolder::create(const int type) +void IMAPFolder::create(const folderAttributes& attribs) { shared_ptr store = m_store.lock(); @@ -361,12 +345,36 @@ void IMAPFolder::create(const int type) string mailbox = IMAPUtils::pathToString (m_connection->hierarchySeparator(), getFullPath()); - if (type & TYPE_CONTAINS_FOLDERS) + if (attribs.getType() & folderAttributes::TYPE_CONTAINS_FOLDERS) mailbox += m_connection->hierarchySeparator(); std::ostringstream oss; oss << "CREATE " << IMAPUtils::quoteString(mailbox); + if (attribs.getSpecialUse() != folderAttributes::SPECIALUSE_NONE) + { + if (!m_connection->hasCapability("CREATE-SPECIAL-USE")) + throw exceptions::operation_not_supported(); + + // C: t2 CREATE MySpecial (USE (\Drafts \Sent)) + oss << "(USE ("; + + switch (attribs.getSpecialUse()) + { + case folderAttributes::SPECIALUSE_NONE: // should not happen + case folderAttributes::SPECIALUSE_ALL: oss << "\\All"; break; + case folderAttributes::SPECIALUSE_ARCHIVE: oss << "\\Archive"; break; + case folderAttributes::SPECIALUSE_DRAFTS: oss << "\\Drafts"; break; + case folderAttributes::SPECIALUSE_FLAGGED: oss << "\\Flagged"; break; + case folderAttributes::SPECIALUSE_JUNK: oss << "\\Junk"; break; + case folderAttributes::SPECIALUSE_SENT: oss << "\\Sent"; break; + case folderAttributes::SPECIALUSE_TRASH: oss << "\\Trash"; break; + case folderAttributes::SPECIALUSE_IMPORTANT: oss << "\\Important"; break; + } + + oss << "))"; + } + m_connection->send(true, oss.str(), true); @@ -434,14 +442,12 @@ bool IMAPFolder::exists() if (!isOpen() && !store) throw exceptions::illegal_state("Store disconnected"); - return (testExistAndGetType() != TYPE_UNDEFINED); + return testExistAndGetType() != -1; } int IMAPFolder::testExistAndGetType() { - m_type = TYPE_UNDEFINED; - // To test whether a folder exists, we simple list it using // the "LIST" command, and there should be one unique mailbox // with this name... @@ -482,6 +488,9 @@ int IMAPFolder::testExistAndGetType() const std::vector & respDataList = resp->continue_req_or_response_data(); + folderAttributes attribs; + attribs.setType(-1); + for (std::vector ::const_iterator it = respDataList.begin() ; it != respDataList.end() ; ++it) { @@ -498,15 +507,14 @@ int IMAPFolder::testExistAndGetType() if (mailboxData != NULL && mailboxData->type() == IMAPParser::mailbox_data::LIST) { // Get the folder type/flags at the same time - m_type = IMAPUtils::folderTypeFromFlags - (mailboxData->mailbox_list()->mailbox_flag_list()); - - m_flags = IMAPUtils::folderFlagsFromFlags - (m_connection, mailboxData->mailbox_list()->mailbox_flag_list()); + IMAPUtils::mailboxFlagsToFolderAttributes + (m_connection, mailboxData->mailbox_list()->mailbox_flag_list(), attribs); } } - return (m_type); + m_attribs = make_shared (attribs); + + return m_attribs->getType(); } @@ -656,7 +664,7 @@ shared_ptr IMAPFolder::getFolder(const folder::path::component& name) if (!store) throw exceptions::illegal_state("Store disconnected"); - return make_shared (m_path / name, store); + return make_shared (m_path / name, store, shared_ptr ()); } @@ -740,9 +748,11 @@ std::vector > IMAPFolder::getFolders(const bool recursive) const class IMAPParser::mailbox_flag_list* mailbox_flag_list = mailboxData->mailbox_list()->mailbox_flag_list(); - v.push_back(make_shared (path, store, - IMAPUtils::folderTypeFromFlags(mailbox_flag_list), - IMAPUtils::folderFlagsFromFlags(m_connection, mailbox_flag_list))); + shared_ptr attribs = make_shared (); + IMAPUtils::mailboxFlagsToFolderAttributes + (m_connection, mailbox_flag_list, *attribs); + + v.push_back(make_shared (path, store, attribs)); } } @@ -867,7 +877,7 @@ shared_ptr IMAPFolder::getParent() if (m_path.isEmpty()) return null; else - return make_shared (m_path.getParent(), m_store.lock()); + return make_shared (m_path.getParent(), m_store.lock(), shared_ptr ()); } @@ -1453,6 +1463,16 @@ void IMAPFolder::processStatusUpdate(const IMAPParser::response* resp) else if ((*it)->response_data() && (*it)->response_data()->mailbox_data()) { m_status->updateFromResponse((*it)->response_data()->mailbox_data()); + + // Update folder attributes, if available + if ((*it)->response_data()->mailbox_data()->type() == IMAPParser::mailbox_data::LIST) + { + folderAttributes attribs; + IMAPUtils::mailboxFlagsToFolderAttributes + (m_connection, (*it)->response_data()->mailbox_data()->mailbox_list()->mailbox_flag_list(), attribs); + + m_attribs = make_shared (attribs); + } } else if ((*it)->response_data() && (*it)->response_data()->message_data()) { diff --git a/src/vmime/net/imap/IMAPFolder.hpp b/src/vmime/net/imap/IMAPFolder.hpp index 8d6f6278..96560f38 100644 --- a/src/vmime/net/imap/IMAPFolder.hpp +++ b/src/vmime/net/imap/IMAPFolder.hpp @@ -66,22 +66,20 @@ private: public: - IMAPFolder(const folder::path& path, shared_ptr store, const int type = TYPE_UNDEFINED, const int flags = FLAG_UNDEFINED); + IMAPFolder(const folder::path& path, shared_ptr store, shared_ptr attribs); ~IMAPFolder(); int getMode() const; - int getType(); - - int getFlags(); + 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 int type); + void create(const folderAttributes& attribs); bool exists(); @@ -195,8 +193,7 @@ private: int m_mode; bool m_open; - int m_type; - int m_flags; + shared_ptr m_attribs; shared_ptr m_status; diff --git a/src/vmime/net/imap/IMAPParser.hpp b/src/vmime/net/imap/IMAPParser.hpp index 53e9a3c0..533f78fb 100644 --- a/src/vmime/net/imap/IMAPParser.hpp +++ b/src/vmime/net/imap/IMAPParser.hpp @@ -1803,23 +1803,92 @@ public: const string name = utility::stringUtils::toLower(at->value()); delete (at); - if (name == "marked") - m_type = MARKED; - else if (name == "noinferiors") - m_type = NOINFERIORS; - else if (name == "noselect") - m_type = NOSELECT; - else if (name == "unmarked") - m_type = UNMARKED; - else if (name == "haschildren") - m_type = HASCHILDREN; - else if (name == "hasnochildren") - m_type = HASNOCHILDREN; - else + m_type = UNKNOWN; // default + + switch (name[0]) { - m_type = UNKNOWN; - m_name = "\\" + name; + case 'a': + + if (name == "all") + m_type = SPECIALUSE_ALL; + else if (name == "archive") + m_type = SPECIALUSE_ARCHIVE; + + break; + + case 'd': + + if (name == "drafts") + m_type = SPECIALUSE_DRAFTS; + + break; + + case 'f': + + if (name == "flagged") + m_type = SPECIALUSE_FLAGGED; + + break; + + case 'h': + + if (name == "haschildren") + m_type = HASCHILDREN; + else if (name == "hasnochildren") + m_type = HASNOCHILDREN; + + break; + + case 'i': + + if (name == "important") + m_type = SPECIALUSE_IMPORTANT; + + break; + + case 'j': + + if (name == "junk") + m_type = SPECIALUSE_JUNK; + + break; + + case 'm': + + if (name == "marked") + m_type = MARKED; + + case 'n': + + if (name == "noinferiors") + m_type = NOINFERIORS; + else if (name == "noselect") + m_type = NOSELECT; + + case 's': + + if (name == "sent") + m_type = SPECIALUSE_SENT; + + break; + + case 't': + + if (name == "trash") + m_type = SPECIALUSE_TRASH; + + break; + + case 'u': + + if (name == "unmarked") + m_type = UNMARKED; + + break; } + + if (m_type == UNKNOWN) + m_name = "\\" + name; } else { @@ -1841,6 +1910,16 @@ public: HASCHILDREN, HASNOCHILDREN, + // RFC-6154 - Special-Use Mailboxes + SPECIALUSE_ALL, + SPECIALUSE_ARCHIVE, + SPECIALUSE_DRAFTS, + SPECIALUSE_FLAGGED, + SPECIALUSE_JUNK, + SPECIALUSE_SENT, + SPECIALUSE_TRASH, + SPECIALUSE_IMPORTANT, // draft + // Standard mailbox flags UNKNOWN, MARKED, diff --git a/src/vmime/net/imap/IMAPStore.cpp b/src/vmime/net/imap/IMAPStore.cpp index a1a8c9ca..031ebf24 100644 --- a/src/vmime/net/imap/IMAPStore.cpp +++ b/src/vmime/net/imap/IMAPStore.cpp @@ -76,7 +76,8 @@ shared_ptr IMAPStore::getRootFolder() return make_shared (folder::path(), - dynamicCast (shared_from_this())); + dynamicCast (shared_from_this()), + shared_ptr ()); } @@ -87,7 +88,8 @@ shared_ptr IMAPStore::getDefaultFolder() return make_shared (folder::path::component("INBOX"), - dynamicCast (shared_from_this())); + dynamicCast (shared_from_this()), + shared_ptr ()); } @@ -97,7 +99,9 @@ shared_ptr IMAPStore::getFolder(const folder::path& path) throw exceptions::illegal_state("Not connected"); return make_shared - (path, dynamicCast (shared_from_this())); + (path, + dynamicCast (shared_from_this()), + shared_ptr ()); } diff --git a/src/vmime/net/imap/IMAPUtils.cpp b/src/vmime/net/imap/IMAPUtils.cpp index a58035cb..519e413b 100644 --- a/src/vmime/net/imap/IMAPUtils.cpp +++ b/src/vmime/net/imap/IMAPUtils.cpp @@ -366,52 +366,89 @@ const folder::path::component IMAPUtils::fromModifiedUTF7(const string& text) } -int IMAPUtils::folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list) +// static +void IMAPUtils::mailboxFlagsToFolderAttributes + (shared_ptr cnt, const IMAPParser::mailbox_flag_list* list, + folderAttributes& attribs) { - // Get folder type - int type = folder::TYPE_CONTAINS_MESSAGES | folder::TYPE_CONTAINS_FOLDERS; - const std::vector & flags = list->flags(); - - for (std::vector ::const_iterator it = flags.begin() ; - it != flags.end() ; ++it) - { - if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT) - type &= ~folder::TYPE_CONTAINS_MESSAGES; - } - - if (type & folder::TYPE_CONTAINS_MESSAGES) - type &= ~folder::TYPE_CONTAINS_FOLDERS; - - return (type); -} - - -int IMAPUtils::folderFlagsFromFlags - (shared_ptr cnt, const IMAPParser::mailbox_flag_list* list) -{ - int folderFlags = 0; + int specialUse = folderAttributes::SPECIALUSE_NONE; + int type = folderAttributes::TYPE_CONTAINS_MESSAGES | folderAttributes::TYPE_CONTAINS_FOLDERS; + int flags = 0; // If CHILDREN extension (RFC-3348) is not supported, assume folder has children // as we have no hint about it if (!cnt->hasCapability("CHILDREN")) - folderFlags |= folder::FLAG_HAS_CHILDREN; + flags |= folderAttributes::FLAG_HAS_CHILDREN; - const std::vector & flags = list->flags(); + const std::vector & mailboxFlags = list->flags(); - for (std::vector ::const_iterator it = flags.begin() ; - it != flags.end() ; ++it) + for (std::vector ::const_iterator it = mailboxFlags.begin() ; + it != mailboxFlags.end() ; ++it) { - if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT) - folderFlags |= folder::FLAG_NO_OPEN; - else if ((*it)->type() == IMAPParser::mailbox_flag::NOINFERIORS) - folderFlags &= ~folder::FLAG_HAS_CHILDREN; - else if ((*it)->type() == IMAPParser::mailbox_flag::HASNOCHILDREN) - folderFlags &= ~folder::FLAG_HAS_CHILDREN; - else if ((*it)->type() == IMAPParser::mailbox_flag::HASCHILDREN) - folderFlags |= folder::FLAG_HAS_CHILDREN; + switch ((*it)->type()) + { + case IMAPParser::mailbox_flag::NOSELECT: + + type &= ~folderAttributes::TYPE_CONTAINS_MESSAGES; + flags |= folderAttributes::FLAG_NO_OPEN; + break; + + case IMAPParser::mailbox_flag::NOINFERIORS: + case IMAPParser::mailbox_flag::HASNOCHILDREN: + + flags &= ~folderAttributes::FLAG_HAS_CHILDREN; + break; + + case IMAPParser::mailbox_flag::HASCHILDREN: + + flags |= folderAttributes::FLAG_HAS_CHILDREN; + break; + + case IMAPParser::mailbox_flag::SPECIALUSE_ALL: + + specialUse = folderAttributes::SPECIALUSE_ALL; + break; + + case IMAPParser::mailbox_flag::SPECIALUSE_ARCHIVE: + + specialUse = folderAttributes::SPECIALUSE_ARCHIVE; + break; + + case IMAPParser::mailbox_flag::SPECIALUSE_DRAFTS: + + specialUse = folderAttributes::SPECIALUSE_DRAFTS; + break; + + case IMAPParser::mailbox_flag::SPECIALUSE_FLAGGED: + + specialUse = folderAttributes::SPECIALUSE_FLAGGED; + break; + + case IMAPParser::mailbox_flag::SPECIALUSE_JUNK: + + specialUse = folderAttributes::SPECIALUSE_JUNK; + break; + + case IMAPParser::mailbox_flag::SPECIALUSE_SENT: + + specialUse = folderAttributes::SPECIALUSE_SENT; + break; + + case IMAPParser::mailbox_flag::SPECIALUSE_TRASH: + + specialUse = folderAttributes::SPECIALUSE_TRASH; + break; + + case IMAPParser::mailbox_flag::SPECIALUSE_IMPORTANT: + + specialUse = folderAttributes::SPECIALUSE_IMPORTANT; + break; + } } - return (folderFlags); + attribs.setSpecialUse(specialUse); + attribs.setType(type); + attribs.setFlags(flags); } diff --git a/src/vmime/net/imap/IMAPUtils.hpp b/src/vmime/net/imap/IMAPUtils.hpp index 55443cfc..2a7efbb0 100644 --- a/src/vmime/net/imap/IMAPUtils.hpp +++ b/src/vmime/net/imap/IMAPUtils.hpp @@ -66,10 +66,16 @@ public: */ static const string quoteString(const string& text); - static int folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list); - static int folderFlagsFromFlags + /** Parse mailbox flags and fill in folder attributes. + * + * @param cnt reference to current IMAP connection (for testing capabilities) + * @param list list of mailbox flags + * @param attribs reference to an object holding folder attributes + */ + static void mailboxFlagsToFolderAttributes (shared_ptr cnt, - const IMAPParser::mailbox_flag_list* list); + const IMAPParser::mailbox_flag_list* list, + folderAttributes& attribs); static int messageFlagsFromFlags(const IMAPParser::flag_list* list); diff --git a/src/vmime/net/maildir/maildirFolder.cpp b/src/vmime/net/maildir/maildirFolder.cpp index 5d57f3e7..feb24fd7 100644 --- a/src/vmime/net/maildir/maildirFolder.cpp +++ b/src/vmime/net/maildir/maildirFolder.cpp @@ -91,23 +91,19 @@ int maildirFolder::getMode() const } -int maildirFolder::getType() +const folderAttributes maildirFolder::getAttributes() { + folderAttributes attribs; + if (m_path.isEmpty()) - return (TYPE_CONTAINS_FOLDERS); + attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS); else - return (TYPE_CONTAINS_FOLDERS | TYPE_CONTAINS_MESSAGES); -} - - -int maildirFolder::getFlags() -{ - int flags = 0; + attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS | folderAttributes::TYPE_CONTAINS_MESSAGES); if (m_store.lock()->getFormat()->folderHasSubfolders(m_path)) - flags |= FLAG_HAS_CHILDREN; // Contains at least one sub-folder + attribs.setFlags(folderAttributes::FLAG_HAS_CHILDREN); // contains at least one sub-folder - return (flags); + return attribs; } @@ -189,7 +185,7 @@ void maildirFolder::unregisterMessage(maildirMessage* msg) } -void maildirFolder::create(const int /* type */) +void maildirFolder::create(const folderAttributes& /* attribs */) { shared_ptr store = m_store.lock(); diff --git a/src/vmime/net/maildir/maildirFolder.hpp b/src/vmime/net/maildir/maildirFolder.hpp index 6563b86a..85677c07 100644 --- a/src/vmime/net/maildir/maildirFolder.hpp +++ b/src/vmime/net/maildir/maildirFolder.hpp @@ -71,16 +71,14 @@ public: int getMode() const; - int getType(); - - int getFlags(); + 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 int type); + void create(const folderAttributes& attribs); bool exists(); diff --git a/src/vmime/net/pop3/POP3Folder.cpp b/src/vmime/net/pop3/POP3Folder.cpp index abee8b28..116157e6 100644 --- a/src/vmime/net/pop3/POP3Folder.cpp +++ b/src/vmime/net/pop3/POP3Folder.cpp @@ -81,23 +81,23 @@ int POP3Folder::getMode() const } -int POP3Folder::getType() +const folderAttributes POP3Folder::getAttributes() { if (!isOpen()) throw exceptions::illegal_state("Folder not open"); + folderAttributes attribs; + if (m_path.isEmpty()) - return (TYPE_CONTAINS_FOLDERS); + attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS); else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX") - return (TYPE_CONTAINS_MESSAGES); + attribs.setType(folderAttributes::TYPE_CONTAINS_MESSAGES); else throw exceptions::folder_not_found(); -} + attribs.setFlags(0); -int POP3Folder::getFlags() -{ - return (0); + return attribs; } @@ -186,7 +186,7 @@ void POP3Folder::onClose() } -void POP3Folder::create(const int /* type */) +void POP3Folder::create(const folderAttributes& /* attribs */) { throw exceptions::operation_not_supported(); } diff --git a/src/vmime/net/pop3/POP3Folder.hpp b/src/vmime/net/pop3/POP3Folder.hpp index a4b30c18..3db2aa27 100644 --- a/src/vmime/net/pop3/POP3Folder.hpp +++ b/src/vmime/net/pop3/POP3Folder.hpp @@ -68,16 +68,14 @@ public: int getMode() const; - int getType(); - - int getFlags(); + 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 int type); + void create(const folderAttributes& attribs); bool exists(); diff --git a/tests/net/folderAttributesTest.cpp b/tests/net/folderAttributesTest.cpp new file mode 100644 index 00000000..06235399 --- /dev/null +++ b/tests/net/folderAttributesTest.cpp @@ -0,0 +1,137 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2014 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 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 "tests/testUtils.hpp" + +#include "vmime/net/folderAttributes.hpp" + + +VMIME_TEST_SUITE_BEGIN(folderAttributesTest) + + VMIME_TEST_LIST_BEGIN + VMIME_TEST(testConstruct) + VMIME_TEST(testConstructCopy) + VMIME_TEST(testSetType) + VMIME_TEST(testSetFlags) + VMIME_TEST(testHasFlag) + VMIME_TEST(testSetUserFlags) + VMIME_TEST(testHasUserFlag) + VMIME_TEST(testSetSpecialUse) + VMIME_TEST_LIST_END + + + void testConstruct() + { + vmime::net::folderAttributes attr; + + // Default values + VASSERT_EQ("type", vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS + | vmime::net::folderAttributes::TYPE_CONTAINS_MESSAGES, attr.getType()); + VASSERT_EQ("flags", 0, attr.getFlags()); + VASSERT_EQ("user-flags", 0, attr.getUserFlags().size()); + VASSERT_EQ("special-use", vmime::net::folderAttributes::SPECIALUSE_NONE, attr.getSpecialUse()); + } + + void testConstructCopy() + { + std::vector userFlags; + userFlags.push_back("\\XMyFlag1"); + userFlags.push_back("\\XMyFlag2"); + userFlags.push_back("\\XMyFlag3"); + + vmime::net::folderAttributes attr; + + attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN); + attr.setUserFlags(userFlags); + + vmime::net::folderAttributes attr2(attr); + + VASSERT("flags", attr2.getFlags() == attr.getFlags()); + VASSERT("user-flags", attr2.getUserFlags() == attr.getUserFlags()); + } + + void testSetType() + { + vmime::net::folderAttributes attr; + attr.setType(vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS); + + VASSERT_EQ("eq", vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS, attr.getType()); + } + + void testSetFlags() + { + vmime::net::folderAttributes attr; + attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN); + + VASSERT_EQ("eq", vmime::net::folderAttributes::FLAG_HAS_CHILDREN, attr.getFlags()); + } + + void testHasFlag() + { + vmime::net::folderAttributes attr; + attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN); + + VASSERT("has", attr.hasFlag(vmime::net::folderAttributes::FLAG_HAS_CHILDREN)); + VASSERT("has-not", !attr.hasFlag(vmime::net::folderAttributes::FLAG_NO_OPEN)); + } + + void testSetUserFlags() + { + std::vector userFlags; + userFlags.push_back("\\XMyFlag1"); + userFlags.push_back("\\XMyFlag2"); + userFlags.push_back("\\XMyFlag3"); + + vmime::net::folderAttributes attr; + attr.setUserFlags(userFlags); + + VASSERT("eq", attr.getUserFlags() == userFlags); + } + + void testHasUserFlag() + { + std::vector userFlags; + userFlags.push_back("\\XMyFlag1"); + userFlags.push_back("\\XMyFlag2"); + userFlags.push_back("\\XMyFlag3"); + + vmime::net::folderAttributes attr; + attr.setUserFlags(userFlags); + + VASSERT("has", attr.hasUserFlag("\\XMyFlag1")); + VASSERT("has-casesensitive", !attr.hasUserFlag("\\xmyflag1")); + VASSERT("has-not", !attr.hasUserFlag("\\XMyFlag4")); + } + + void testSetSpecialUse() + { + const int use = vmime::net::folderAttributes::SPECIALUSE_JUNK + | vmime::net::folderAttributes::SPECIALUSE_TRASH; + + vmime::net::folderAttributes attr; + attr.setSpecialUse(use); + + VASSERT_EQ("eq", use, attr.getSpecialUse()); + } + +VMIME_TEST_SUITE_END diff --git a/tests/net/maildir/maildirStoreTest.cpp b/tests/net/maildir/maildirStoreTest.cpp index 34e8249c..7e0ee39a 100644 --- a/tests/net/maildir/maildirStoreTest.cpp +++ b/tests/net/maildir/maildirStoreTest.cpp @@ -456,8 +456,10 @@ public: VASSERT("Before", !store->getFolder(fpath() / "Folder" / "NewFolder")->exists()); - VASSERT_NO_THROW("Creation", store->getFolder(fpath() / "Folder" / "NewFolder")-> - create(vmime::net::folder::TYPE_CONTAINS_MESSAGES)); + vmime::net::folderAttributes attribs; + attribs.setType(vmime::net::folderAttributes::TYPE_CONTAINS_MESSAGES); + + VASSERT_NO_THROW("Creation", store->getFolder(fpath() / "Folder" / "NewFolder")->create(attribs)); VASSERT("After", store->getFolder(fpath() / "Folder" / "NewFolder")->exists());