diff options
Diffstat (limited to 'vmime-master/src/vmime/net/pop3/POP3Folder.cpp')
-rw-r--r-- | vmime-master/src/vmime/net/pop3/POP3Folder.cpp | 822 |
1 files changed, 822 insertions, 0 deletions
diff --git a/vmime-master/src/vmime/net/pop3/POP3Folder.cpp b/vmime-master/src/vmime/net/pop3/POP3Folder.cpp new file mode 100644 index 0000000..b69a483 --- /dev/null +++ b/vmime-master/src/vmime/net/pop3/POP3Folder.cpp @@ -0,0 +1,822 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 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_POP3 + + +#include "vmime/net/pop3/POP3Folder.hpp" + +#include "vmime/net/pop3/POP3Store.hpp" +#include "vmime/net/pop3/POP3Message.hpp" +#include "vmime/net/pop3/POP3Command.hpp" +#include "vmime/net/pop3/POP3Response.hpp" +#include "vmime/net/pop3/POP3FolderStatus.hpp" + +#include "vmime/net/pop3/POP3Utils.hpp" + +#include "vmime/exception.hpp" + + +namespace vmime { +namespace net { +namespace pop3 { + + +POP3Folder::POP3Folder( + const folder::path& path, + const shared_ptr <POP3Store>& store +) + : m_store(store), + m_path(path), + m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()), + m_mode(-1), + m_open(false) { + + store->registerFolder(this); +} + + +POP3Folder::~POP3Folder() { + + try { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (store) { + + if (m_open) { + close(false); + } + + store->unregisterFolder(this); + + } else if (m_open) { + + onClose(); + } + + } catch (...) { + + // Don't throw in destructor + } +} + + +int POP3Folder::getMode() const { + + if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + return m_mode; +} + + +const folderAttributes POP3Folder::getAttributes() { + + folderAttributes attribs; + + if (m_path.isEmpty()) { + attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS); + } else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX") { + attribs.setType(folderAttributes::TYPE_CONTAINS_MESSAGES); + attribs.setSpecialUse(folderAttributes::SPECIALUSE_INBOX); + } else { + throw exceptions::folder_not_found(); + } + + attribs.setFlags(0); + + return attribs; +} + + +const folder::path::component POP3Folder::getName() const { + + return m_name; +} + + +const folder::path POP3Folder::getFullPath() const { + + return m_path; +} + + +void POP3Folder::open(const int mode, bool failIfModeIsNotAvailable) { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + if (m_path.isEmpty()) { + + if (mode != MODE_READ_ONLY && failIfModeIsNotAvailable) { + throw exceptions::operation_not_supported(); + } + + m_open = true; + m_mode = mode; + + m_messageCount = 0; + + } else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX") { + + POP3Command::STAT()->send(store->getConnection()); + + shared_ptr <POP3Response> response = POP3Response::readResponse(store->getConnection()); + + if (!response->isSuccess()) { + throw exceptions::command_error("STAT", response->getFirstLine()); + } + + std::istringstream iss(response->getText()); + iss.imbue(std::locale::classic()); + iss >> m_messageCount; + + if (iss.fail()) { + throw exceptions::invalid_response("STAT", response->getFirstLine()); + } + + m_open = true; + m_mode = mode; + + } else { + + throw exceptions::folder_not_found(); + } +} + + +void POP3Folder::close(const bool expunge) { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + if (!expunge) { + POP3Command::RSET()->send(store->getConnection()); + POP3Response::readResponse(store->getConnection()); + } + + m_open = false; + m_mode = -1; + + onClose(); +} + + +void POP3Folder::onClose() { + + for (MessageMap::iterator it = m_messages.begin() ; it != m_messages.end() ; ++it) { + (*it).first->onFolderClosed(); + } + + m_messages.clear(); +} + + +void POP3Folder::create(const folderAttributes& /* attribs */) { + + throw exceptions::operation_not_supported(); +} + + +void POP3Folder::destroy() { + + throw exceptions::operation_not_supported(); +} + + +bool POP3Folder::exists() { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + return m_path.isEmpty() || (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX"); +} + + +bool POP3Folder::isOpen() const { + + return m_open; +} + + +shared_ptr <message> POP3Folder::getMessage(const size_t num) { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } else if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } else if (num < 1 || num > m_messageCount) { + throw exceptions::message_not_found(); + } + + return make_shared <POP3Message>(dynamicCast <POP3Folder>(shared_from_this()), num); +} + + +std::vector <shared_ptr <message> > POP3Folder::getMessages(const messageSet& msgs) { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } else if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + if (msgs.isNumberSet()) { + + const std::vector <size_t> numbers = POP3Utils::messageSetToNumberList(msgs, m_messageCount); + + std::vector <shared_ptr <message> > messages; + shared_ptr <POP3Folder> thisFolder(dynamicCast <POP3Folder>(shared_from_this())); + + for (std::vector <size_t>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) { + + if (*it < 1|| *it > m_messageCount) { + throw exceptions::message_not_found(); + } + + messages.push_back(make_shared <POP3Message>(thisFolder, *it)); + } + + return messages; + + } else { + + throw exceptions::operation_not_supported(); + } +} + + +size_t POP3Folder::getMessageCount() { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } else if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + return m_messageCount; +} + + +shared_ptr <folder> POP3Folder::getFolder(const folder::path::component& name) { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + return shared_ptr <POP3Folder>(new POP3Folder(m_path / name, store)); +} + + +std::vector <shared_ptr <folder> > POP3Folder::getFolders(const bool /* recursive */) { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + if (m_path.isEmpty()) { + + std::vector <shared_ptr <folder> > v; + v.push_back(shared_ptr <POP3Folder>(new POP3Folder(folder::path::component("INBOX"), store))); + return v; + + } else { + + std::vector <shared_ptr <folder> > v; + return v; + } +} + + +void POP3Folder::fetchMessages( + std::vector <shared_ptr <message> >& msg, + const fetchAttributes& options, + utility::progressListener* progress +) { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } else if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + if (msg.empty()) { + return; + } + + const size_t total = msg.size(); + size_t current = 0; + + if (progress) { + progress->start(total); + } + + for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ; + it != msg.end() ; ++it) { + + dynamicCast <POP3Message>(*it)->fetch( + dynamicCast <POP3Folder>(shared_from_this()), + options + ); + + if (progress) { + progress->progress(++current, total); + } + } + + if (options.has(fetchAttributes::SIZE)) { + + // Send the "LIST" command + POP3Command::LIST()->send(store->getConnection()); + + // Get the response + shared_ptr <POP3Response> response = + POP3Response::readMultilineResponse(store->getConnection()); + + if (response->isSuccess()) { + + // C: LIST + // S: +OK + // S: 1 47548 + // S: 2 12653 + // S: . + std::map <size_t, string> result; + POP3Utils::parseMultiListOrUidlResponse(response, result); + + for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ; + it != msg.end() ; ++it) { + + shared_ptr <POP3Message> m = dynamicCast <POP3Message>(*it); + + std::map <size_t, string>::const_iterator x = result.find(m->m_num); + + if (x != result.end()) { + + size_t size = 0; + + std::istringstream iss((*x).second); + iss.imbue(std::locale::classic()); + iss >> size; + + m->m_size = size; + } + } + } + } + + if (options.has(fetchAttributes::UID)) { + + // Send the "UIDL" command + POP3Command::UIDL()->send(store->getConnection()); + + // Get the response + shared_ptr <POP3Response> response = + POP3Response::readMultilineResponse(store->getConnection()); + + if (response->isSuccess()) { + + // C: UIDL + // S: +OK + // S: 1 whqtswO00WBw418f9t5JxYwZ + // S: 2 QhdPYR:00WBw1Ph7x7 + // S: . + std::map <size_t, string> result; + POP3Utils::parseMultiListOrUidlResponse(response, result); + + for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ; + it != msg.end() ; ++it) { + + shared_ptr <POP3Message> m = dynamicCast <POP3Message>(*it); + + std::map <size_t, string>::const_iterator x = result.find(m->m_num); + + if (x != result.end()) { + m->m_uid = (*x).second; + } + } + } + } + + if (progress) { + progress->stop(total); + } +} + + +void POP3Folder::fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options) { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } else if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + dynamicCast <POP3Message>(msg)->fetch( + dynamicCast <POP3Folder>(shared_from_this()), + options + ); + + if (options.has(fetchAttributes::SIZE)) { + + // Send the "LIST" command + POP3Command::LIST(msg->getNumber())->send(store->getConnection()); + + // Get the response + shared_ptr <POP3Response> response = + POP3Response::readResponse(store->getConnection()); + + if (response->isSuccess()) { + + string responseText = response->getText(); + + // C: LIST 2 + // S: +OK 2 4242 + string::iterator it = responseText.begin(); + + while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it; + while (it != responseText.end() && !(*it == ' ' || *it == '\t')) ++it; + while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it; + + if (it != responseText.end()) { + + size_t size = 0; + + std::istringstream iss(string(it, responseText.end())); + iss.imbue(std::locale::classic()); + iss >> size; + + dynamicCast <POP3Message>(msg)->m_size = size; + } + } + } + + if (options.has(fetchAttributes::UID)) { + + // Send the "UIDL" command + POP3Command::UIDL(msg->getNumber())->send(store->getConnection()); + + // Get the response + shared_ptr <POP3Response> response = + POP3Response::readResponse(store->getConnection()); + + if (response->isSuccess()) { + + string responseText = response->getText(); + + // C: UIDL 2 + // S: +OK 2 QhdPYR:00WBw1Ph7x7 + string::iterator it = responseText.begin(); + + while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it; + while (it != responseText.end() && !(*it == ' ' || *it == '\t')) ++it; + while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it; + + if (it != responseText.end()) { + dynamicCast <POP3Message>(msg)->m_uid = string(it, responseText.end()); + } + } + } +} + + +std::vector <shared_ptr <message> > POP3Folder::getAndFetchMessages( + const messageSet& msgs, + const fetchAttributes& attribs +) { + + if (msgs.isEmpty()) { + return std::vector <shared_ptr <message> >(); + } + + std::vector <shared_ptr <message> > messages = getMessages(msgs); + fetchMessages(messages, attribs); + + return messages; +} + + +int POP3Folder::getFetchCapabilities() const { + + return fetchAttributes::ENVELOPE | + fetchAttributes::CONTENT_INFO | + fetchAttributes::SIZE | + fetchAttributes::FULL_HEADER | + fetchAttributes::UID | + fetchAttributes::IMPORTANCE; +} + + +shared_ptr <folder> POP3Folder::getParent() { + + if (m_path.isEmpty()) { + return null; + } else { + return shared_ptr <POP3Folder>(new POP3Folder(m_path.getParent(), m_store.lock())); + } +} + + +shared_ptr <const store> POP3Folder::getStore() const { + + return m_store.lock(); +} + + +shared_ptr <store> POP3Folder::getStore() { + + return m_store.lock(); +} + + +void POP3Folder::registerMessage(POP3Message* msg) { + + m_messages.insert(MessageMap::value_type(msg, msg->getNumber())); +} + + +void POP3Folder::unregisterMessage(POP3Message* msg) { + + m_messages.erase(msg); +} + + +void POP3Folder::onStoreDisconnected() { + + m_store.reset(); +} + + +void POP3Folder::deleteMessages(const messageSet& msgs) { + + shared_ptr <POP3Store> store = m_store.lock(); + + const std::vector <size_t> nums = POP3Utils::messageSetToNumberList(msgs, m_messageCount); + + 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"); + } + + for (std::vector <size_t>::const_iterator + it = nums.begin() ; it != nums.end() ; ++it) { + + POP3Command::DELE(*it)->send(store->getConnection()); + + shared_ptr <POP3Response> response = + POP3Response::readResponse(store->getConnection()); + + if (!response->isSuccess()) { + throw exceptions::command_error("DELE", response->getFirstLine()); + } + } + + // Sort message list + std::vector <size_t> list; + + list.resize(nums.size()); + std::copy(nums.begin(), nums.end(), list.begin()); + + std::sort(list.begin(), list.end()); + + // Update local flags + for (std::map <POP3Message*, size_t>::iterator it = + m_messages.begin() ; it != m_messages.end() ; ++it) { + + POP3Message* msg = (*it).first; + + if (std::binary_search(list.begin(), list.end(), msg->getNumber())) { + msg->m_deleted = true; + } + } + + // Notify message flags changed + shared_ptr <events::messageChangedEvent> event = + make_shared <events::messageChangedEvent>( + dynamicCast <folder>(shared_from_this()), + events::messageChangedEvent::TYPE_FLAGS, + list + ); + + notifyMessageChanged(event); +} + + +void POP3Folder::setMessageFlags( + const messageSet& /* msgs */, + const int /* flags */, + const int /* mode */ +) { + + throw exceptions::operation_not_supported(); +} + + +void POP3Folder::rename(const folder::path& /* newPath */) { + + throw exceptions::operation_not_supported(); +} + + +messageSet POP3Folder::addMessage( + const shared_ptr <vmime::message>& /* msg */, + const int /* flags */, + vmime::datetime* /* date */, + utility::progressListener* /* progress */ +) { + + throw exceptions::operation_not_supported(); +} + + +messageSet POP3Folder::addMessage( + utility::inputStream& /* is */, + const size_t /* size */, + const int /* flags */, + vmime::datetime* /* date */, + utility::progressListener* /* progress */ +) { + + throw exceptions::operation_not_supported(); +} + + +messageSet POP3Folder::copyMessages( + const folder::path& /* dest */, + const messageSet& /* msgs */ +) { + + throw exceptions::operation_not_supported(); +} + + +void POP3Folder::status(size_t& count, size_t& unseen) { + + count = 0; + unseen = 0; + + shared_ptr <folderStatus> status = getStatus(); + + count = status->getMessageCount(); + unseen = status->getUnseenCount(); + + m_messageCount = count; +} + + +shared_ptr <folderStatus> POP3Folder::getStatus() { + + shared_ptr <POP3Store> store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + POP3Command::STAT()->send(store->getConnection()); + + shared_ptr <POP3Response> response = + POP3Response::readResponse(store->getConnection()); + + if (!response->isSuccess()) { + throw exceptions::command_error("STAT", response->getFirstLine()); + } + + + size_t count = 0; + + std::istringstream iss(response->getText()); + iss.imbue(std::locale::classic()); + iss >> count; + + shared_ptr <POP3FolderStatus> status = make_shared <POP3FolderStatus>(); + + status->setMessageCount(count); + status->setUnseenCount(count); + + // Update local message count + if (m_messageCount != count) { + + const size_t oldCount = m_messageCount; + + m_messageCount = count; + + if (count > oldCount) { + + std::vector <size_t> nums; + nums.resize(count - oldCount); + + for (size_t i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j) { + nums[j] = i; + } + + // Notify message count changed + shared_ptr <events::messageCountEvent> event = + make_shared <events::messageCountEvent>( + dynamicCast <folder>(shared_from_this()), + events::messageCountEvent::TYPE_ADDED, + nums + ); + + notifyMessageCount(event); + + // Notify folders with the same path + for (std::list <POP3Folder*>::iterator it = store->m_folders.begin() ; + it != store->m_folders.end() ; ++it) { + + if ((*it) != this && (*it)->getFullPath() == m_path) { + + (*it)->m_messageCount = count; + + shared_ptr <events::messageCountEvent> event = + make_shared <events::messageCountEvent>( + dynamicCast <folder>((*it)->shared_from_this()), + events::messageCountEvent::TYPE_ADDED, + nums + ); + + (*it)->notifyMessageCount(event); + } + } + } + } + + return status; +} + + +void POP3Folder::expunge() { + + // Not supported by POP3 protocol (deleted messages are automatically + // expunged at the end of the session...). +} + + +std::vector <size_t> POP3Folder::getMessageNumbersStartingOnUID(const message::uid& /* uid */) { + + throw exceptions::operation_not_supported(); +} + + +} // pop3 +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3 + |