diff options
Diffstat (limited to '')
-rw-r--r-- | src/net/imap/IMAPConnection.cpp | 103 | ||||
-rw-r--r-- | src/net/imap/IMAPFolder.cpp | 185 | ||||
-rw-r--r-- | src/net/imap/IMAPFolderStatus.cpp | 158 | ||||
-rw-r--r-- | src/net/imap/IMAPMessage.cpp | 80 | ||||
-rw-r--r-- | src/net/imap/IMAPStore.cpp | 13 | ||||
-rw-r--r-- | src/net/imap/IMAPUtils.cpp | 26 | ||||
-rw-r--r-- | src/net/maildir/maildirFolder.cpp | 27 | ||||
-rw-r--r-- | src/net/maildir/maildirFolderStatus.cpp | 67 | ||||
-rw-r--r-- | src/net/maildir/maildirMessage.cpp | 2 | ||||
-rw-r--r-- | src/net/pop3/POP3Folder.cpp | 25 | ||||
-rw-r--r-- | src/net/pop3/POP3FolderStatus.cpp | 67 | ||||
-rw-r--r-- | src/net/pop3/POP3Message.cpp | 2 |
12 files changed, 585 insertions, 170 deletions
diff --git a/src/net/imap/IMAPConnection.cpp b/src/net/imap/IMAPConnection.cpp index 935de8cf..c5ff58a7 100644 --- a/src/net/imap/IMAPConnection.cpp +++ b/src/net/imap/IMAPConnection.cpp @@ -35,6 +35,8 @@ #include "vmime/exception.hpp" #include "vmime/platform.hpp" +#include "vmime/utility/stringUtils.hpp" + #include "vmime/net/defaultConnectionInfos.hpp" #if VMIME_HAVE_SASL_SUPPORT @@ -66,7 +68,7 @@ namespace imap { IMAPConnection::IMAPConnection(ref <IMAPStore> store, ref <security::authenticator> auth) : m_store(store), m_auth(auth), m_socket(NULL), m_parser(NULL), m_tag(NULL), m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(NULL), - m_secured(false), m_firstTag(true), m_capabilitiesFetched(false) + m_secured(false), m_firstTag(true), m_capabilitiesFetched(false), m_noModSeq(false) { } @@ -155,6 +157,12 @@ void IMAPConnection::connect() needAuth = true; } + if (greet->resp_cond_auth()->resp_text()->resp_text_code() && + greet->resp_cond_auth()->resp_text()->resp_text_code()->capability_data()) + { + processCapabilityResponseData(greet->resp_cond_auth()->resp_text()->resp_text_code()->capability_data()); + } + #if VMIME_HAVE_TLS_SUPPORT // Setup secured connection, if requested const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS) @@ -266,6 +274,10 @@ void IMAPConnection::authenticate() internalDisconnect(); throw exceptions::authentication_error(m_parser->lastLine()); } + + // Server capabilities may change when logged in + if (!processCapabilityResponseData(resp)) + invalidateCapabilities(); } @@ -397,6 +409,9 @@ void IMAPConnection::authenticateSASL() // Send response send(false, saslContext->encodeB64(resp, respLen), true); + + // Server capabilities may change when logged in + invalidateCapabilities(); } catch (exceptions::sasl_exception& e) { @@ -506,6 +521,23 @@ const std::vector <string> IMAPConnection::getCapabilities() } +bool IMAPConnection::hasCapability(const string& capa) +{ + if (!m_capabilitiesFetched) + fetchCapabilities(); + + const string normCapa = utility::stringUtils::toUpper(capa); + + for (unsigned int i = 0, n = m_capabilities.size() ; i < n ; ++i) + { + if (m_capabilities[i] == normCapa) + return true; + } + + return false; +} + + void IMAPConnection::invalidateCapabilities() { m_capabilities.clear(); @@ -519,35 +551,50 @@ void IMAPConnection::fetchCapabilities() utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse()); - std::vector <string> res; - if (resp->response_done()->response_tagged()-> resp_cond_state()->status() == IMAPParser::resp_cond_state::OK) { - const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = - resp->continue_req_or_response_data(); + processCapabilityResponseData(resp); + } +} - for (unsigned int i = 0 ; i < respDataList.size() ; ++i) - { - if (respDataList[i]->response_data() == NULL) - continue; - const IMAPParser::capability_data* capaData = - respDataList[i]->response_data()->capability_data(); +bool IMAPConnection::processCapabilityResponseData(const IMAPParser::response* resp) +{ + const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = + resp->continue_req_or_response_data(); + + for (unsigned int i = 0 ; i < respDataList.size() ; ++i) + { + if (respDataList[i]->response_data() == NULL) + continue; - if (capaData == NULL) - continue; + const IMAPParser::capability_data* capaData = + respDataList[i]->response_data()->capability_data(); - std::vector <IMAPParser::capability*> caps = capaData->capabilities(); + if (capaData == NULL) + continue; - for (unsigned int j = 0 ; j < caps.size() ; ++j) - { - if (caps[j]->auth_type()) - res.push_back("AUTH=" + caps[j]->auth_type()->name()); - else - res.push_back(caps[j]->atom()->value()); - } - } + processCapabilityResponseData(capaData); + return true; + } + + return false; +} + + +void IMAPConnection::processCapabilityResponseData(const IMAPParser::capability_data* capaData) +{ + std::vector <string> res; + + std::vector <IMAPParser::capability*> caps = capaData->capabilities(); + + for (unsigned int j = 0 ; j < caps.size() ; ++j) + { + if (caps[j]->auth_type()) + res.push_back("AUTH=" + caps[j]->auth_type()->name()); + else + res.push_back(utility::stringUtils::toUpper(caps[j]->atom()->value())); } m_capabilities = res; @@ -756,6 +803,18 @@ ref <const socket> IMAPConnection::getSocket() const } +bool IMAPConnection::isMODSEQDisabled() const +{ + return m_noModSeq; +} + + +void IMAPConnection::disableMODSEQ() +{ + m_noModSeq = true; +} + + } // imap } // net } // vmime diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp index 1ee8ac3f..3c54bce8 100644 --- a/src/net/imap/IMAPFolder.cpp +++ b/src/net/imap/IMAPFolder.cpp @@ -34,6 +34,7 @@ #include "vmime/net/imap/IMAPMessage.hpp" #include "vmime/net/imap/IMAPUtils.hpp" #include "vmime/net/imap/IMAPConnection.hpp" +#include "vmime/net/imap/IMAPFolderStatus.hpp" #include "vmime/message.hpp" @@ -57,6 +58,8 @@ IMAPFolder::IMAPFolder(const folder::path& path, ref <IMAPStore> store, const in m_open(false), m_type(type), m_flags(flags), m_messageCount(0), m_uidValidity(0) { store->registerFolder(this); + + m_status = vmime::create <IMAPFolderStatus>(); } @@ -176,6 +179,9 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable) oss << IMAPUtils::quoteString(IMAPUtils::pathToString (connection->hierarchySeparator(), getFullPath())); + if (m_connection->hasCapability("CONDSTORE")) + oss << " (CONDSTORE)"; + connection->send(true, oss.str(), true); // Read the response @@ -217,6 +223,11 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable) m_uidValidity = static_cast <unsigned int>(code->nz_number()->value()); break; + case IMAPParser::resp_text_code::NOMODSEQ: + + connection->disableMODSEQ(); + break; + default: break; @@ -255,6 +266,8 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable) } } + processStatusUpdate(resp); + // 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(); @@ -792,7 +805,7 @@ void IMAPFolder::fetchMessages(std::vector <ref <message> >& msg, const int opti } // Send the request - const string command = IMAPUtils::buildFetchRequest(list, options); + const string command = IMAPUtils::buildFetchRequest(m_connection, list, options); m_connection->send(true, command, true); // Get the response @@ -856,19 +869,17 @@ void IMAPFolder::fetchMessages(std::vector <ref <message> >& msg, const int opti if (progress) progress->stop(total); + + processStatusUpdate(resp); } 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"); + std::vector <ref <message> > msgs; + msgs.push_back(msg); - msg.dynamicCast <IMAPMessage>()->fetch(thisRef().dynamicCast <IMAPFolder>(), options); + fetchMessages(msgs, options, /* progress */ NULL); } @@ -973,6 +984,8 @@ void IMAPFolder::deleteMessage(const int num) events::messageChangedEvent::TYPE_FLAGS, nums); notifyMessageChanged(event); + + processStatusUpdate(resp); } @@ -1040,6 +1053,8 @@ void IMAPFolder::deleteMessages(const int from, const int to) events::messageChangedEvent::TYPE_FLAGS, nums); notifyMessageChanged(event); + + processStatusUpdate(resp); } @@ -1103,6 +1118,8 @@ void IMAPFolder::deleteMessages(const std::vector <int>& nums) events::messageChangedEvent::TYPE_FLAGS, list); notifyMessageChanged(event); + + processStatusUpdate(resp); } @@ -1311,6 +1328,8 @@ void IMAPFolder::setMessageFlags(const string& set, const int flags, const int m throw exceptions::command_error("STORE", m_connection->getParser()->lastLine(), "bad response"); } + + processStatusUpdate(resp); } } @@ -1455,6 +1474,8 @@ void IMAPFolder::addMessage(utility::inputStream& is, const int size, const int (*it)->notifyMessageCount(event); } } + + processStatusUpdate(resp); } @@ -1545,6 +1566,8 @@ void IMAPFolder::expunge() (*it)->notifyMessageCount(event); } } + + processStatusUpdate(resp); } @@ -1624,6 +1647,8 @@ void IMAPFolder::rename(const folder::path& newPath) (*it)->notifyFolder(event); } } + + processStatusUpdate(resp); } @@ -1767,16 +1792,30 @@ void IMAPFolder::copyMessages(const string& set, const folder::path& dest) throw exceptions::command_error("COPY", m_connection->getParser()->lastLine(), "bad response"); } + + processStatusUpdate(resp); } void IMAPFolder::status(int& count, int& unseen) { - ref <IMAPStore> store = m_store.acquire(); - count = 0; unseen = 0; + ref <folderStatus> status = getStatus(); + + count = status->getMessageCount(); + unseen = status->getUnseenCount(); +} + + +ref <folderStatus> IMAPFolder::getStatus() +{ + ref <IMAPStore> store = m_store.acquire(); + + if (!store) + throw exceptions::illegal_state("Store disconnected"); + // Build the request text std::ostringstream command; command.imbue(std::locale::classic()); @@ -1784,7 +1823,14 @@ void IMAPFolder::status(int& count, int& unseen) command << "STATUS "; command << IMAPUtils::quoteString(IMAPUtils::pathToString (m_connection->hierarchySeparator(), getFullPath())); - command << " (MESSAGES UNSEEN)"; + command << " ("; + + command << "MESSAGES" << ' ' << "UNSEEN" << ' ' << "UIDNEXT" << ' ' << "UIDVALIDITY"; + + if (m_connection->hasCapability("CONDSTORE")) + command << ' ' << "HIGHESTMODSEQ"; + + command << ")"; // Send the request m_connection->send(true, command.str(), true); @@ -1805,81 +1851,47 @@ void IMAPFolder::status(int& count, int& unseen) 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) + if ((*it)->response_data() != NULL) { - const IMAPParser::status_att_list* statusAttList = - responseData->mailbox_data()->status_att_list(); + const IMAPParser::response_data* responseData = (*it)->response_data(); - for (std::vector <IMAPParser::status_att_val*>::const_iterator - jt = statusAttList->values().begin() ; jt != statusAttList->values().end() ; ++jt) + if (responseData->mailbox_data() && + responseData->mailbox_data()->type() == IMAPParser::mailbox_data::STATUS) { - switch ((*jt)->type()) - { - case IMAPParser::status_att_val::MESSAGES: - - count = (*jt)->value_as_number()->value(); - break; - - case IMAPParser::status_att_val::UNSEEN: - - unseen = (*jt)->value_as_number()->value(); - break; + ref <IMAPFolderStatus> status = vmime::create <IMAPFolderStatus>(); + status->updateFromResponse(responseData->mailbox_data()); - default: + m_messageCount = status->getMessageCount(); + m_uidValidity = status->getUIDValidity(); - break; - } + return status; } } } - // 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); + throw exceptions::command_error("STATUS", + m_connection->getParser()->lastLine(), "invalid response"); +} - 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); +void IMAPFolder::noop() +{ + ref <IMAPStore> store = m_store.acquire(); - notifyMessageCount(event); + if (!store) + throw exceptions::illegal_state("Store disconnected"); - // 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; + m_connection->send(true, "NOOP", true); - events::messageCountEvent event - ((*it)->thisRef().dynamicCast <folder>(), - events::messageCountEvent::TYPE_ADDED, nums); + utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse()); - (*it)->notifyMessageCount(event); - } - } - } + if (resp->isBad() || resp->response_done()->response_tagged()-> + resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) + { + throw exceptions::command_error("NOOP", m_connection->getParser()->lastLine()); } + + processStatusUpdate(resp); } @@ -1939,6 +1951,39 @@ std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& } +void IMAPFolder::processStatusUpdate(const IMAPParser::response* resp) +{ + // Process tagged response + if (resp->response_done() && resp->response_done()->response_tagged() && + resp->response_done()->response_tagged() + ->resp_cond_state()->resp_text()->resp_text_code()) + { + const IMAPParser::resp_text_code* code = + resp->response_done()->response_tagged() + ->resp_cond_state()->resp_text()->resp_text_code(); + + m_status->updateFromResponse(code); + } + + // Process untagged responses + for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator + it = resp->continue_req_or_response_data().begin() ; + it != resp->continue_req_or_response_data().end() ; ++it) + { + if ((*it)->response_data() && (*it)->response_data()->resp_cond_state() && + (*it)->response_data()->resp_cond_state()->resp_text()->resp_text_code()) + { + const IMAPParser::resp_text_code* code = + (*it)->response_data()->resp_cond_state()->resp_text()->resp_text_code(); + + m_status->updateFromResponse(code); + } + } + + m_messageCount = m_status->getMessageCount(); + m_uidValidity = m_status->getUIDValidity(); +} + } // imap } // net } // vmime diff --git a/src/net/imap/IMAPFolderStatus.cpp b/src/net/imap/IMAPFolderStatus.cpp new file mode 100644 index 00000000..009f6ba4 --- /dev/null +++ b/src/net/imap/IMAPFolderStatus.cpp @@ -0,0 +1,158 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP + + +#include "vmime/net/imap/IMAPFolderStatus.hpp" + + +namespace vmime { +namespace net { +namespace imap { + + +unsigned int IMAPFolderStatus::getMessageCount() const +{ + return m_count; +} + + +unsigned int IMAPFolderStatus::getUnseenCount() const +{ + return m_unseen; +} + + +unsigned int IMAPFolderStatus::getRecentCount() const +{ + return m_recent; +} + + +vmime_uint32 IMAPFolderStatus::getUIDValidity() const +{ + return m_uidValidity; +} + + +vmime_uint32 IMAPFolderStatus::getUIDNext() const +{ + return m_uidNext; +} + + +vmime_uint64 IMAPFolderStatus::getHighestModSeq() const +{ + return m_highestModSeq; +} + + +void IMAPFolderStatus::updateFromResponse(const IMAPParser::mailbox_data* resp) +{ + const IMAPParser::status_att_list* statusAttList = resp->status_att_list(); + + for (std::vector <IMAPParser::status_att_val*>::const_iterator + jt = statusAttList->values().begin() ; jt != statusAttList->values().end() ; ++jt) + { + switch ((*jt)->type()) + { + case IMAPParser::status_att_val::MESSAGES: + + m_count = (*jt)->value_as_number()->value(); + break; + + case IMAPParser::status_att_val::UNSEEN: + + m_unseen = (*jt)->value_as_number()->value(); + break; + + case IMAPParser::status_att_val::RECENT: + + m_recent = (*jt)->value_as_number()->value(); + break; + + case IMAPParser::status_att_val::UIDNEXT: + + m_uidNext = (*jt)->value_as_number()->value(); + break; + + case IMAPParser::status_att_val::UIDVALIDITY: + + m_uidValidity = (*jt)->value_as_number()->value(); + break; + + case IMAPParser::status_att_val::HIGHESTMODSEQ: + + m_highestModSeq = (*jt)->value_as_mod_sequence_value()->value(); + break; + } + } +} + + +void IMAPFolderStatus::updateFromResponse(const IMAPParser::resp_text_code* resp) +{ + switch (resp->type()) + { + case IMAPParser::resp_text_code::UIDVALIDITY: + + m_uidValidity = resp->nz_number()->value(); + break; + + case IMAPParser::resp_text_code::UIDNEXT: + + m_uidNext = resp->nz_number()->value(); + break; + + case IMAPParser::resp_text_code::UNSEEN: + + m_unseen = resp->nz_number()->value(); + break; + + case IMAPParser::resp_text_code::HIGHESTMODSEQ: + + m_highestModSeq = resp->mod_sequence_value()->value(); + break; + + case IMAPParser::resp_text_code::NOMODSEQ: + + m_highestModSeq = 0; + break; + + default: + + break; + } +} + + +} // imap +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp index 6db00768..7e88ef85 100644 --- a/src/net/imap/IMAPMessage.cpp +++ b/src/net/imap/IMAPMessage.cpp @@ -98,15 +98,15 @@ private: IMAPMessage::IMAPMessage(ref <IMAPFolder> folder, const int num) : m_folder(folder), m_num(num), m_size(-1), m_flags(FLAG_UNDEFINED), - m_expunged(false), m_structure(NULL) + m_expunged(false), m_modseq(0), m_structure(NULL) { folder->registerMessage(this); } -IMAPMessage::IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uniqueId) +IMAPMessage::IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uid) : m_folder(folder), m_num(num), m_size(-1), m_flags(FLAG_UNDEFINED), - m_expunged(false), m_uid(uniqueId), m_structure(NULL) + m_expunged(false), m_uid(uid), m_modseq(0), m_structure(NULL) { folder->registerMessage(this); } @@ -133,9 +133,15 @@ int IMAPMessage::getNumber() const } -const message::uid IMAPMessage::getUniqueId() const +const message::uid IMAPMessage::getUID() const { - return (m_uid); + return m_uid; +} + + +vmime_uint64 IMAPMessage::getModSequence() const +{ + return m_modseq; } @@ -358,59 +364,6 @@ void IMAPMessage::extractImpl(ref <const part> p, utility::outputStream& os, } -void IMAPMessage::fetch(ref <IMAPFolder> msgFolder, const int options) -{ - ref <IMAPFolder> folder = m_folder.acquire(); - - if (folder != msgFolder) - throw exceptions::folder_not_found(); - - // Send the request - std::vector <int> list; - list.push_back(m_num); - - const string command = IMAPUtils::buildFetchRequest(list, options); - - folder->m_connection->send(true, command, true); - - // Get the response - utility::auto_ptr <IMAPParser::response> resp(folder->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", - folder->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("FETCH", - folder->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; - - if (static_cast <int>(messageData->number()) != m_num) - continue; - - // Process fetch response for this message - processFetchResponse(options, messageData); - } -} - - void IMAPMessage::processFetchResponse (const int options, const IMAPParser::message_data* msgData) { @@ -436,6 +389,11 @@ void IMAPMessage::processFetchResponse m_uid = IMAPUtils::makeGlobalUID(folder->m_uidValidity, (*it)->unique_id()->value()); break; } + case IMAPParser::msg_att_item::MODSEQ: + { + m_modseq = (*it)->mod_sequence_value()->value(); + break; + } case IMAPParser::msg_att_item::ENVELOPE: { if (!(options & folder::FETCH_FULL_HEADER)) @@ -731,7 +689,11 @@ ref <vmime::message> IMAPMessage::getParsedMessage() } catch (exceptions::unfetched_object&) { - fetch(m_folder.acquire(), IMAPFolder::FETCH_STRUCTURE); + std::vector <ref <message> > msgs; + msgs.push_back(thisRef().dynamicCast <IMAPMessage>()); + + m_folder.acquire()->fetchMessages(msgs, IMAPFolder::FETCH_STRUCTURE, /* progress */ NULL); + structure = getStructure(); } diff --git a/src/net/imap/IMAPStore.cpp b/src/net/imap/IMAPStore.cpp index 1821b221..e8778f90 100644 --- a/src/net/imap/IMAPStore.cpp +++ b/src/net/imap/IMAPStore.cpp @@ -153,6 +153,12 @@ ref <connectionInfos> IMAPStore::getConnectionInfos() const } +ref <IMAPConnection> IMAPStore::getConnection() +{ + return m_connection; +} + + void IMAPStore::disconnect() { if (!isConnected()) @@ -187,6 +193,13 @@ void IMAPStore::noop() { throw exceptions::command_error("NOOP", m_connection->getParser()->lastLine()); } + + + for (std::list <IMAPFolder*>::iterator it = m_folders.begin() ; + it != m_folders.end() ; ++it) + { + (*it)->noop(); + } } diff --git a/src/net/imap/IMAPUtils.cpp b/src/net/imap/IMAPUtils.cpp index 4fea517f..2aad06a1 100644 --- a/src/net/imap/IMAPUtils.cpp +++ b/src/net/imap/IMAPUtils.cpp @@ -634,7 +634,7 @@ const string IMAPUtils::dateTime(const vmime::datetime& date) // static const string IMAPUtils::buildFetchRequestImpl - (const string& mode, const string& set, const int options) + (ref <IMAPConnection> cnt, const string& mode, const string& set, const int options) { // Example: // C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)]) @@ -655,8 +655,14 @@ const string IMAPUtils::buildFetchRequestImpl items.push_back("BODYSTRUCTURE"); if (options & folder::FETCH_UID) + { items.push_back("UID"); + // Also fetch MODSEQ if CONDSTORE is supported + if (cnt->hasCapability("CONDSTORE") && !cnt->isMODSEQDisabled()) + items.push_back("MODSEQ"); + } + if (options & folder::FETCH_FULL_HEADER) items.push_back("RFC822.HEADER"); else @@ -715,16 +721,18 @@ const string IMAPUtils::buildFetchRequestImpl // static -const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const int options) +const string IMAPUtils::buildFetchRequest + (ref <IMAPConnection> cnt, const std::vector <int>& list, const int options) { - return buildFetchRequestImpl("number", listToSet(list, -1, false), options); + return buildFetchRequestImpl(cnt, "number", listToSet(list, -1, false), options); } // static -const string IMAPUtils::buildFetchRequest(const std::vector <message::uid>& list, const int options) +const string IMAPUtils::buildFetchRequest + (ref <IMAPConnection> cnt, const std::vector <message::uid>& list, const int options) { - return buildFetchRequestImpl("uid", listToSet(list), options); + return buildFetchRequestImpl(cnt, "uid", listToSet(list), options); } @@ -749,7 +757,7 @@ void IMAPUtils::convertAddressList // static -unsigned int IMAPUtils::extractUIDFromGlobalUID(const message::uid& uid) +vmime_uint32 IMAPUtils::extractUIDFromGlobalUID(const message::uid& uid) { message::uid::size_type colonPos = uid.find(':'); @@ -758,7 +766,7 @@ unsigned int IMAPUtils::extractUIDFromGlobalUID(const message::uid& uid) std::istringstream iss(uid); iss.imbue(std::locale::classic()); - unsigned int n = 0; + vmime_uint32 n = 0; iss >> n; return n; @@ -768,7 +776,7 @@ unsigned int IMAPUtils::extractUIDFromGlobalUID(const message::uid& uid) std::istringstream iss(uid.substr(colonPos + 1)); iss.imbue(std::locale::classic()); - unsigned int n = 0; + vmime_uint32 n = 0; iss >> n; return n; @@ -777,7 +785,7 @@ unsigned int IMAPUtils::extractUIDFromGlobalUID(const message::uid& uid) // static -const message::uid IMAPUtils::makeGlobalUID(const unsigned int UIDValidity, const unsigned int messageUID) +const message::uid IMAPUtils::makeGlobalUID(const vmime_uint32 UIDValidity, const vmime_uint32 messageUID) { std::ostringstream oss; oss.imbue(std::locale::classic()); diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp index aa886ff3..3ea1093e 100644 --- a/src/net/maildir/maildirFolder.cpp +++ b/src/net/maildir/maildirFolder.cpp @@ -33,6 +33,7 @@ #include "vmime/net/maildir/maildirMessage.hpp" #include "vmime/net/maildir/maildirUtils.hpp" #include "vmime/net/maildir/maildirFormat.hpp" +#include "vmime/net/maildir/maildirFolderStatus.hpp" #include "vmime/utility/smartPtr.hpp" @@ -1163,22 +1164,36 @@ void maildirFolder::notifyMessagesCopied(const folder::path& dest) void maildirFolder::status(int& count, int& unseen) { + count = 0; + unseen = 0; + + ref <folderStatus> status = getStatus(); + + count = status->getMessageCount(); + unseen = status->getUnseenCount(); +} + + +ref <folderStatus> maildirFolder::getStatus() +{ ref <maildirStore> store = m_store.acquire(); const int oldCount = m_messageCount; scanFolder(); - count = m_messageCount; - unseen = m_unreadMessageCount; + ref <maildirFolderStatus> status = vmime::create <maildirFolderStatus>(); + + status->setMessageCount(m_messageCount); + status->setUnseenCount(m_unreadMessageCount); // Notify message count changed (new messages) - if (count > oldCount) + if (m_messageCount > oldCount) { std::vector <int> nums; - nums.reserve(count - oldCount); + nums.reserve(m_messageCount - oldCount); - for (int i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j) + for (int i = oldCount + 1, j = 0 ; i <= m_messageCount ; ++i, ++j) nums[j] = i; events::messageCountEvent event @@ -1207,6 +1222,8 @@ void maildirFolder::status(int& count, int& unseen) } } } + + return status; } diff --git a/src/net/maildir/maildirFolderStatus.cpp b/src/net/maildir/maildirFolderStatus.cpp new file mode 100644 index 00000000..49425e59 --- /dev/null +++ b/src/net/maildir/maildirFolderStatus.cpp @@ -0,0 +1,67 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/maildir/maildirFolderStatus.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +unsigned int maildirFolderStatus::getMessageCount() const +{ + return m_count; +} + + +unsigned int maildirFolderStatus::getUnseenCount() const +{ + return m_unseen; +} + + +void maildirFolderStatus::setMessageCount(const unsigned int count) +{ + m_count = count; +} + + +void maildirFolderStatus::setUnseenCount(const unsigned int unseen) +{ + m_unseen = unseen; +} + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR diff --git a/src/net/maildir/maildirMessage.cpp b/src/net/maildir/maildirMessage.cpp index 9b14ad78..b6c12053 100644 --- a/src/net/maildir/maildirMessage.cpp +++ b/src/net/maildir/maildirMessage.cpp @@ -261,7 +261,7 @@ int maildirMessage::getNumber() const } -const message::uid maildirMessage::getUniqueId() const +const message::uid maildirMessage::getUID() const { return (m_uid); } diff --git a/src/net/pop3/POP3Folder.cpp b/src/net/pop3/POP3Folder.cpp index 7aa850b1..1b7b3df6 100644 --- a/src/net/pop3/POP3Folder.cpp +++ b/src/net/pop3/POP3Folder.cpp @@ -33,6 +33,7 @@ #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" @@ -752,12 +753,22 @@ void POP3Folder::copyMessages(const folder::path& /* dest */, const std::vector void POP3Folder::status(int& count, int& unseen) { + count = 0; + unseen = 0; + + ref <folderStatus> status = getStatus(); + + count = status->getMessageCount(); + unseen = status->getUnseenCount(); +} + + +ref <folderStatus> POP3Folder::getStatus() +{ ref <POP3Store> store = m_store.acquire(); if (!store) throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); POP3Command::STAT()->send(store->getConnection()); @@ -767,10 +778,16 @@ void POP3Folder::status(int& count, int& unseen) if (!response->isSuccess()) throw exceptions::command_error("STAT", response->getFirstLine()); + + unsigned int count = 0; + std::istringstream iss(response->getText()); iss >> count; - unseen = count; + ref <POP3FolderStatus> status = vmime::create <POP3FolderStatus>(); + + status->setMessageCount(count); + status->setUnseenCount(count); // Update local message count if (m_messageCount != count) @@ -811,6 +828,8 @@ void POP3Folder::status(int& count, int& unseen) } } } + + return status; } diff --git a/src/net/pop3/POP3FolderStatus.cpp b/src/net/pop3/POP3FolderStatus.cpp new file mode 100644 index 00000000..e8c5face --- /dev/null +++ b/src/net/pop3/POP3FolderStatus.cpp @@ -0,0 +1,67 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3 + + +#include "vmime/net/pop3/POP3FolderStatus.hpp" + + +namespace vmime { +namespace net { +namespace pop3 { + + +unsigned int POP3FolderStatus::getMessageCount() const +{ + return m_count; +} + + +unsigned int POP3FolderStatus::getUnseenCount() const +{ + return m_unseen; +} + + +void POP3FolderStatus::setMessageCount(const unsigned int count) +{ + m_count = count; +} + + +void POP3FolderStatus::setUnseenCount(const unsigned int unseen) +{ + m_unseen = unseen; +} + + +} // pop3 +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3 diff --git a/src/net/pop3/POP3Message.cpp b/src/net/pop3/POP3Message.cpp index d2bb9881..659e3d79 100644 --- a/src/net/pop3/POP3Message.cpp +++ b/src/net/pop3/POP3Message.cpp @@ -72,7 +72,7 @@ int POP3Message::getNumber() const } -const message::uid POP3Message::getUniqueId() const +const message::uid POP3Message::getUID() const { return (m_uid); } |