diff options
Diffstat (limited to 'src/messaging/IMAPFolder.cpp')
-rw-r--r-- | src/messaging/IMAPFolder.cpp | 1559 |
1 files changed, 0 insertions, 1559 deletions
diff --git a/src/messaging/IMAPFolder.cpp b/src/messaging/IMAPFolder.cpp deleted file mode 100644 index 98737165..00000000 --- a/src/messaging/IMAPFolder.cpp +++ /dev/null @@ -1,1559 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2005 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 2 of -// the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// - -#include "vmime/messaging/IMAPFolder.hpp" - -#include "vmime/messaging/IMAPStore.hpp" -#include "vmime/messaging/IMAPParser.hpp" -#include "vmime/messaging/IMAPMessage.hpp" -#include "vmime/messaging/IMAPUtils.hpp" -#include "vmime/messaging/IMAPConnection.hpp" - -#include "vmime/message.hpp" - -#include "vmime/exception.hpp" -#include "vmime/utility/smartPtr.hpp" - -#include <algorithm> -#include <sstream> - - -namespace vmime { -namespace messaging { - - -IMAPFolder::IMAPFolder(const folder::path& path, IMAPStore* store, const int type, const int flags) - : m_store(store), m_connection(m_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) -{ - m_store->registerFolder(this); -} - - -IMAPFolder::~IMAPFolder() -{ - if (m_store) - { - if (m_open) - close(false); - - m_store->unregisterFolder(this); - } - else if (m_open) - { - delete (m_connection); - onClose(); - } -} - - -const int IMAPFolder::getMode() const -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - return (m_mode); -} - - -const 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); - } -} - - -const 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) -{ - if (!m_store) - throw exceptions::illegal_state("Store disconnected"); - - // Open a connection for this folder - IMAPConnection* connection = - new IMAPConnection(m_store, m_store->oneTimeAuthenticator()); - - 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 = 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&) - { - delete (connection); - throw; - } -} - - -void IMAPFolder::close(const bool expunge) -{ - if (!m_store) - throw exceptions::illegal_state("Store disconnected"); - - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - 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->connection(); - - m_open = false; - m_mode = -1; - - m_uidValidity = 0; - - onClose(); - - delete (oldConnection); -} - - -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) -{ - if (!m_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 (!m_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(this, events::folderEvent::TYPE_CREATED, m_path, m_path); - notifyFolder(event); -} - - -const bool IMAPFolder::exists() -{ - if (!isOpen() && !m_store) - throw exceptions::illegal_state("Store disconnected"); - - return (testExistAndGetType() != TYPE_UNDEFINED); -} - - -const 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); -} - - -const bool IMAPFolder::isOpen() const -{ - return (m_open); -} - - -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 new IMAPMessage(this, num); -} - - -std::vector <message*> IMAPFolder::getMessages(const int from, const int to) -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - std::vector <message*> v; - - for (int i = from ; i <= to ; ++i) - v.push_back(new IMAPMessage(this, i)); - - return (v); -} - - -std::vector <message*> IMAPFolder::getMessages(const std::vector <int>& nums) -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - std::vector <message*> v; - - for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it) - v.push_back(new IMAPMessage(this, *it)); - - return (v); -} - - -const int IMAPFolder::getMessageCount() -{ - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - return (m_messageCount); -} - - -folder* IMAPFolder::getFolder(const folder::path::component& name) -{ - if (!m_store) - throw exceptions::illegal_state("Store disconnected"); - - return new IMAPFolder(m_path / name, m_store); -} - - -std::vector <folder*> IMAPFolder::getFolders(const bool recursive) -{ - if (!isOpen() && !m_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 "; - oss << IMAPUtils::quoteString - (IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath())); - - if (recursive) - oss << " *"; - else - 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 <folder*> v; - - 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("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(new IMAPFolder(path, m_store, - IMAPUtils::folderTypeFromFlags(mailbox_flag_list), - IMAPUtils::folderFlagsFromFlags(mailbox_flag_list))); - } - } - } - catch (std::exception&) - { - for (std::vector <folder*>::iterator it = v.begin() ; it != v.end() ; ++it) - delete (*it); - - throw; - } - - return (v); -} - - -void IMAPFolder::fetchMessages(std::vector <message*>& msg, const int options, - progressionListener* progress) -{ - if (!m_store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - const int total = msg.size(); - int current = 0; - - if (progress) - progress->start(total); - - for (std::vector <message*>::iterator it = msg.begin() ; - it != msg.end() ; ++it) - { - dynamic_cast <IMAPMessage*>(*it)->fetch(this, options); - - if (progress) - progress->progress(++current, total); - } - - if (progress) - progress->stop(total); -} - - -void IMAPFolder::fetchMessage(message* msg, const int options) -{ - if (!m_store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - dynamic_cast <IMAPMessage*>(msg)->fetch(this, options); -} - - -const int IMAPFolder::getFetchCapabilities() const -{ - return (FETCH_ENVELOPE | FETCH_CONTENT_INFO | FETCH_STRUCTURE | - FETCH_FLAGS | FETCH_SIZE | FETCH_FULL_HEADER | FETCH_UID); -} - - -folder* IMAPFolder::getParent() -{ - return (m_path.isEmpty() ? NULL : new IMAPFolder(m_path.getParent(), m_store)); -} - - -const store* IMAPFolder::getStore() const -{ - return (m_store); -} - - -store* IMAPFolder::getStore() -{ - return (m_store); -} - - -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) -{ - if (!m_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 << "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(this, events::messageChangedEvent::TYPE_FLAGS, nums); - - notifyMessageChanged(event); -} - - -void IMAPFolder::deleteMessages(const int from, const int to) -{ - if (from < 1 || (to < from && to != -1)) - throw exceptions::invalid_argument(); - - if (!m_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 << "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(this, events::messageChangedEvent::TYPE_FLAGS, nums); - - notifyMessageChanged(event); -} - - -void IMAPFolder::deleteMessages(const std::vector <int>& nums) -{ - if (nums.empty()) - throw exceptions::invalid_argument(); - - if (!m_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 << "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(this, events::messageChangedEvent::TYPE_FLAGS, list); - - notifyMessageChanged(event); -} - - -void IMAPFolder::setMessageFlags(const int from, const int to, const int flags, const int mode) -{ - if (from < 1 || (to < from && to != -1)) - throw exceptions::invalid_argument(); - - if (!m_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; - - 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(this, events::messageChangedEvent::TYPE_FLAGS, nums); - - notifyMessageChanged(event); -} - - -void IMAPFolder::setMessageFlags(const std::vector <int>& nums, const int flags, const int mode) -{ - if (!m_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(this, 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 << "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(vmime::message* msg, const int flags, - vmime::datetime* date, progressionListener* 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, progressionListener* progress) -{ - if (!m_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 << "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); - - char buffer[65536]; - - 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 progression - 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(this, events::messageCountEvent::TYPE_ADDED, nums); - - m_messageCount++; - notifyMessageCount(event); - - // Notify folders with the same path - for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ; - it != m_store->m_folders.end() ; ++it) - { - if ((*it) != this && (*it)->getFullPath() == m_path) - { - events::messageCountEvent event(*it, events::messageCountEvent::TYPE_ADDED, nums); - - (*it)->m_messageCount++; - (*it)->notifyMessageCount(event); - } - } -} - - -void IMAPFolder::expunge() -{ - if (!m_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(this, events::messageCountEvent::TYPE_REMOVED, nums); - - notifyMessageCount(event); - - // Notify folders with the same path - for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ; - it != m_store->m_folders.end() ; ++it) - { - if ((*it) != this && (*it)->getFullPath() == m_path) - { - (*it)->m_messageCount = m_messageCount; - - events::messageCountEvent event(*it, events::messageCountEvent::TYPE_REMOVED, nums); - - (*it)->notifyMessageCount(event); - } - } -} - - -void IMAPFolder::rename(const folder::path& newPath) -{ - if (!m_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 (!m_store->isValidFolderName(newPath.getLastComponent())) - throw exceptions::invalid_folder_name(); - - // Build the request text - std::ostringstream command; - 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(this, events::folderEvent::TYPE_RENAMED, oldPath, newPath); - notifyFolder(event); - - // Notify folders with the same path and sub-folders - for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ; - it != m_store->m_folders.end() ; ++it) - { - if ((*it) != this && (*it)->getFullPath() == oldPath) - { - (*it)->m_path = newPath; - (*it)->m_name = newPath.getLastComponent(); - - events::folderEvent event(*it, 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, events::folderEvent::TYPE_RENAMED, oldPath, (*it)->m_path); - (*it)->notifyFolder(event); - } - } -} - - -void IMAPFolder::copyMessage(const folder::path& dest, const int num) -{ - if (!m_store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - // Construct set - std::ostringstream set; - set << num; - - // Delegate message copy - copyMessages(set.str(), dest); - - // Notify message count changed - std::vector <int> nums; - nums.push_back(num); - - events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums); - - for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ; - it != m_store->m_folders.end() ; ++it) - { - if ((*it)->getFullPath() == dest) - { - (*it)->m_messageCount++; - (*it)->notifyMessageCount(event); - } - } -} - - -void IMAPFolder::copyMessages(const folder::path& dest, const int from, const int to) -{ - if (!m_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; - - 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; - - events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums); - - for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ; - it != m_store->m_folders.end() ; ++it) - { - if ((*it)->getFullPath() == dest) - { - (*it)->m_messageCount += count; - (*it)->notifyMessageCount(event); - } - } -} - - -void IMAPFolder::copyMessages(const folder::path& dest, const std::vector <int>& nums) -{ - if (!m_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(); - - events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums); - - for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ; - it != m_store->m_folders.end() ; ++it) - { - if ((*it)->getFullPath() == dest) - { - (*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 << "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) -{ - count = 0; - unseen = 0; - - // Build the request text - std::ostringstream command; - command << "STATUS "; - command << IMAPUtils::quoteString(IMAPUtils::pathToString - (m_connection->hierarchySeparator(), getFullPath())); - command << "(MESSAGES UNSEEN)"; - - // Send the request - m_store->m_connection->send(true, command.str(), true); - - // Get the response - utility::auto_ptr <IMAPParser::response> resp(m_store->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_store->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_store->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(this, events::messageCountEvent::TYPE_ADDED, nums); - - notifyMessageCount(event); - - // Notify folders with the same path - for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ; - it != m_store->m_folders.end() ; ++it) - { - if ((*it) != this && (*it)->getFullPath() == m_path) - { - (*it)->m_messageCount = count; - - events::messageCountEvent event(*it, events::messageCountEvent::TYPE_ADDED, nums); - - (*it)->notifyMessageCount(event); - } - } - } - } -} - - -} // messaging -} // vmime |