aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Richard <[email protected]>2014-01-03 19:41:32 +0000
committerVincent Richard <[email protected]>2014-01-03 19:41:32 +0000
commitbd378bbfa228f723c62da09c7caa09b8e5569266 (patch)
treea2354843ab3dd4cc279b6f5967f73ef96f66f38e
parentDo not expose internal constants. (diff)
downloadvmime-bd378bbfa228f723c62da09c7caa09b8e5569266.tar.gz
vmime-bd378bbfa228f723c62da09c7caa09b8e5569266.zip
Added support for SPECIAL-USE extension (IMAP).
-rw-r--r--src/vmime/net/folder.cpp12
-rw-r--r--src/vmime/net/folder.hpp38
-rw-r--r--src/vmime/net/folderAttributes.cpp121
-rw-r--r--src/vmime/net/folderAttributes.hpp179
-rw-r--r--src/vmime/net/imap/IMAPFolder.cpp110
-rw-r--r--src/vmime/net/imap/IMAPFolder.hpp11
-rw-r--r--src/vmime/net/imap/IMAPParser.hpp109
-rw-r--r--src/vmime/net/imap/IMAPStore.cpp10
-rw-r--r--src/vmime/net/imap/IMAPUtils.cpp105
-rw-r--r--src/vmime/net/imap/IMAPUtils.hpp12
-rw-r--r--src/vmime/net/maildir/maildirFolder.cpp20
-rw-r--r--src/vmime/net/maildir/maildirFolder.hpp6
-rw-r--r--src/vmime/net/pop3/POP3Folder.cpp16
-rw-r--r--src/vmime/net/pop3/POP3Folder.hpp6
-rw-r--r--tests/net/folderAttributesTest.cpp137
-rw-r--r--tests/net/maildir/maildirStoreTest.cpp6
16 files changed, 740 insertions, 158 deletions
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)
+ */
+ int getFlags();
+
+ /** Return the attributes of the folder.
+ *
+ * @return folder attributes (see folder::Flags)
*/
- virtual int getFlags() = 0;
+ 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 <[email protected]>
+//
+// 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 <algorithm>
+
+
+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 <string> folderAttributes::getUserFlags() const
+{
+ return m_userFlags;
+}
+
+
+void folderAttributes::setUserFlags(const std::vector <string>& 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 <[email protected]>
+//
+// 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 <vector>
+
+#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 <string> getUserFlags() const;
+
+ /** Set the user-defined flags of the folder.
+ *
+ * @param flags a list of user-defined flags
+ */
+ void setUserFlags(const std::vector <string>& 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 <string> 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 <IMAPStore> store, const int type, const int flags)
+IMAPFolder::IMAPFolder(const folder::path& path, shared_ptr <IMAPStore> store, shared_ptr <folderAttributes> 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);
- }
- else
- {
- if (m_type == TYPE_UNDEFINED)
- testExistAndGetType();
+ folderAttributes attribs;
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS);
+ attribs.setFlags(folderAttributes::FLAG_HAS_CHILDREN | folderAttributes::FLAG_NO_OPEN);
- 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);
+ return attribs;
}
else
{
- if (m_flags == FLAG_UNDEFINED)
+ if (!m_attribs)
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 <folderAttributes>();
- 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 <IMAPStore> 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 <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
+ folderAttributes attribs;
+ attribs.setType(-1);
+
for (std::vector <IMAPParser::continue_req_or_response_data*>::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 <folderAttributes>(attribs);
+
+ return m_attribs->getType();
}
@@ -656,7 +664,7 @@ shared_ptr <folder> IMAPFolder::getFolder(const folder::path::component& name)
if (!store)
throw exceptions::illegal_state("Store disconnected");
- return make_shared <IMAPFolder>(m_path / name, store);
+ return make_shared <IMAPFolder>(m_path / name, store, shared_ptr <folderAttributes>());
}
@@ -740,9 +748,11 @@ std::vector <shared_ptr <folder> > 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 <IMAPFolder>(path, store,
- IMAPUtils::folderTypeFromFlags(mailbox_flag_list),
- IMAPUtils::folderFlagsFromFlags(m_connection, mailbox_flag_list)));
+ shared_ptr <folderAttributes> attribs = make_shared <folderAttributes>();
+ IMAPUtils::mailboxFlagsToFolderAttributes
+ (m_connection, mailbox_flag_list, *attribs);
+
+ v.push_back(make_shared <IMAPFolder>(path, store, attribs));
}
}
@@ -867,7 +877,7 @@ shared_ptr <folder> IMAPFolder::getParent()
if (m_path.isEmpty())
return null;
else
- return make_shared <IMAPFolder>(m_path.getParent(), m_store.lock());
+ return make_shared <IMAPFolder>(m_path.getParent(), m_store.lock(), shared_ptr <folderAttributes>());
}
@@ -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 <folderAttributes>(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 <IMAPStore> store, const int type = TYPE_UNDEFINED, const int flags = FLAG_UNDEFINED);
+ IMAPFolder(const folder::path& path, shared_ptr <IMAPStore> store, shared_ptr <folderAttributes> 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 <folderAttributes> m_attribs;
shared_ptr <IMAPFolderStatus> 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 <folder> IMAPStore::getRootFolder()
return make_shared <IMAPFolder>
(folder::path(),
- dynamicCast <IMAPStore>(shared_from_this()));
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>());
}
@@ -87,7 +88,8 @@ shared_ptr <folder> IMAPStore::getDefaultFolder()
return make_shared <IMAPFolder>
(folder::path::component("INBOX"),
- dynamicCast <IMAPStore>(shared_from_this()));
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>());
}
@@ -97,7 +99,9 @@ shared_ptr <folder> IMAPStore::getFolder(const folder::path& path)
throw exceptions::illegal_state("Not connected");
return make_shared <IMAPFolder>
- (path, dynamicCast <IMAPStore>(shared_from_this()));
+ (path,
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>());
}
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 <const IMAPConnection> 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 <IMAPParser::mailbox_flag*>& flags = list->flags();
+ 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"))
+ flags |= folderAttributes::FLAG_HAS_CHILDREN;
- for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ;
- it != flags.end() ; ++it)
+ const std::vector <IMAPParser::mailbox_flag*>& mailboxFlags = list->flags();
+
+ for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = mailboxFlags.begin() ;
+ it != mailboxFlags.end() ; ++it)
{
- if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT)
- type &= ~folder::TYPE_CONTAINS_MESSAGES;
- }
+ switch ((*it)->type())
+ {
+ case IMAPParser::mailbox_flag::NOSELECT:
- if (type & folder::TYPE_CONTAINS_MESSAGES)
- type &= ~folder::TYPE_CONTAINS_FOLDERS;
+ type &= ~folderAttributes::TYPE_CONTAINS_MESSAGES;
+ flags |= folderAttributes::FLAG_NO_OPEN;
+ break;
- return (type);
-}
+ case IMAPParser::mailbox_flag::NOINFERIORS:
+ case IMAPParser::mailbox_flag::HASNOCHILDREN:
+ flags &= ~folderAttributes::FLAG_HAS_CHILDREN;
+ break;
-int IMAPUtils::folderFlagsFromFlags
- (shared_ptr <const IMAPConnection> cnt, const IMAPParser::mailbox_flag_list* list)
-{
- int folderFlags = 0;
+ case IMAPParser::mailbox_flag::HASCHILDREN:
- // 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;
+ break;
- const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags();
+ case IMAPParser::mailbox_flag::SPECIALUSE_ALL:
- for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ;
- it != flags.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;
+ 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 <const IMAPConnection> 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 <maildirStore> 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 <[email protected]>
+//
+// 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 <vmime::string> 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 <vmime::string> 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 <vmime::string> 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());