Added support for SPECIAL-USE extension (IMAP).

This commit is contained in:
Vincent Richard 2014-01-03 20:41:32 +01:00
parent 1791e5114a
commit bd378bbfa2
16 changed files with 743 additions and 161 deletions

View File

@ -36,6 +36,18 @@ namespace vmime {
namespace net { namespace net {
int folder::getType()
{
return getAttributes().getType();
}
int folder::getFlags()
{
return getAttributes().getFlags();
}
void folder::addMessageChangedListener(events::messageChangedListener* l) void folder::addMessageChangedListener(events::messageChangedListener* l)
{ {
m_messageChangedListeners.push_back(l); m_messageChangedListeners.push_back(l);

View File

@ -42,6 +42,7 @@
#include "vmime/net/events.hpp" #include "vmime/net/events.hpp"
#include "vmime/net/folderStatus.hpp" #include "vmime/net/folderStatus.hpp"
#include "vmime/net/fetchAttributes.hpp" #include "vmime/net/fetchAttributes.hpp"
#include "vmime/net/folderAttributes.hpp"
#include "vmime/utility/path.hpp" #include "vmime/utility/path.hpp"
#include "vmime/utility/stream.hpp" #include "vmime/utility/stream.hpp"
@ -91,33 +92,28 @@ public:
MODE_READ_WRITE /**< Full access mode (read and write). */ 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 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 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. /** Return the mode in which the folder has been open.
* *
@ -159,10 +155,10 @@ public:
/** Create this folder. /** 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 * @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. /** Test whether this folder exists.
* *

View File

@ -0,0 +1,121 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2014 Vincent Richard <vincent@vmime.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#include "vmime/config.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES
#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

View File

@ -0,0 +1,179 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2014 Vincent Richard <vincent@vmime.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#ifndef VMIME_NET_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

View File

@ -51,10 +51,10 @@ namespace net {
namespace imap { 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_store(store), m_connection(store->connection()), m_path(path),
m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()), m_mode(-1), 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); store->registerFolder(this);
@ -90,7 +90,7 @@ int IMAPFolder::getMode() const
} }
int IMAPFolder::getType() const folderAttributes IMAPFolder::getAttributes()
{ {
if (!isOpen()) if (!isOpen())
throw exceptions::illegal_state("Folder not open"); throw exceptions::illegal_state("Folder not open");
@ -98,34 +98,18 @@ int IMAPFolder::getType()
// Root folder // Root folder
if (m_path.isEmpty()) 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 else
{ {
if (m_type == TYPE_UNDEFINED) if (!m_attribs)
testExistAndGetType(); testExistAndGetType();
return (m_type); return *m_attribs;
}
}
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);
} }
} }
@ -245,11 +229,11 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable)
case IMAPParser::mailbox_data::FLAGS: case IMAPParser::mailbox_data::FLAGS:
{ {
m_type = IMAPUtils::folderTypeFromFlags if (!m_attribs)
(responseData->mailbox_data()->mailbox_flag_list()); m_attribs = make_shared <folderAttributes>();
m_flags = IMAPUtils::folderFlagsFromFlags IMAPUtils::mailboxFlagsToFolderAttributes
(connection, responseData->mailbox_data()->mailbox_flag_list()); (connection, responseData->mailbox_data()->mailbox_flag_list(), *m_attribs);
break; 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(); shared_ptr <IMAPStore> store = m_store.lock();
@ -361,12 +345,36 @@ void IMAPFolder::create(const int type)
string mailbox = IMAPUtils::pathToString string mailbox = IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath()); (m_connection->hierarchySeparator(), getFullPath());
if (type & TYPE_CONTAINS_FOLDERS) if (attribs.getType() & folderAttributes::TYPE_CONTAINS_FOLDERS)
mailbox += m_connection->hierarchySeparator(); mailbox += m_connection->hierarchySeparator();
std::ostringstream oss; std::ostringstream oss;
oss << "CREATE " << IMAPUtils::quoteString(mailbox); 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); m_connection->send(true, oss.str(), true);
@ -434,14 +442,12 @@ bool IMAPFolder::exists()
if (!isOpen() && !store) if (!isOpen() && !store)
throw exceptions::illegal_state("Store disconnected"); throw exceptions::illegal_state("Store disconnected");
return (testExistAndGetType() != TYPE_UNDEFINED); return testExistAndGetType() != -1;
} }
int IMAPFolder::testExistAndGetType() int IMAPFolder::testExistAndGetType()
{ {
m_type = TYPE_UNDEFINED;
// To test whether a folder exists, we simple list it using // To test whether a folder exists, we simple list it using
// the "LIST" command, and there should be one unique mailbox // the "LIST" command, and there should be one unique mailbox
// with this name... // with this name...
@ -482,6 +488,9 @@ int IMAPFolder::testExistAndGetType()
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data(); resp->continue_req_or_response_data();
folderAttributes attribs;
attribs.setType(-1);
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it) it = respDataList.begin() ; it != respDataList.end() ; ++it)
{ {
@ -498,15 +507,14 @@ int IMAPFolder::testExistAndGetType()
if (mailboxData != NULL && mailboxData->type() == IMAPParser::mailbox_data::LIST) if (mailboxData != NULL && mailboxData->type() == IMAPParser::mailbox_data::LIST)
{ {
// Get the folder type/flags at the same time // Get the folder type/flags at the same time
m_type = IMAPUtils::folderTypeFromFlags IMAPUtils::mailboxFlagsToFolderAttributes
(mailboxData->mailbox_list()->mailbox_flag_list()); (m_connection, mailboxData->mailbox_list()->mailbox_flag_list(), attribs);
m_flags = IMAPUtils::folderFlagsFromFlags
(m_connection, mailboxData->mailbox_list()->mailbox_flag_list());
} }
} }
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) if (!store)
throw exceptions::illegal_state("Store disconnected"); 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 = const class IMAPParser::mailbox_flag_list* mailbox_flag_list =
mailboxData->mailbox_list()->mailbox_flag_list(); mailboxData->mailbox_list()->mailbox_flag_list();
v.push_back(make_shared <IMAPFolder>(path, store, shared_ptr <folderAttributes> attribs = make_shared <folderAttributes>();
IMAPUtils::folderTypeFromFlags(mailbox_flag_list), IMAPUtils::mailboxFlagsToFolderAttributes
IMAPUtils::folderFlagsFromFlags(m_connection, mailbox_flag_list))); (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()) if (m_path.isEmpty())
return null; return null;
else 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()) else if ((*it)->response_data() && (*it)->response_data()->mailbox_data())
{ {
m_status->updateFromResponse((*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()) else if ((*it)->response_data() && (*it)->response_data()->message_data())
{ {

View File

@ -66,22 +66,20 @@ private:
public: 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(); ~IMAPFolder();
int getMode() const; int getMode() const;
int getType(); const folderAttributes getAttributes();
int getFlags();
const folder::path::component getName() const; const folder::path::component getName() const;
const folder::path getFullPath() const; const folder::path getFullPath() const;
void open(const int mode, bool failIfModeIsNotAvailable = false); void open(const int mode, bool failIfModeIsNotAvailable = false);
void close(const bool expunge); void close(const bool expunge);
void create(const int type); void create(const folderAttributes& attribs);
bool exists(); bool exists();
@ -195,8 +193,7 @@ private:
int m_mode; int m_mode;
bool m_open; bool m_open;
int m_type; shared_ptr <folderAttributes> m_attribs;
int m_flags;
shared_ptr <IMAPFolderStatus> m_status; shared_ptr <IMAPFolderStatus> m_status;

View File

@ -1803,23 +1803,92 @@ public:
const string name = utility::stringUtils::toLower(at->value()); const string name = utility::stringUtils::toLower(at->value());
delete (at); delete (at);
if (name == "marked") m_type = UNKNOWN; // default
m_type = MARKED;
else if (name == "noinferiors") switch (name[0])
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; case 'a':
m_name = "\\" + name;
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 else
{ {
@ -1841,6 +1910,16 @@ public:
HASCHILDREN, HASCHILDREN,
HASNOCHILDREN, 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 // Standard mailbox flags
UNKNOWN, UNKNOWN,
MARKED, MARKED,

View File

@ -76,7 +76,8 @@ shared_ptr <folder> IMAPStore::getRootFolder()
return make_shared <IMAPFolder> return make_shared <IMAPFolder>
(folder::path(), (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> return make_shared <IMAPFolder>
(folder::path::component("INBOX"), (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"); throw exceptions::illegal_state("Not connected");
return make_shared <IMAPFolder> return make_shared <IMAPFolder>
(path, dynamicCast <IMAPStore>(shared_from_this())); (path,
dynamicCast <IMAPStore>(shared_from_this()),
shared_ptr <folderAttributes>());
} }

View File

@ -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 specialUse = folderAttributes::SPECIALUSE_NONE;
int type = folder::TYPE_CONTAINS_MESSAGES | folder::TYPE_CONTAINS_FOLDERS; int type = folderAttributes::TYPE_CONTAINS_MESSAGES | folderAttributes::TYPE_CONTAINS_FOLDERS;
const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags(); int flags = 0;
for (std::vector <IMAPParser::mailbox_flag*>::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 <const IMAPConnection> cnt, const IMAPParser::mailbox_flag_list* list)
{
int folderFlags = 0;
// If CHILDREN extension (RFC-3348) is not supported, assume folder has children // If CHILDREN extension (RFC-3348) is not supported, assume folder has children
// as we have no hint about it // as we have no hint about it
if (!cnt->hasCapability("CHILDREN")) if (!cnt->hasCapability("CHILDREN"))
folderFlags |= folder::FLAG_HAS_CHILDREN; flags |= folderAttributes::FLAG_HAS_CHILDREN;
const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags(); const std::vector <IMAPParser::mailbox_flag*>& mailboxFlags = list->flags();
for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ; for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = mailboxFlags.begin() ;
it != flags.end() ; ++it) it != mailboxFlags.end() ; ++it)
{ {
if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT) switch ((*it)->type())
folderFlags |= folder::FLAG_NO_OPEN; {
else if ((*it)->type() == IMAPParser::mailbox_flag::NOINFERIORS) case IMAPParser::mailbox_flag::NOSELECT:
folderFlags &= ~folder::FLAG_HAS_CHILDREN;
else if ((*it)->type() == IMAPParser::mailbox_flag::HASNOCHILDREN) type &= ~folderAttributes::TYPE_CONTAINS_MESSAGES;
folderFlags &= ~folder::FLAG_HAS_CHILDREN; flags |= folderAttributes::FLAG_NO_OPEN;
else if ((*it)->type() == IMAPParser::mailbox_flag::HASCHILDREN) break;
folderFlags |= folder::FLAG_HAS_CHILDREN;
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);
} }

View File

@ -66,10 +66,16 @@ public:
*/ */
static const string quoteString(const string& text); static const string quoteString(const string& text);
static int folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list); /** Parse mailbox flags and fill in folder attributes.
static int folderFlagsFromFlags *
* @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, (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); static int messageFlagsFromFlags(const IMAPParser::flag_list* list);

View File

@ -91,23 +91,19 @@ int maildirFolder::getMode() const
} }
int maildirFolder::getType() const folderAttributes maildirFolder::getAttributes()
{ {
folderAttributes attribs;
if (m_path.isEmpty()) if (m_path.isEmpty())
return (TYPE_CONTAINS_FOLDERS); attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS);
else else
return (TYPE_CONTAINS_FOLDERS | TYPE_CONTAINS_MESSAGES); attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS | folderAttributes::TYPE_CONTAINS_MESSAGES);
}
int maildirFolder::getFlags()
{
int flags = 0;
if (m_store.lock()->getFormat()->folderHasSubfolders(m_path)) 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(); shared_ptr <maildirStore> store = m_store.lock();

View File

@ -71,16 +71,14 @@ public:
int getMode() const; int getMode() const;
int getType(); const folderAttributes getAttributes();
int getFlags();
const folder::path::component getName() const; const folder::path::component getName() const;
const folder::path getFullPath() const; const folder::path getFullPath() const;
void open(const int mode, bool failIfModeIsNotAvailable = false); void open(const int mode, bool failIfModeIsNotAvailable = false);
void close(const bool expunge); void close(const bool expunge);
void create(const int type); void create(const folderAttributes& attribs);
bool exists(); bool exists();

View File

@ -81,23 +81,23 @@ int POP3Folder::getMode() const
} }
int POP3Folder::getType() const folderAttributes POP3Folder::getAttributes()
{ {
if (!isOpen()) if (!isOpen())
throw exceptions::illegal_state("Folder not open"); throw exceptions::illegal_state("Folder not open");
folderAttributes attribs;
if (m_path.isEmpty()) 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") else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX")
return (TYPE_CONTAINS_MESSAGES); attribs.setType(folderAttributes::TYPE_CONTAINS_MESSAGES);
else else
throw exceptions::folder_not_found(); throw exceptions::folder_not_found();
}
attribs.setFlags(0);
int POP3Folder::getFlags() return attribs;
{
return (0);
} }
@ -186,7 +186,7 @@ void POP3Folder::onClose()
} }
void POP3Folder::create(const int /* type */) void POP3Folder::create(const folderAttributes& /* attribs */)
{ {
throw exceptions::operation_not_supported(); throw exceptions::operation_not_supported();
} }

View File

@ -68,16 +68,14 @@ public:
int getMode() const; int getMode() const;
int getType(); const folderAttributes getAttributes();
int getFlags();
const folder::path::component getName() const; const folder::path::component getName() const;
const folder::path getFullPath() const; const folder::path getFullPath() const;
void open(const int mode, bool failIfModeIsNotAvailable = false); void open(const int mode, bool failIfModeIsNotAvailable = false);
void close(const bool expunge); void close(const bool expunge);
void create(const int type); void create(const folderAttributes& attribs);
bool exists(); bool exists();

View File

@ -0,0 +1,137 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2014 Vincent Richard <vincent@vmime.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#include "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

View File

@ -456,8 +456,10 @@ public:
VASSERT("Before", !store->getFolder(fpath() / "Folder" / "NewFolder")->exists()); VASSERT("Before", !store->getFolder(fpath() / "Folder" / "NewFolder")->exists());
VASSERT_NO_THROW("Creation", store->getFolder(fpath() / "Folder" / "NewFolder")-> vmime::net::folderAttributes attribs;
create(vmime::net::folder::TYPE_CONTAINS_MESSAGES)); 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()); VASSERT("After", store->getFolder(fpath() / "Folder" / "NewFolder")->exists());