vmime/src/net/imap/IMAPFolder.cpp
2013-01-10 17:30:31 +01:00

1949 lines
49 KiB
C++

//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library. Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//
#include "vmime/config.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
#include "vmime/net/imap/IMAPFolder.hpp"
#include "vmime/net/imap/IMAPStore.hpp"
#include "vmime/net/imap/IMAPParser.hpp"
#include "vmime/net/imap/IMAPMessage.hpp"
#include "vmime/net/imap/IMAPUtils.hpp"
#include "vmime/net/imap/IMAPConnection.hpp"
#include "vmime/message.hpp"
#include "vmime/exception.hpp"
#include "vmime/utility/smartPtr.hpp"
#include "vmime/utility/outputStreamAdapter.hpp"
#include <algorithm>
#include <sstream>
namespace vmime {
namespace net {
namespace imap {
IMAPFolder::IMAPFolder(const folder::path& path, ref <IMAPStore> store, const int type, const int flags)
: 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_messageCount(0), m_uidValidity(0)
{
store->registerFolder(this);
}
IMAPFolder::~IMAPFolder()
{
ref <IMAPStore> store = m_store.acquire();
if (store)
{
if (m_open)
close(false);
store->unregisterFolder(this);
}
else if (m_open)
{
m_connection = NULL;
onClose();
}
}
int IMAPFolder::getMode() const
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
return (m_mode);
}
int IMAPFolder::getType()
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
// Root folder
if (m_path.isEmpty())
{
return (TYPE_CONTAINS_FOLDERS);
}
else
{
if (m_type == TYPE_UNDEFINED)
testExistAndGetType();
return (m_type);
}
}
int IMAPFolder::getFlags()
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
// Root folder
if (m_path.isEmpty())
{
return (FLAG_CHILDREN | FLAG_NO_OPEN);
}
else
{
if (m_flags == FLAG_UNDEFINED)
testExistAndGetType();
return (m_flags);
}
}
const folder::path::component IMAPFolder::getName() const
{
return (m_name);
}
const folder::path IMAPFolder::getFullPath() const
{
return (m_path);
}
void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
// Open a connection for this folder
ref <IMAPConnection> connection =
vmime::create <IMAPConnection>(store, store->getAuthenticator());
try
{
connection->connect();
// Emit the "SELECT" command
//
// Example: C: A142 SELECT INBOX
// S: * 172 EXISTS
// S: * 1 RECENT
// S: * OK [UNSEEN 12] Message 12 is first unseen
// S: * OK [UIDVALIDITY 3857529045] UIDs valid
// S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
// S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
// S: A142 OK [READ-WRITE] SELECT completed
std::ostringstream oss;
if (mode == MODE_READ_ONLY)
oss << "EXAMINE ";
else
oss << "SELECT ";
oss << IMAPUtils::quoteString(IMAPUtils::pathToString
(connection->hierarchySeparator(), getFullPath()));
connection->send(true, oss.str(), true);
// Read the response
utility::auto_ptr <IMAPParser::response> resp(connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("SELECT",
connection->getParser()->lastLine(), "bad response");
}
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("SELECT",
connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::response_data* responseData = (*it)->response_data();
// OK Untagged responses: UNSEEN, PERMANENTFLAGS, UIDVALIDITY (optional)
if (responseData->resp_cond_state())
{
const IMAPParser::resp_text_code* code =
responseData->resp_cond_state()->resp_text()->resp_text_code();
if (code != NULL)
{
switch (code->type())
{
case IMAPParser::resp_text_code::UIDVALIDITY:
m_uidValidity = static_cast <unsigned int>(code->nz_number()->value());
break;
default:
break;
}
}
}
// Untagged responses: FLAGS, EXISTS, RECENT (required)
else if (responseData->mailbox_data())
{
switch (responseData->mailbox_data()->type())
{
default: break;
case IMAPParser::mailbox_data::FLAGS:
{
m_type = IMAPUtils::folderTypeFromFlags
(responseData->mailbox_data()->mailbox_flag_list());
m_flags = IMAPUtils::folderFlagsFromFlags
(responseData->mailbox_data()->mailbox_flag_list());
break;
}
case IMAPParser::mailbox_data::EXISTS:
{
m_messageCount = responseData->mailbox_data()->number()->value();
break;
}
case IMAPParser::mailbox_data::RECENT:
{
// TODO
break;
}
}
}
}
// Check for access mode (read-only or read-write)
const IMAPParser::resp_text_code* respTextCode = resp->response_done()->
response_tagged()->resp_cond_state()->resp_text()->resp_text_code();
if (respTextCode)
{
const int openMode =
(respTextCode->type() == IMAPParser::resp_text_code::READ_WRITE)
? MODE_READ_WRITE : MODE_READ_ONLY;
if (failIfModeIsNotAvailable &&
mode == MODE_READ_WRITE && openMode == MODE_READ_ONLY)
{
throw exceptions::operation_not_supported();
}
}
m_connection = connection;
m_open = true;
m_mode = mode;
}
catch (std::exception&)
{
throw;
}
}
void IMAPFolder::close(const bool expunge)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
ref <IMAPConnection> oldConnection = m_connection;
// Emit the "CLOSE" command to expunge messages marked
// as deleted (this is fastest than "EXPUNGE")
if (expunge)
{
if (m_mode == MODE_READ_ONLY)
throw exceptions::operation_not_supported();
oldConnection->send(true, "CLOSE", true);
}
// Close this folder connection
oldConnection->disconnect();
// Now use default store connection
m_connection = m_store.acquire()->connection();
m_open = false;
m_mode = -1;
m_uidValidity = 0;
onClose();
}
void IMAPFolder::onClose()
{
for (std::vector <IMAPMessage*>::iterator it = m_messages.begin() ;
it != m_messages.end() ; ++it)
{
(*it)->onFolderClosed();
}
m_messages.clear();
}
void IMAPFolder::create(const int type)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (isOpen())
throw exceptions::illegal_state("Folder is open");
else if (exists())
throw exceptions::illegal_state("Folder already exists");
else if (!store->isValidFolderName(m_name))
throw exceptions::invalid_folder_name();
// Emit the "CREATE" command
//
// Example: C: A003 CREATE owatagusiam/
// S: A003 OK CREATE completed
// C: A004 CREATE owatagusiam/blurdybloop
// S: A004 OK CREATE completed
string mailbox = IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath());
if (type & TYPE_CONTAINS_FOLDERS)
mailbox += m_connection->hierarchySeparator();
std::ostringstream oss;
oss << "CREATE " << IMAPUtils::quoteString(mailbox);
m_connection->send(true, oss.str(), true);
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("CREATE",
m_connection->getParser()->lastLine(), "bad response");
}
// Notify folder created
events::folderEvent event
(thisRef().dynamicCast <folder>(),
events::folderEvent::TYPE_CREATED, m_path, m_path);
notifyFolder(event);
}
void IMAPFolder::destroy()
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
if (isOpen())
throw exceptions::illegal_state("Folder is open");
const string mailbox = IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath());
std::ostringstream oss;
oss << "DELETE " << IMAPUtils::quoteString(mailbox);
m_connection->send(true, oss.str(), true);
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("DELETE",
m_connection->getParser()->lastLine(), "bad response");
}
// Notify folder deleted
events::folderEvent event
(thisRef().dynamicCast <folder>(),
events::folderEvent::TYPE_DELETED, m_path, m_path);
notifyFolder(event);
}
bool IMAPFolder::exists()
{
ref <IMAPStore> store = m_store.acquire();
if (!isOpen() && !store)
throw exceptions::illegal_state("Store disconnected");
return (testExistAndGetType() != TYPE_UNDEFINED);
}
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...
//
// Eg. Test whether '/foo/bar' exists
//
// C: a005 list "" foo/bar
// S: * LIST (\NoSelect) "/" foo/bar
// S: a005 OK LIST completed
//
// ==> OK, exists
//
// Test whether '/foo/bar/zap' exists
//
// C: a005 list "" foo/bar/zap
// S: a005 OK LIST completed
//
// ==> NO, does not exist
std::ostringstream oss;
oss << "LIST \"\" ";
oss << IMAPUtils::quoteString(IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath()));
m_connection->send(true, oss.str(), true);
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("LIST",
m_connection->getParser()->lastLine(), "bad response");
}
// Check whether the result mailbox list contains this folder
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("LIST",
m_connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::mailbox_data* mailboxData =
(*it)->response_data()->mailbox_data();
// We are only interested in responses of type "LIST"
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
(mailboxData->mailbox_list()->mailbox_flag_list());
}
}
return (m_type);
}
bool IMAPFolder::isOpen() const
{
return (m_open);
}
ref <message> IMAPFolder::getMessage(const int num)
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
if (num < 1 || num > m_messageCount)
throw exceptions::message_not_found();
return vmime::create <IMAPMessage>(thisRef().dynamicCast <IMAPFolder>(), num);
}
std::vector <ref <message> > IMAPFolder::getMessages(const int from, const int to)
{
const int messageCount = getMessageCount();
const int to2 = (to == -1 ? messageCount : to);
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (to2 < from || from < 1 || to2 < 1 || from > messageCount || to2 > messageCount)
throw exceptions::message_not_found();
std::vector <ref <message> > v;
ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
for (int i = from ; i <= to2 ; ++i)
v.push_back(vmime::create <IMAPMessage>(thisFolder, i));
return (v);
}
std::vector <ref <message> > IMAPFolder::getMessages(const std::vector <int>& nums)
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
std::vector <ref <message> > v;
ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it)
v.push_back(vmime::create <IMAPMessage>(thisFolder, *it));
return (v);
}
ref <message> IMAPFolder::getMessageByUID(const message::uid& uid)
{
std::vector <message::uid> uids;
uids.push_back(uid);
std::vector <ref <message> > msgs = getMessagesByUID(uids);
if (msgs.size() == 0)
throw exceptions::message_not_found();
return msgs[0];
}
std::vector <ref <message> > IMAPFolder::getMessagesByUID(const std::vector <message::uid>& uids)
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
if (uids.size() == 0)
return std::vector <ref <message> >();
// C: . UID FETCH uuuu1,uuuu2,uuuu3 UID
// S: * nnnn1 FETCH (UID uuuu1)
// S: * nnnn2 FETCH (UID uuuu2)
// S: * nnnn3 FETCH (UID uuuu3)
// S: . OK UID FETCH completed
// Prepare command and arguments
std::ostringstream cmd;
cmd.imbue(std::locale::classic());
cmd << "UID FETCH " << IMAPUtils::extractUIDFromGlobalUID(uids[0]);
for (std::vector <message::uid>::size_type i = 1, n = uids.size() ; i < n ; ++i)
cmd << "," << IMAPUtils::extractUIDFromGlobalUID(uids[i]);
cmd << " UID";
// Send the request
m_connection->send(true, cmd.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("UID FETCH ... UID", m_connection->getParser()->lastLine(), "bad response");
}
// Process the response
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
std::vector <ref <message> > messages;
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("UID FETCH ... UID",
m_connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::message_data* messageData =
(*it)->response_data()->message_data();
// We are only interested in responses of type "FETCH"
if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH)
continue;
// Get Process fetch response for this message
const int msgNum = static_cast <int>(messageData->number());
message::uid msgUID, msgFullUID;
// Find UID in message attributes
const std::vector <IMAPParser::msg_att_item*> atts = messageData->msg_att()->items();
for (std::vector <IMAPParser::msg_att_item*>::const_iterator
it = atts.begin() ; it != atts.end() ; ++it)
{
if ((*it)->type() == IMAPParser::msg_att_item::UID)
{
msgFullUID = IMAPUtils::makeGlobalUID(m_uidValidity, (*it)->unique_id()->value());
msgUID = (*it)->unique_id()->value();
break;
}
}
if (!msgUID.empty())
{
ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
messages.push_back(vmime::create <IMAPMessage>(thisFolder, msgNum, msgFullUID));
}
}
return messages;
}
int IMAPFolder::getMessageCount()
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
return (m_messageCount);
}
ref <folder> IMAPFolder::getFolder(const folder::path::component& name)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
return vmime::create <IMAPFolder>(m_path / name, store);
}
std::vector <ref <folder> > IMAPFolder::getFolders(const bool recursive)
{
ref <IMAPStore> store = m_store.acquire();
if (!isOpen() && !store)
throw exceptions::illegal_state("Store disconnected");
// Eg. List folders in '/foo/bar'
//
// C: a005 list "foo/bar" *
// S: * LIST (\NoSelect) "/" foo/bar
// S: * LIST (\NoInferiors) "/" foo/bar/zap
// S: a005 OK LIST completed
std::ostringstream oss;
oss << "LIST ";
const string pathString = IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath());
if (recursive)
{
oss << IMAPUtils::quoteString(pathString);
oss << " *";
}
else
{
if (pathString.empty()) // don't add sep for root folder
oss << "\"\"";
else
oss << IMAPUtils::quoteString(pathString + m_connection->hierarchySeparator());
oss << " %";
}
m_connection->send(true, oss.str(), true);
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("LIST", m_connection->getParser()->lastLine(), "bad response");
}
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
std::vector <ref <folder> > v;
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("LIST",
m_connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::mailbox_data* mailboxData =
(*it)->response_data()->mailbox_data();
if (mailboxData == NULL || mailboxData->type() != IMAPParser::mailbox_data::LIST)
continue;
// Get folder path
const class IMAPParser::mailbox* mailbox =
mailboxData->mailbox_list()->mailbox();
folder::path path = IMAPUtils::stringToPath
(mailboxData->mailbox_list()->quoted_char(), mailbox->name());
if (recursive || m_path.isDirectParentOf(path))
{
// Append folder to list
const class IMAPParser::mailbox_flag_list* mailbox_flag_list =
mailboxData->mailbox_list()->mailbox_flag_list();
v.push_back(vmime::create <IMAPFolder>(path, store,
IMAPUtils::folderTypeFromFlags(mailbox_flag_list),
IMAPUtils::folderFlagsFromFlags(mailbox_flag_list)));
}
}
return (v);
}
void IMAPFolder::fetchMessages(std::vector <ref <message> >& msg, const int options,
utility::progressListener* progress)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
// Build message numbers list
std::vector <int> list;
list.reserve(msg.size());
std::map <int, ref <IMAPMessage> > numberToMsg;
for (std::vector <ref <message> >::iterator it = msg.begin() ; it != msg.end() ; ++it)
{
list.push_back((*it)->getNumber());
numberToMsg[(*it)->getNumber()] = (*it).dynamicCast <IMAPMessage>();
}
// Send the request
const string command = IMAPUtils::buildFetchRequest(list, options);
m_connection->send(true, command, true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("FETCH",
m_connection->getParser()->lastLine(), "bad response");
}
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
const int total = msg.size();
int current = 0;
if (progress)
progress->start(total);
try
{
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("FETCH",
m_connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::message_data* messageData =
(*it)->response_data()->message_data();
// We are only interested in responses of type "FETCH"
if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH)
continue;
// Process fetch response for this message
const int num = static_cast <int>(messageData->number());
std::map <int, ref <IMAPMessage> >::iterator msg = numberToMsg.find(num);
if (msg != numberToMsg.end())
{
(*msg).second->processFetchResponse(options, messageData);
if (progress)
progress->progress(++current, total);
}
}
}
catch (...)
{
if (progress)
progress->stop(total);
throw;
}
if (progress)
progress->stop(total);
}
void IMAPFolder::fetchMessage(ref <message> msg, const int options)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
msg.dynamicCast <IMAPMessage>()->fetch(thisRef().dynamicCast <IMAPFolder>(), options);
}
int IMAPFolder::getFetchCapabilities() const
{
return (FETCH_ENVELOPE | FETCH_CONTENT_INFO | FETCH_STRUCTURE |
FETCH_FLAGS | FETCH_SIZE | FETCH_FULL_HEADER | FETCH_UID |
FETCH_IMPORTANCE);
}
ref <folder> IMAPFolder::getParent()
{
if (m_path.isEmpty())
return NULL;
else
return vmime::create <IMAPFolder>(m_path.getParent(), m_store.acquire());
}
ref <const store> IMAPFolder::getStore() const
{
return m_store.acquire();
}
ref <store> IMAPFolder::getStore()
{
return m_store.acquire();
}
void IMAPFolder::registerMessage(IMAPMessage* msg)
{
m_messages.push_back(msg);
}
void IMAPFolder::unregisterMessage(IMAPMessage* msg)
{
std::vector <IMAPMessage*>::iterator it =
std::find(m_messages.begin(), m_messages.end(), msg);
if (it != m_messages.end())
m_messages.erase(it);
}
void IMAPFolder::onStoreDisconnected()
{
m_store = NULL;
}
void IMAPFolder::deleteMessage(const int num)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
command << "STORE " << num << " +FLAGS.SILENT (\\Deleted)";
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("STORE",
m_connection->getParser()->lastLine(), "bad response");
}
// Update local flags
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if ((*it)->getNumber() == num &&
(*it)->m_flags != message::FLAG_UNDEFINED)
{
(*it)->m_flags |= message::FLAG_DELETED;
}
}
// Notify message flags changed
std::vector <int> nums;
nums.push_back(num);
events::messageChangedEvent event
(thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, nums);
notifyMessageChanged(event);
}
void IMAPFolder::deleteMessages(const int from, const int to)
{
ref <IMAPStore> store = m_store.acquire();
if (from < 1 || (to < from && to != -1))
throw exceptions::invalid_argument();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
command << "STORE " << from << ":";
if (to == -1) command << m_messageCount;
else command << to;
command << " +FLAGS.SILENT (\\Deleted)";
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("STORE",
m_connection->getParser()->lastLine(), "bad response");
}
// Update local flags
const int to2 = (to == -1) ? m_messageCount : to;
const int count = to - from + 1;
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 &&
(*it)->m_flags != message::FLAG_UNDEFINED)
{
(*it)->m_flags |= message::FLAG_DELETED;
}
}
// Notify message flags changed
std::vector <int> nums;
nums.resize(count);
for (int i = from, j = 0 ; i <= to2 ; ++i, ++j)
nums[j] = i;
events::messageChangedEvent event
(thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, nums);
notifyMessageChanged(event);
}
void IMAPFolder::deleteMessages(const std::vector <int>& nums)
{
ref <IMAPStore> store = m_store.acquire();
if (nums.empty())
throw exceptions::invalid_argument();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
// Sort the list of message numbers
std::vector <int> list;
list.resize(nums.size());
std::copy(nums.begin(), nums.end(), list.begin());
std::sort(list.begin(), list.end());
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
command << "STORE ";
command << IMAPUtils::listToSet(list, m_messageCount, true);
command << " +FLAGS.SILENT (\\Deleted)";
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("STORE",
m_connection->getParser()->lastLine(), "bad response");
}
// Update local flags
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if (std::binary_search(list.begin(), list.end(), (*it)->getNumber()))
{
if ((*it)->m_flags != message::FLAG_UNDEFINED)
(*it)->m_flags |= message::FLAG_DELETED;
}
}
// Notify message flags changed
events::messageChangedEvent event
(thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, list);
notifyMessageChanged(event);
}
void IMAPFolder::setMessageFlags(const int from, const int to, const int flags, const int mode)
{
ref <IMAPStore> store = m_store.acquire();
if (from < 1 || (to < from && to != -1))
throw exceptions::invalid_argument();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
std::ostringstream oss;
oss.imbue(std::locale::classic());
if (to == -1)
oss << from << ":*";
else
oss << from << ":" << to;
setMessageFlags(oss.str(), flags, mode);
// Update local flags
const int to2 = (to == -1) ? m_messageCount : to;
const int count = to - from + 1;
switch (mode)
{
case message::FLAG_MODE_ADD:
{
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 &&
(*it)->m_flags != message::FLAG_UNDEFINED)
{
(*it)->m_flags |= flags;
}
}
break;
}
case message::FLAG_MODE_REMOVE:
{
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 &&
(*it)->m_flags != message::FLAG_UNDEFINED)
{
(*it)->m_flags &= ~flags;
}
}
break;
}
default:
case message::FLAG_MODE_SET:
{
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 &&
(*it)->m_flags != message::FLAG_UNDEFINED)
{
(*it)->m_flags = flags;
}
}
break;
}
}
// Notify message flags changed
std::vector <int> nums;
nums.resize(count);
for (int i = from, j = 0 ; i <= to2 ; ++i, ++j)
nums[j] = i;
events::messageChangedEvent event
(thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, nums);
notifyMessageChanged(event);
}
void IMAPFolder::setMessageFlags(const std::vector <int>& nums, const int flags, const int mode)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
// Sort the list of message numbers
std::vector <int> list;
list.resize(nums.size());
std::copy(nums.begin(), nums.end(), list.begin());
std::sort(list.begin(), list.end());
// Delegates call
setMessageFlags(IMAPUtils::listToSet(list, m_messageCount, true), flags, mode);
// Update local flags
switch (mode)
{
case message::FLAG_MODE_ADD:
{
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if (std::binary_search(list.begin(), list.end(), (*it)->getNumber()) &&
(*it)->m_flags != message::FLAG_UNDEFINED)
{
(*it)->m_flags |= flags;
}
}
break;
}
case message::FLAG_MODE_REMOVE:
{
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if (std::binary_search(list.begin(), list.end(), (*it)->getNumber()) &&
(*it)->m_flags != message::FLAG_UNDEFINED)
{
(*it)->m_flags &= ~flags;
}
}
break;
}
default:
case message::FLAG_MODE_SET:
{
for (std::vector <IMAPMessage*>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
if (std::binary_search(list.begin(), list.end(), (*it)->getNumber()) &&
(*it)->m_flags != message::FLAG_UNDEFINED)
{
(*it)->m_flags = flags;
}
}
break;
}
}
// Notify message flags changed
events::messageChangedEvent event
(thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, nums);
notifyMessageChanged(event);
}
void IMAPFolder::setMessageFlags(const string& set, const int flags, const int mode)
{
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
command << "STORE " << set;
switch (mode)
{
case message::FLAG_MODE_ADD: command << " +FLAGS.SILENT "; break;
case message::FLAG_MODE_REMOVE: command << " -FLAGS.SILENT "; break;
default:
case message::FLAG_MODE_SET: command << " FLAGS.SILENT "; break;
}
const string flagList = IMAPUtils::messageFlagList(flags);
if (!flagList.empty())
{
command << flagList;
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("STORE",
m_connection->getParser()->lastLine(), "bad response");
}
}
}
void IMAPFolder::addMessage(ref <vmime::message> msg, const int flags,
vmime::datetime* date, utility::progressListener* progress)
{
std::ostringstream oss;
utility::outputStreamAdapter ossAdapter(oss);
msg->generate(ossAdapter);
const std::string& str = oss.str();
utility::inputStreamStringAdapter strAdapter(str);
addMessage(strAdapter, str.length(), flags, date, progress);
}
void IMAPFolder::addMessage(utility::inputStream& is, const int size, const int flags,
vmime::datetime* date, utility::progressListener* progress)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
command << "APPEND " << IMAPUtils::quoteString(IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath())) << ' ';
const string flagList = IMAPUtils::messageFlagList(flags);
if (flags != message::FLAG_UNDEFINED && !flagList.empty())
{
command << flagList;
command << ' ';
}
if (date != NULL)
{
command << IMAPUtils::dateTime(*date);
command << ' ';
}
command << '{' << size << '}';
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
bool ok = false;
const std::vector <IMAPParser::continue_req_or_response_data*>& respList
= resp->continue_req_or_response_data();
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respList.begin() ; !ok && (it != respList.end()) ; ++it)
{
if ((*it)->continue_req())
ok = true;
}
if (!ok)
{
throw exceptions::command_error("APPEND",
m_connection->getParser()->lastLine(), "bad response");
}
// Send message data
const int total = size;
int current = 0;
if (progress)
progress->start(total);
const socket::size_type blockSize = std::min(is.getBlockSize(),
static_cast <size_t>(m_connection->getSocket()->getBlockSize()));
std::vector <char> vbuffer(blockSize);
char* buffer = &vbuffer.front();
while (!is.eof())
{
// Read some data from the input stream
const int read = is.read(buffer, sizeof(buffer));
current += read;
// Put read data into socket output stream
m_connection->sendRaw(buffer, read);
// Notify progress
if (progress)
progress->progress(current, total);
}
m_connection->send(false, "", true);
if (progress)
progress->stop(total);
// Get the response
utility::auto_ptr <IMAPParser::response> finalResp(m_connection->readResponse());
if (finalResp->isBad() || finalResp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("APPEND",
m_connection->getParser()->lastLine(), "bad response");
}
// Notify message added
std::vector <int> nums;
nums.push_back(m_messageCount + 1);
events::messageCountEvent event
(thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
m_messageCount++;
notifyMessageCount(event);
// Notify folders with the same path
for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
it != store->m_folders.end() ; ++it)
{
if ((*it) != this && (*it)->getFullPath() == m_path)
{
events::messageCountEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
(*it)->m_messageCount++;
(*it)->notifyMessageCount(event);
}
}
}
void IMAPFolder::expunge()
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
// Send the request
m_connection->send(true, "EXPUNGE", true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("EXPUNGE",
m_connection->getParser()->lastLine(), "bad response");
}
// Update the numbering of the messages
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
std::vector <int> nums;
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("EXPUNGE",
m_connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::message_data* messageData =
(*it)->response_data()->message_data();
// We are only interested in responses of type "EXPUNGE"
if (messageData == NULL ||
messageData->type() != IMAPParser::message_data::EXPUNGE)
{
continue;
}
const int number = messageData->number();
nums.push_back(number);
for (std::vector <IMAPMessage*>::iterator jt =
m_messages.begin() ; jt != m_messages.end() ; ++jt)
{
if ((*jt)->m_num == number)
(*jt)->m_expunged = true;
else if ((*jt)->m_num > number)
(*jt)->m_num--;
}
}
m_messageCount -= nums.size();
// Notify message expunged
events::messageCountEvent event
(thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_REMOVED, nums);
notifyMessageCount(event);
// Notify folders with the same path
for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
it != store->m_folders.end() ; ++it)
{
if ((*it) != this && (*it)->getFullPath() == m_path)
{
(*it)->m_messageCount = m_messageCount;
events::messageCountEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_REMOVED, nums);
(*it)->notifyMessageCount(event);
}
}
}
void IMAPFolder::rename(const folder::path& newPath)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (m_path.isEmpty() || newPath.isEmpty())
throw exceptions::illegal_operation("Cannot rename root folder");
else if (m_path.getSize() == 1 && m_name.getBuffer() == "INBOX")
throw exceptions::illegal_operation("Cannot rename 'INBOX' folder");
else if (!store->isValidFolderName(newPath.getLastComponent()))
throw exceptions::invalid_folder_name();
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
command << "RENAME ";
command << IMAPUtils::quoteString(IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath())) << " ";
command << IMAPUtils::quoteString(IMAPUtils::pathToString
(m_connection->hierarchySeparator(), newPath));
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("RENAME",
m_connection->getParser()->lastLine(), "bad response");
}
// Notify folder renamed
folder::path oldPath(m_path);
m_path = newPath;
m_name = newPath.getLastComponent();
events::folderEvent event
(thisRef().dynamicCast <folder>(),
events::folderEvent::TYPE_RENAMED, oldPath, newPath);
notifyFolder(event);
// Notify folders with the same path and sub-folders
for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
it != store->m_folders.end() ; ++it)
{
if ((*it) != this && (*it)->getFullPath() == oldPath)
{
(*it)->m_path = newPath;
(*it)->m_name = newPath.getLastComponent();
events::folderEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::folderEvent::TYPE_RENAMED, oldPath, newPath);
(*it)->notifyFolder(event);
}
else if ((*it) != this && oldPath.isParentOf((*it)->getFullPath()))
{
folder::path oldPath((*it)->m_path);
(*it)->m_path.renameParent(oldPath, newPath);
events::folderEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::folderEvent::TYPE_RENAMED, oldPath, (*it)->m_path);
(*it)->notifyFolder(event);
}
}
}
void IMAPFolder::copyMessage(const folder::path& dest, const int num)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
// Construct set
std::ostringstream set;
set.imbue(std::locale::classic());
set << num;
// Delegate message copy
copyMessages(set.str(), dest);
// Notify message count changed
std::vector <int> nums;
nums.push_back(num);
for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
it != store->m_folders.end() ; ++it)
{
if ((*it)->getFullPath() == dest)
{
events::messageCountEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
(*it)->m_messageCount++;
(*it)->notifyMessageCount(event);
}
}
}
void IMAPFolder::copyMessages(const folder::path& dest, const int from, const int to)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (from < 1 || (to < from && to != -1))
throw exceptions::invalid_argument();
// Construct set
std::ostringstream set;
set.imbue(std::locale::classic());
if (to == -1)
set << from << ":*";
else
set << from << ":" << to;
// Delegate message copy
copyMessages(set.str(), dest);
// Notify message count changed
const int to2 = (to == -1) ? m_messageCount : to;
const int count = to - from + 1;
std::vector <int> nums;
nums.resize(count);
for (int i = from, j = 0 ; i <= to2 ; ++i, ++j)
nums[j] = i;
for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
it != store->m_folders.end() ; ++it)
{
if ((*it)->getFullPath() == dest)
{
events::messageCountEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
(*it)->m_messageCount += count;
(*it)->notifyMessageCount(event);
}
}
}
void IMAPFolder::copyMessages(const folder::path& dest, const std::vector <int>& nums)
{
ref <IMAPStore> store = m_store.acquire();
if (!store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
// Delegate message copy
copyMessages(IMAPUtils::listToSet(nums, m_messageCount), dest);
// Notify message count changed
const int count = nums.size();
for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
it != store->m_folders.end() ; ++it)
{
if ((*it)->getFullPath() == dest)
{
events::messageCountEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
(*it)->m_messageCount += count;
(*it)->notifyMessageCount(event);
}
}
}
void IMAPFolder::copyMessages(const string& set, const folder::path& dest)
{
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
command << "COPY " << set << " ";
command << IMAPUtils::quoteString(IMAPUtils::pathToString
(m_connection->hierarchySeparator(), dest));
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("COPY",
m_connection->getParser()->lastLine(), "bad response");
}
}
void IMAPFolder::status(int& count, int& unseen)
{
ref <IMAPStore> store = m_store.acquire();
count = 0;
unseen = 0;
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
command << "STATUS ";
command << IMAPUtils::quoteString(IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath()));
command << " (MESSAGES UNSEEN)";
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("STATUS",
m_connection->getParser()->lastLine(), "bad response");
}
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("STATUS",
m_connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::response_data* responseData = (*it)->response_data();
if (responseData->mailbox_data() &&
responseData->mailbox_data()->type() == IMAPParser::mailbox_data::STATUS)
{
const std::vector <IMAPParser::status_info*>& statusList =
responseData->mailbox_data()->status_info_list();
for (std::vector <IMAPParser::status_info*>::const_iterator
jt = statusList.begin() ; jt != statusList.end() ; ++jt)
{
switch ((*jt)->status_att()->type())
{
case IMAPParser::status_att::MESSAGES:
count = (*jt)->number()->value();
break;
case IMAPParser::status_att::UNSEEN:
unseen = (*jt)->number()->value();
break;
default:
break;
}
}
}
}
// Notify message count changed (new messages)
if (m_messageCount != count)
{
const int oldCount = m_messageCount;
m_messageCount = count;
if (count > oldCount)
{
std::vector <int> nums;
nums.reserve(count - oldCount);
for (int i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j)
nums[j] = i;
events::messageCountEvent event
(thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
notifyMessageCount(event);
// Notify folders with the same path
for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
it != store->m_folders.end() ; ++it)
{
if ((*it) != this && (*it)->getFullPath() == m_path)
{
(*it)->m_messageCount = count;
events::messageCountEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
(*it)->notifyMessageCount(event);
}
}
}
}
}
std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid)
{
std::vector<int> v;
std::ostringstream command;
command.imbue(std::locale::classic());
command << "SEARCH UID " << uid << ":*";
// Send the request
m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() ||
resp->response_done()->response_tagged()->resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("SEARCH",
m_connection->getParser()->lastLine(), "bad response");
}
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = resp->continue_req_or_response_data();
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("SEARCH",
m_connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::mailbox_data* mailboxData =
(*it)->response_data()->mailbox_data();
// We are only interested in responses of type "SEARCH"
if (mailboxData == NULL ||
mailboxData->type() != IMAPParser::mailbox_data::SEARCH)
{
continue;
}
for (std::vector <IMAPParser::nz_number*>::const_iterator
it = mailboxData->search_nz_number_list().begin() ;
it != mailboxData->search_nz_number_list().end();
++it)
{
v.push_back((*it)->value());
}
}
return v;
}
} // imap
} // net
} // vmime
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP