aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Richard <[email protected]>2013-07-16 09:07:16 +0000
committerVincent Richard <[email protected]>2013-07-16 09:07:16 +0000
commit54084253e62941d641061b9db0af7ea607a910bd (patch)
tree81ae637583e56e02790e65cd12caf906a0770b04
parentFixed IMAP tag not incrementing. (diff)
downloadvmime-54084253e62941d641061b9db0af7ea607a910bd.tar.gz
vmime-54084253e62941d641061b9db0af7ea607a910bd.zip
Added basic support for IMAP CONDSTORE extension.
Process CAPABILITY in IMAP greeting response. Renamed getUniqueId() to getUID() for consistency.
-rw-r--r--SConstruct4
-rw-r--r--src/net/imap/IMAPConnection.cpp103
-rw-r--r--src/net/imap/IMAPFolder.cpp185
-rw-r--r--src/net/imap/IMAPFolderStatus.cpp158
-rw-r--r--src/net/imap/IMAPMessage.cpp80
-rw-r--r--src/net/imap/IMAPStore.cpp13
-rw-r--r--src/net/imap/IMAPUtils.cpp26
-rw-r--r--src/net/maildir/maildirFolder.cpp27
-rw-r--r--src/net/maildir/maildirFolderStatus.cpp67
-rw-r--r--src/net/maildir/maildirMessage.cpp2
-rw-r--r--src/net/pop3/POP3Folder.cpp25
-rw-r--r--src/net/pop3/POP3FolderStatus.cpp67
-rw-r--r--src/net/pop3/POP3Message.cpp2
-rw-r--r--vmime/net/folder.hpp10
-rw-r--r--vmime/net/folderStatus.hpp68
-rw-r--r--vmime/net/imap/IMAPConnection.hpp9
-rw-r--r--vmime/net/imap/IMAPFolder.hpp24
-rw-r--r--vmime/net/imap/IMAPFolderStatus.hpp117
-rw-r--r--vmime/net/imap/IMAPMessage.hpp19
-rw-r--r--vmime/net/imap/IMAPParser.hpp837
-rw-r--r--vmime/net/imap/IMAPStore.hpp1
-rw-r--r--vmime/net/imap/IMAPUtils.hpp15
-rw-r--r--vmime/net/maildir/maildirFolder.hpp1
-rw-r--r--vmime/net/maildir/maildirFolderStatus.hpp70
-rw-r--r--vmime/net/maildir/maildirMessage.hpp2
-rw-r--r--vmime/net/message.hpp5
-rw-r--r--vmime/net/pop3/POP3Folder.hpp1
-rw-r--r--vmime/net/pop3/POP3FolderStatus.hpp70
-rw-r--r--vmime/net/pop3/POP3Message.hpp2
29 files changed, 1560 insertions, 450 deletions
diff --git a/SConstruct b/SConstruct
index 6f8b83ac..e4f149f3 100644
--- a/SConstruct
+++ b/SConstruct
@@ -204,6 +204,7 @@ libvmime_messaging_sources = [
'net/defaultConnectionInfos.cpp', 'net/defaultConnectionInfos.hpp',
'net/events.cpp', 'net/events.hpp',
'net/folder.cpp', 'net/folder.hpp',
+ 'net/folderStatus.hpp',
'net/message.cpp', 'net/message.hpp',
'net/securedConnectionInfos.hpp',
'net/service.cpp', 'net/service.hpp',
@@ -245,6 +246,7 @@ libvmime_messaging_proto_sources = [
'net/pop3/POP3Store.cpp', 'net/pop3/POP3Store.hpp',
'net/pop3/POP3SStore.cpp', 'net/pop3/POP3SStore.hpp',
'net/pop3/POP3Folder.cpp', 'net/pop3/POP3Folder.hpp',
+ 'net/pop3/POP3FolderStatus.cpp', 'net/pop3/POP3FolderStatus.hpp',
'net/pop3/POP3Message.cpp', 'net/pop3/POP3Message.hpp',
'net/pop3/POP3Response.cpp', 'net/pop3/POP3Response.hpp',
'net/pop3/POP3Utils.cpp', 'net/pop3/POP3Utils.hpp'
@@ -271,6 +273,7 @@ libvmime_messaging_proto_sources = [
'net/imap/IMAPStore.cpp', 'net/imap/IMAPStore.hpp',
'net/imap/IMAPSStore.cpp', 'net/imap/IMAPSStore.hpp',
'net/imap/IMAPFolder.cpp', 'net/imap/IMAPFolder.hpp',
+ 'net/imap/IMAPFolderStatus.cpp', 'net/imap/IMAPFolderStatus.hpp',
'net/imap/IMAPMessage.cpp', 'net/imap/IMAPMessage.hpp',
'net/imap/IMAPTag.cpp', 'net/imap/IMAPTag.hpp',
'net/imap/IMAPUtils.cpp', 'net/imap/IMAPUtils.hpp',
@@ -286,6 +289,7 @@ libvmime_messaging_proto_sources = [
'net/maildir/maildirServiceInfos.cpp', 'net/maildir/maildirServiceInfos.hpp',
'net/maildir/maildirStore.cpp', 'net/maildir/maildirStore.hpp',
'net/maildir/maildirFolder.cpp', 'net/maildir/maildirFolder.hpp',
+ 'net/maildir/maildirFolderStatus.cpp', 'net/maildir/maildirFolderStatus.hpp',
'net/maildir/maildirMessage.cpp', 'net/maildir/maildirMessage.hpp',
'net/maildir/maildirUtils.cpp', 'net/maildir/maildirUtils.hpp',
'net/maildir/maildirFormat.cpp', 'net/maildir/maildirFormat.hpp',
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);
}
diff --git a/vmime/net/folder.hpp b/vmime/net/folder.hpp
index b34ff812..f65f3711 100644
--- a/vmime/net/folder.hpp
+++ b/vmime/net/folder.hpp
@@ -39,6 +39,7 @@
#include "vmime/message.hpp"
#include "vmime/net/message.hpp"
#include "vmime/net/events.hpp"
+#include "vmime/net/folderStatus.hpp"
#include "vmime/utility/path.hpp"
#include "vmime/utility/stream.hpp"
@@ -335,12 +336,21 @@ public:
/** Request folder status without opening it.
*
+ * \deprecated Use the new getStatus() method
+ *
* @param count will receive the number of messages in the folder
* @param unseen will receive the number of unseen messages in the folder
* @throw net_exception if an error occurs
*/
virtual void status(int& count, int& unseen) = 0;
+ /** Request folder status without opening it.
+ *
+ * @return current folder status
+ * @throw net_exception if an error occurs
+ */
+ virtual ref <folderStatus> getStatus() = 0;
+
/** Expunge deleted messages.
*
* @throw net_exception if an error occurs
diff --git a/vmime/net/folderStatus.hpp b/vmime/net/folderStatus.hpp
new file mode 100644
index 00000000..90beea66
--- /dev/null
+++ b/vmime/net/folderStatus.hpp
@@ -0,0 +1,68 @@
+//
+// 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.
+//
+
+#ifndef VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds the status of a mail store folder.
+ */
+
+class VMIME_EXPORT folderStatus : public object
+{
+public:
+
+ /** Returns the total number of messages in the folder.
+ *
+ * @return number of messages
+ */
+ virtual unsigned int getMessageCount() const = 0;
+
+ /** Returns the number of unseen messages in the folder.
+ *
+ * @return number of unseen messages
+ */
+ virtual unsigned int getUnseenCount() const = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime/net/imap/IMAPConnection.hpp b/vmime/net/imap/IMAPConnection.hpp
index 257e60d3..72defc29 100644
--- a/vmime/net/imap/IMAPConnection.hpp
+++ b/vmime/net/imap/IMAPConnection.hpp
@@ -96,6 +96,7 @@ public:
void fetchCapabilities();
void invalidateCapabilities();
const std::vector <string> getCapabilities();
+ bool hasCapability(const string& capa);
ref <security::authenticator> getAuthenticator();
@@ -104,6 +105,9 @@ public:
ref <const socket> getSocket() const;
+ bool isMODSEQDisabled() const;
+ void disableMODSEQ();
+
private:
void authenticate();
@@ -115,6 +119,9 @@ private:
void startTLS();
#endif // VMIME_HAVE_TLS_SUPPORT
+ bool processCapabilityResponseData(const IMAPParser::response* resp);
+ void processCapabilityResponseData(const IMAPParser::capability_data* capaData);
+
weak_ref <IMAPStore> m_store;
@@ -140,6 +147,8 @@ private:
std::vector <string> m_capabilities;
bool m_capabilitiesFetched;
+ bool m_noModSeq;
+
void internalDisconnect();
diff --git a/vmime/net/imap/IMAPFolder.hpp b/vmime/net/imap/IMAPFolder.hpp
index 55c16e9c..48e07603 100644
--- a/vmime/net/imap/IMAPFolder.hpp
+++ b/vmime/net/imap/IMAPFolder.hpp
@@ -38,6 +38,8 @@
#include "vmime/net/folder.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+
namespace vmime {
namespace net {
@@ -47,6 +49,7 @@ namespace imap {
class IMAPStore;
class IMAPMessage;
class IMAPConnection;
+class IMAPFolderStatus;
/** IMAP folder implementation.
@@ -62,7 +65,7 @@ private:
IMAPFolder(const folder::path& path, ref <IMAPStore> store, const int type = TYPE_UNDEFINED, const int flags = FLAG_UNDEFINED);
- IMAPFolder(const IMAPFolder&) : folder() { }
+ IMAPFolder(const IMAPFolder&);
~IMAPFolder();
@@ -118,6 +121,9 @@ public:
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
void status(int& count, int& unseen);
+ ref <folderStatus> getStatus();
+
+ void noop();
void expunge();
@@ -148,6 +154,18 @@ private:
void copyMessages(const string& set, const folder::path& dest);
+ /** Process status updates ("unsolicited responses") contained in the
+ * specified response. Example:
+ *
+ * C: a006 NOOP
+ * S: * 930 EXISTS <-- this is a status update
+ * S: a006 OK Success
+ *
+ * @param resp parsed IMAP response
+ */
+ void processStatusUpdate(const IMAPParser::response* resp);
+
+
weak_ref <IMAPStore> m_store;
ref <IMAPConnection> m_connection;
@@ -161,8 +179,8 @@ private:
int m_flags;
int m_messageCount;
-
- unsigned int m_uidValidity;
+ vmime_uint32 m_uidValidity;
+ ref <IMAPFolderStatus> m_status;
std::vector <IMAPMessage*> m_messages;
};
diff --git a/vmime/net/imap/IMAPFolderStatus.hpp b/vmime/net/imap/IMAPFolderStatus.hpp
new file mode 100644
index 00000000..1cad217c
--- /dev/null
+++ b/vmime/net/imap/IMAPFolderStatus.hpp
@@ -0,0 +1,117 @@
+//
+// 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.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/folderStatus.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+/** Holds the status of an IMAP folder.
+ */
+
+class VMIME_EXPORT IMAPFolderStatus : public folderStatus
+{
+public:
+
+ // Inherited from folderStatus
+ unsigned int getMessageCount() const;
+ unsigned int getUnseenCount() const;
+
+ /** Returns the the number of messages with the Recent flag set.
+ *
+ * @return number of messages flagged Recent
+ */
+ unsigned int getRecentCount() const;
+
+ /** Returns the UID validity of the folder for the current session.
+ * If the server is capable of persisting UIDs accross sessions,
+ * this value should never change for a folder.
+ *
+ * @return UID validity of the folder
+ */
+ vmime_uint32 getUIDValidity() const;
+
+ /** Returns the UID value that will be assigned to a new message
+ * in the folder. If the server does not support the UIDPLUS
+ * extension, it will return 0.
+ *
+ * @return UID of the next message
+ */
+ vmime_uint32 getUIDNext() const;
+
+ /** Returns the highest modification sequence of all messages
+ * in the folder, or 0 if not available for this folder, or not
+ * supported by the server. The server must support the CONDSTORE
+ * extension for this to be available.
+ *
+ * @return highest modification sequence
+ */
+ vmime_uint64 getHighestModSeq() const;
+
+
+ /** Reads the folder status from the specified IMAP response.
+ *
+ * @param resp parsed IMAP response
+ */
+ void updateFromResponse(const IMAPParser::mailbox_data* resp);
+
+ /** Reads the folder status from the specified IMAP response.
+ *
+ * @param resp parsed IMAP response
+ */
+ void updateFromResponse(const IMAPParser::resp_text_code* resp);
+
+private:
+
+ unsigned int m_count;
+ unsigned int m_unseen;
+ unsigned int m_recent;
+ vmime_uint32 m_uidValidity;
+ vmime_uint32 m_uidNext;
+ vmime_uint64 m_highestModSeq;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime/net/imap/IMAPMessage.hpp b/vmime/net/imap/IMAPMessage.hpp
index 5c36ce13..fb86696f 100644
--- a/vmime/net/imap/IMAPMessage.hpp
+++ b/vmime/net/imap/IMAPMessage.hpp
@@ -57,7 +57,7 @@ private:
friend class vmime::creator; // vmime::create <IMAPMessage>
IMAPMessage(ref <IMAPFolder> folder, const int num);
- IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uniqueId);
+ IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uid);
IMAPMessage(const IMAPMessage&) : message() { }
~IMAPMessage();
@@ -66,7 +66,19 @@ public:
int getNumber() const;
- const uid getUniqueId() const;
+ const uid getUID() const;
+
+ /** Returns the modification sequence for this message.
+ *
+ * Every time metadata for this message changes, the modification
+ * sequence is updated, and is greater than the previous one. The
+ * server must support the CONDSTORE extension for this to be
+ * available.
+ *
+ * @return modification sequence, or zero if not supported by
+ * the underlying protocol
+ */
+ vmime_uint64 getModSequence() const;
int getSize() const;
@@ -89,8 +101,6 @@ public:
private:
- void fetch(ref <IMAPFolder> folder, const int options);
-
void processFetchResponse(const int options, const IMAPParser::message_data* msgData);
/** Recursively fetch part header for all parts in the structure.
@@ -132,6 +142,7 @@ private:
int m_flags;
bool m_expunged;
uid m_uid;
+ vmime_uint64 m_modseq;
ref <header> m_header;
ref <structure> m_structure;
diff --git a/vmime/net/imap/IMAPParser.hpp b/vmime/net/imap/IMAPParser.hpp
index 41252a92..af871c27 100644
--- a/vmime/net/imap/IMAPParser.hpp
+++ b/vmime/net/imap/IMAPParser.hpp
@@ -1288,6 +1288,211 @@ public:
};
+ // seq-number = nz-number / "*"
+ // ; message sequence number (COPY, FETCH, STORE
+ // ; commands) or unique identifier (UID COPY,
+ // ; UID FETCH, UID STORE commands).
+
+ class seq_number : public component
+ {
+ public:
+
+ seq_number()
+ : m_number(NULL), m_star(false)
+ {
+ }
+
+ ~seq_number()
+ {
+ delete m_number;
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("seq_number");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'*'> >(line, &pos, true))
+ {
+ m_star = true;
+ m_number = NULL;
+ }
+ else
+ {
+ m_star = false;
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::number* m_number;
+ bool m_star;
+
+ public:
+
+ const IMAPParser::number* number() const { return m_number; }
+ bool star() const { return m_star; }
+ };
+
+
+ // seq-range = seq-number ":" seq-number
+ // ; two seq-number values and all values between
+ // ; these two regardless of order.
+ // ; Example: 2:4 and 4:2 are equivalent and indicate
+ // ; values 2, 3, and 4.
+
+ class seq_range : public component
+ {
+ public:
+
+ seq_range()
+ : m_first(NULL), m_last(NULL)
+ {
+ }
+
+ ~seq_range()
+ {
+ delete m_first;
+ delete m_last;
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("seq_range");
+
+ string::size_type pos = *currentPos;
+
+ m_first = parser.get <seq_number>(line, &pos);
+
+ parser.check <one_char <'*'> >(line, &pos);
+
+ m_last = parser.get <seq_number>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::seq_number* m_first;
+ IMAPParser::seq_number* m_last;
+
+ public:
+
+ const IMAPParser::seq_number* first() const { return m_first; }
+ const IMAPParser::seq_number* last() const { return m_last; }
+ };
+
+
+ // sequence-set = (seq-number / seq-range) *("," sequence-set)
+ // ; set of seq-number values, regardless of order.
+ // ; Servers MAY coalesce overlaps and/or execute the
+ // ; sequence in any order.
+ // ; Example: a message sequence number set of
+ // ; 2,4:7,9,12:* for a mailbox with 15 messages is
+ // ; equivalent to 2,4,5,6,7,9,12,13,14,15
+
+ class sequence_set : public component
+ {
+ public:
+
+ sequence_set()
+ : m_number(NULL), m_range(NULL), m_nextSet(NULL)
+ {
+ }
+
+ ~sequence_set()
+ {
+ delete m_number;
+ delete m_range;
+ delete m_nextSet;
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("sequence_set");
+
+ string::size_type pos = *currentPos;
+
+ if ((m_range = parser.get <IMAPParser::seq_range>(line, &pos, true)) == NULL)
+ m_number = parser.get <IMAPParser::seq_number>(line, &pos);
+
+ if (parser.check <one_char <','> >(line, &pos, true))
+ m_nextSet = parser.get <sequence_set>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::seq_number* m_number;
+ IMAPParser::seq_range* m_range;
+ IMAPParser::sequence_set* m_nextSet;
+
+ public:
+
+ const IMAPParser::seq_number* seq_number() const { return m_number; }
+ const IMAPParser::seq_range* seq_range() const { return m_range; }
+ const IMAPParser::sequence_set* next_sequence_set() const { return m_nextSet; }
+ };
+
+
+ // mod-sequence-value = 1*DIGIT
+ // ;; Positive unsigned 64-bit integer
+ // ;; (mod-sequence)
+ // ;; (1 <= n < 18,446,744,073,709,551,615)
+
+ class mod_sequence_value : public component
+ {
+ public:
+
+ mod_sequence_value()
+ : m_value(0)
+ {
+ }
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mod_sequence_value");
+
+ string::size_type pos = *currentPos;
+
+ bool valid = true;
+ vmime_uint64 val = 0;
+
+ while (valid && pos < line.length())
+ {
+ const char c = line[pos];
+
+ if (c >= '0' && c <= '9')
+ {
+ val = (val * 10) + (c - '0');
+ ++pos;
+ }
+ else
+ {
+ valid = false;
+ }
+ }
+
+ m_value = val;
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ vmime_uint64 m_value;
+
+ public:
+
+ const vmime_uint64 value() const { return m_value; }
+ };
+
+
//
// flag ::= "\Answered" / "\Flagged" / "\Deleted" /
// "\Seen" / "\Draft" / flag_keyword / flag_extension
@@ -1666,249 +1871,6 @@ public:
//
- // resp_text_code ::= "ALERT" / "PARSE" /
- // "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
- // "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
- // "UIDVALIDITY" SPACE nz_number /
- // "UNSEEN" SPACE nz_number /
- // atom [SPACE 1*<any TEXT_CHAR except "]">]
-
- class resp_text_code : public component
- {
- public:
-
- resp_text_code()
- : m_nz_number(NULL), m_atom(NULL), m_flag_list(NULL), m_text(NULL)
- {
- }
-
- ~resp_text_code()
- {
- delete (m_nz_number);
- delete (m_atom);
- delete (m_flag_list);
- delete (m_text);
- }
-
- void go(IMAPParser& parser, string& line, string::size_type* currentPos)
- {
- DEBUG_ENTER_COMPONENT("resp_text_code");
-
- string::size_type pos = *currentPos;
-
- // "ALERT"
- if (parser.checkWithArg <special_atom>(line, &pos, "alert", true))
- {
- m_type = ALERT;
- }
- // "PARSE"
- else if (parser.checkWithArg <special_atom>(line, &pos, "parse", true))
- {
- m_type = PARSE;
- }
- // "PERMANENTFLAGS" SPACE flag_list
- else if (parser.checkWithArg <special_atom>(line, &pos, "permanentflags", true))
- {
- m_type = PERMANENTFLAGS;
-
- parser.check <SPACE>(line, &pos);
-
- m_flag_list = parser.get <IMAPParser::flag_list>(line, &pos);
- }
- // "READ-ONLY"
- else if (parser.checkWithArg <special_atom>(line, &pos, "read-only", true))
- {
- m_type = READ_ONLY;
- }
- // "READ-WRITE"
- else if (parser.checkWithArg <special_atom>(line, &pos, "read-write", true))
- {
- m_type = READ_WRITE;
- }
- // "TRYCREATE"
- else if (parser.checkWithArg <special_atom>(line, &pos, "trycreate", true))
- {
- m_type = TRYCREATE;
- }
- // "UIDVALIDITY" SPACE nz_number
- else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true))
- {
- m_type = UIDVALIDITY;
-
- parser.check <SPACE>(line, &pos);
- m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
- }
- // "UNSEEN" SPACE nz_number
- else if (parser.checkWithArg <special_atom>(line, &pos, "unseen", true))
- {
- m_type = UNSEEN;
-
- parser.check <SPACE>(line, &pos);
- m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
- }
- // atom [SPACE 1*<any TEXT_CHAR except "]">]
- else
- {
- m_type = OTHER;
-
- m_atom = parser.get <IMAPParser::atom>(line, &pos);
-
- if (parser.check <SPACE>(line, &pos, true))
- m_text = parser.get <text_except <']'> >(line, &pos);
- }
-
- *currentPos = pos;
- }
-
-
- enum Type
- {
- ALERT,
- PARSE,
- PERMANENTFLAGS,
- READ_ONLY,
- READ_WRITE,
- TRYCREATE,
- UIDVALIDITY,
- UNSEEN,
- OTHER
- };
-
- private:
-
- Type m_type;
-
- IMAPParser::nz_number* m_nz_number;
- IMAPParser::atom* m_atom;
- IMAPParser::flag_list* m_flag_list;
- IMAPParser::text* m_text;
-
- public:
-
- Type type() const { return (m_type); }
-
- const IMAPParser::nz_number* nz_number() const { return (m_nz_number); }
- const IMAPParser::atom* atom() const { return (m_atom); }
- const IMAPParser::flag_list* flag_list() const { return (m_flag_list); }
- const IMAPParser::text* text() const { return (m_text); }
- };
-
-
- //
- // resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
- // ;; text SHOULD NOT begin with "[" or "="
-
- class resp_text : public component
- {
- public:
-
- resp_text()
- : m_resp_text_code(NULL)
- {
- }
-
- ~resp_text()
- {
- delete (m_resp_text_code);
- }
-
- void go(IMAPParser& parser, string& line, string::size_type* currentPos)
- {
- DEBUG_ENTER_COMPONENT("resp_text");
-
- string::size_type pos = *currentPos;
-
- if (parser.check <one_char <'['> >(line, &pos, true))
- {
- m_resp_text_code = parser.get <IMAPParser::resp_text_code>(line, &pos);
-
- parser.check <one_char <']'> >(line, &pos);
- parser.check <SPACE>(line, &pos, true);
- }
-
- text_mime2* text1 = parser.get <text_mime2>(line, &pos, true);
-
- if (text1 != NULL)
- {
- m_text = text1->value();
- delete (text1);
- }
- else
- {
- IMAPParser::text* text2 =
- parser.get <IMAPParser::text>(line, &pos, true);
-
- if (text2 != NULL)
- {
- m_text = text2->value();
- delete (text2);
- }
- else
- {
- // Empty response text
- }
- }
-
- *currentPos = pos;
- }
-
- private:
-
- IMAPParser::resp_text_code* m_resp_text_code;
- string m_text;
-
- public:
-
- const IMAPParser::resp_text_code* resp_text_code() const { return (m_resp_text_code); }
- const string& text() const { return (m_text); }
- };
-
-
- //
- // continue_req ::= "+" SPACE (resp_text / base64)
- //
-
- class continue_req : public component
- {
- public:
-
- continue_req()
- : m_resp_text(NULL)
- {
- }
-
- ~continue_req()
- {
- delete (m_resp_text);
- }
-
- void go(IMAPParser& parser, string& line, string::size_type* currentPos)
- {
- DEBUG_ENTER_COMPONENT("continue_req");
-
- string::size_type pos = *currentPos;
-
- parser.check <one_char <'+'> >(line, &pos);
- parser.check <SPACE>(line, &pos);
-
- m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
-
- parser.check <CRLF>(line, &pos);
-
- *currentPos = pos;
- }
-
- private:
-
- IMAPParser::resp_text* m_resp_text;
-
- public:
-
- const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
- };
-
-
- //
// auth_type ::= atom
// ;; Defined by [IMAP-AUTH]
//
@@ -1965,6 +1927,13 @@ public:
// ("UIDVALIDITY" SP nz-number) /
// ("UNSEEN" SP number)
//
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // status-att-val =/ "HIGHESTMODSEQ" SP mod-sequence-valzer
+ // ;; extends non-terminal defined in [IMAPABNF].
+ // ;; Value 0 denotes that the mailbox doesn't
+ // ;; support persistent mod-sequences
+ //
class status_att_val : public component
{
@@ -1976,30 +1945,41 @@ public:
string::size_type pos = *currentPos;
- if (parser.checkWithArg <special_atom>(line, &pos, "messages", true))
- {
- m_type = MESSAGES;
- }
- else if (parser.checkWithArg <special_atom>(line, &pos, "recent", true))
- {
- m_type = RECENT;
- }
- else if (parser.checkWithArg <special_atom>(line, &pos, "uidnext", true))
- {
- m_type = UIDNEXT;
- }
- else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true))
+ // "HIGHESTMODSEQ" SP mod-sequence-valzer
+ if (parser.checkWithArg <special_atom>(line, &pos, "highestmodseq", true))
{
- m_type = UIDVALIDITY;
+ m_type = HIGHESTMODSEQ;
+
+ parser.check <SPACE>(line, &pos);
+ m_value = parser.get <IMAPParser::mod_sequence_value>(line, &pos);
}
else
{
- parser.checkWithArg <special_atom>(line, &pos, "unseen");
- m_type = UNSEEN;
- }
+ if (parser.checkWithArg <special_atom>(line, &pos, "messages", true))
+ {
+ m_type = MESSAGES;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "recent", true))
+ {
+ m_type = RECENT;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidnext", true))
+ {
+ m_type = UIDNEXT;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true))
+ {
+ m_type = UIDVALIDITY;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "unseen");
+ m_type = UNSEEN;
+ }
- parser.check <SPACE>(line, &pos);
- m_value = parser.get <IMAPParser::number>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_value = parser.get <IMAPParser::number>(line, &pos);
+ }
*currentPos = pos;
}
@@ -2007,6 +1987,10 @@ public:
enum Type
{
+ // Extensions
+ HIGHESTMODSEQ,
+
+ // Standard IMAP
MESSAGES,
RECENT,
UIDNEXT,
@@ -2027,6 +2011,11 @@ public:
{
return dynamic_cast <IMAPParser::number *>(m_value);
}
+
+ const IMAPParser::mod_sequence_value* value_as_mod_sequence_value() const
+ {
+ return dynamic_cast <IMAPParser::mod_sequence_value *>(m_value);
+ }
};
@@ -3882,6 +3871,9 @@ public:
// "BODY" section ["<" number ">"] SPACE nstring /
// "UID" SPACE uniqueid
//
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // msg_att_item /= "MODSEQ" SP "(" mod_sequence_value ")"
class msg_att_item : public component
{
@@ -3890,7 +3882,7 @@ public:
msg_att_item()
: m_date_time(NULL), m_number(NULL), m_envelope(NULL),
m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL),
- m_section(NULL)
+ m_section(NULL), m_mod_sequence_value(NULL)
{
}
@@ -3905,6 +3897,7 @@ public:
delete (m_body);
delete (m_flag_list);
delete (m_section);
+ delete m_mod_sequence_value;
}
void go(IMAPParser& parser, string& line, string::size_type* currentPos)
@@ -4015,6 +4008,18 @@ public:
m_body = parser.get <IMAPParser::body>(line, &pos);
}
}
+ // "MODSEQ" SP "(" mod_sequence_value ")"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "modseq", true))
+ {
+ m_type = MODSEQ;
+
+ parser.check <SPACE>(line, &pos);
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_mod_sequence_value = parser.get <IMAPParser::mod_sequence_value>(line, &pos);
+
+ parser.check <one_char <')'> >(line, &pos);
+ }
// "UID" SPACE uniqueid
else
{
@@ -4042,7 +4047,8 @@ public:
BODY,
BODY_SECTION,
BODY_STRUCTURE,
- UID
+ UID,
+ MODSEQ
};
private:
@@ -4057,6 +4063,7 @@ public:
IMAPParser::xbody* m_body;
IMAPParser::flag_list* m_flag_list;
IMAPParser::section* m_section;
+ IMAPParser::mod_sequence_value* m_mod_sequence_value;
public:
@@ -4070,6 +4077,7 @@ public:
const IMAPParser::xbody* body() const { return (m_body); }
const IMAPParser::flag_list* flag_list() const { return (m_flag_list); }
const IMAPParser::section* section() const { return (m_section); }
+ const IMAPParser::mod_sequence_value* mod_sequence_value() { return m_mod_sequence_value; }
};
@@ -4189,6 +4197,307 @@ public:
//
+ // resp_text_code ::= "ALERT" / "PARSE" /
+ // capability-data /
+ // "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
+ // "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
+ // "UIDVALIDITY" SPACE nz_number /
+ // "UNSEEN" SPACE nz_number /
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+ //
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // resp-text-code =/ "HIGHESTMODSEQ" SP mod-sequence-value /
+ // "NOMODSEQ" /
+ // "MODIFIED" SP set
+
+ class resp_text_code : public component
+ {
+ public:
+
+ resp_text_code()
+ : m_nz_number(NULL), m_atom(NULL), m_flag_list(NULL),
+ m_text(NULL), m_capability_data(NULL)
+ {
+ }
+
+ ~resp_text_code()
+ {
+ delete (m_nz_number);
+ delete (m_atom);
+ delete (m_flag_list);
+ delete (m_text);
+ delete m_capability_data;
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_text_code");
+
+ string::size_type pos = *currentPos;
+
+ // "ALERT"
+ if (parser.checkWithArg <special_atom>(line, &pos, "alert", true))
+ {
+ m_type = ALERT;
+ }
+ // "PARSE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "parse", true))
+ {
+ m_type = PARSE;
+ }
+ // capability_data
+ else if ((m_capability_data = parser.get <IMAPParser::capability_data>(line, &pos, true)))
+ {
+ m_type = CAPABILITY;
+ }
+ // "PERMANENTFLAGS" SPACE flag_list
+ else if (parser.checkWithArg <special_atom>(line, &pos, "permanentflags", true))
+ {
+ m_type = PERMANENTFLAGS;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_flag_list = parser.get <IMAPParser::flag_list>(line, &pos);
+ }
+ // "READ-ONLY"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "read-only", true))
+ {
+ m_type = READ_ONLY;
+ }
+ // "READ-WRITE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "read-write", true))
+ {
+ m_type = READ_WRITE;
+ }
+ // "TRYCREATE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "trycreate", true))
+ {
+ m_type = TRYCREATE;
+ }
+ // "UIDVALIDITY" SPACE nz_number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true))
+ {
+ m_type = UIDVALIDITY;
+
+ parser.check <SPACE>(line, &pos);
+ m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
+ }
+ // "UIDNEXT" SPACE nz_number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidnext", true))
+ {
+ m_type = UIDNEXT;
+
+ parser.check <SPACE>(line, &pos);
+ m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
+ }
+ // "UNSEEN" SPACE nz_number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "unseen", true))
+ {
+ m_type = UNSEEN;
+
+ parser.check <SPACE>(line, &pos);
+ m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
+ }
+ // "HIGHESTMODSEQ" SP mod-sequence-value
+ else if (parser.checkWithArg <special_atom>(line, &pos, "highestmodseq", true))
+ {
+ m_type = HIGHESTMODSEQ;
+
+ parser.check <SPACE>(line, &pos);
+ m_mod_sequence_value = parser.get <IMAPParser::mod_sequence_value>(line, &pos);
+ }
+ // "NOMODSEQ"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "nomodseq", true))
+ {
+ m_type = NOMODSEQ;
+ }
+ // "MODIFIED" SP sequence-set
+ else if (parser.checkWithArg <special_atom>(line, &pos, "modified", true))
+ {
+ m_type = MODIFIED;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_sequence_set = parser.get <IMAPParser::sequence_set>(line, &pos);
+ }
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+ else
+ {
+ m_type = OTHER;
+
+ m_atom = parser.get <IMAPParser::atom>(line, &pos);
+
+ if (parser.check <SPACE>(line, &pos, true))
+ m_text = parser.get <text_except <']'> >(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ // Extensions
+ HIGHESTMODSEQ,
+ NOMODSEQ,
+ MODIFIED,
+
+ // Standard IMAP
+ ALERT,
+ PARSE,
+ CAPABILITY,
+ PERMANENTFLAGS,
+ READ_ONLY,
+ READ_WRITE,
+ TRYCREATE,
+ UIDVALIDITY,
+ UIDNEXT,
+ UNSEEN,
+ OTHER
+ };
+
+ private:
+
+ Type m_type;
+
+ IMAPParser::nz_number* m_nz_number;
+ IMAPParser::atom* m_atom;
+ IMAPParser::flag_list* m_flag_list;
+ IMAPParser::text* m_text;
+ IMAPParser::mod_sequence_value* m_mod_sequence_value;
+ IMAPParser::sequence_set* m_sequence_set;
+ IMAPParser::capability_data* m_capability_data;
+
+ public:
+
+ Type type() const { return (m_type); }
+
+ const IMAPParser::nz_number* nz_number() const { return (m_nz_number); }
+ const IMAPParser::atom* atom() const { return (m_atom); }
+ const IMAPParser::flag_list* flag_list() const { return (m_flag_list); }
+ const IMAPParser::text* text() const { return (m_text); }
+ const IMAPParser::mod_sequence_value* mod_sequence_value() const { return m_mod_sequence_value; }
+ const IMAPParser::sequence_set* sequence_set() const { return m_sequence_set; }
+ const IMAPParser::capability_data* capability_data() const { return m_capability_data; }
+ };
+
+
+ //
+ // resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
+ // ;; text SHOULD NOT begin with "[" or "="
+
+ class resp_text : public component
+ {
+ public:
+
+ resp_text()
+ : m_resp_text_code(NULL)
+ {
+ }
+
+ ~resp_text()
+ {
+ delete (m_resp_text_code);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_text");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'['> >(line, &pos, true))
+ {
+ m_resp_text_code = parser.get <IMAPParser::resp_text_code>(line, &pos);
+
+ parser.check <one_char <']'> >(line, &pos);
+ parser.check <SPACE>(line, &pos, true);
+ }
+
+ text_mime2* text1 = parser.get <text_mime2>(line, &pos, true);
+
+ if (text1 != NULL)
+ {
+ m_text = text1->value();
+ delete (text1);
+ }
+ else
+ {
+ IMAPParser::text* text2 =
+ parser.get <IMAPParser::text>(line, &pos, true);
+
+ if (text2 != NULL)
+ {
+ m_text = text2->value();
+ delete (text2);
+ }
+ else
+ {
+ // Empty response text
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_text_code* m_resp_text_code;
+ string m_text;
+
+ public:
+
+ const IMAPParser::resp_text_code* resp_text_code() const { return (m_resp_text_code); }
+ const string& text() const { return (m_text); }
+ };
+
+
+ //
+ // continue_req ::= "+" SPACE (resp_text / base64)
+ //
+
+ class continue_req : public component
+ {
+ public:
+
+ continue_req()
+ : m_resp_text(NULL)
+ {
+ }
+
+ ~continue_req()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("continue_req");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'+'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_text* m_resp_text;
+
+ public:
+
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ };
+
+
+ //
// resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
// ;; Status condition
//
diff --git a/vmime/net/imap/IMAPStore.hpp b/vmime/net/imap/IMAPStore.hpp
index 6a06fdc9..e6b27d8d 100644
--- a/vmime/net/imap/IMAPStore.hpp
+++ b/vmime/net/imap/IMAPStore.hpp
@@ -86,6 +86,7 @@ public:
bool isSecuredConnection() const;
ref <connectionInfos> getConnectionInfos() const;
+ ref <IMAPConnection> getConnection();
protected:
diff --git a/vmime/net/imap/IMAPUtils.hpp b/vmime/net/imap/IMAPUtils.hpp
index aea02ef9..591db3f3 100644
--- a/vmime/net/imap/IMAPUtils.hpp
+++ b/vmime/net/imap/IMAPUtils.hpp
@@ -37,6 +37,7 @@
#include "vmime/net/folder.hpp"
#include "vmime/net/message.hpp"
#include "vmime/net/imap/IMAPParser.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
#include "vmime/mailboxList.hpp"
@@ -104,19 +105,23 @@ public:
/** Construct a fetch request for the specified messages, designated by their sequence numbers.
*
+ * @param cnt connection
* @param list list of message numbers
* @param options fetch options
* @return fetch request
*/
- static const string buildFetchRequest(const std::vector <int>& list, const int options);
+ static const string buildFetchRequest
+ (ref <IMAPConnection> cnt, const std::vector <int>& list, const int options);
/** Construct a fetch request for the specified messages, designated by their UIDs.
*
+ * @param cnt connection
* @param list list of message UIDs
* @param options fetch options
* @return fetch request
*/
- static const string buildFetchRequest(const std::vector <message::uid>& list, const int options);
+ static const string buildFetchRequest
+ (ref <IMAPConnection> cnt, const std::vector <message::uid>& list, const int options);
/** Convert a parser-style address list to a mailbox list.
*
@@ -130,7 +135,7 @@ public:
* @param uid globally unique UID (as returned by makeGlobalUID(), for example)
* @return message UID
*/
- static unsigned int extractUIDFromGlobalUID(const message::uid& uid);
+ static vmime_uint32 extractUIDFromGlobalUID(const message::uid& uid);
/** Construct a globally unique UID from UID Validity and a message UID.
*
@@ -138,12 +143,12 @@ public:
* @param messageUID UID of the message
* @return global UID
*/
- static const message::uid makeGlobalUID(const unsigned int UIDValidity, const unsigned int messageUID);
+ static const message::uid makeGlobalUID(const vmime_uint32 UIDValidity, const vmime_uint32 messageUID);
private:
static const string buildFetchRequestImpl
- (const string& mode, const string& set, const int options);
+ (ref <IMAPConnection> cnt, const string& mode, const string& set, const int options);
};
diff --git a/vmime/net/maildir/maildirFolder.hpp b/vmime/net/maildir/maildirFolder.hpp
index 8a418268..940fcaae 100644
--- a/vmime/net/maildir/maildirFolder.hpp
+++ b/vmime/net/maildir/maildirFolder.hpp
@@ -117,6 +117,7 @@ public:
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
void status(int& count, int& unseen);
+ ref <folderStatus> getStatus();
void expunge();
diff --git a/vmime/net/maildir/maildirFolderStatus.hpp b/vmime/net/maildir/maildirFolderStatus.hpp
new file mode 100644
index 00000000..80018b14
--- /dev/null
+++ b/vmime/net/maildir/maildirFolderStatus.hpp
@@ -0,0 +1,70 @@
+//
+// 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.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/folderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+/** Holds the status of a Maildir folder.
+ */
+
+class VMIME_EXPORT maildirFolderStatus : public folderStatus
+{
+public:
+
+ // Inherited from folderStatus
+ unsigned int getMessageCount() const;
+ unsigned int getUnseenCount() const;
+
+ void setMessageCount(const unsigned int count);
+ void setUnseenCount(const unsigned int unseen);
+
+private:
+
+ unsigned int m_count;
+ unsigned int m_unseen;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime/net/maildir/maildirMessage.hpp b/vmime/net/maildir/maildirMessage.hpp
index 4efc2eed..de8c1751 100644
--- a/vmime/net/maildir/maildirMessage.hpp
+++ b/vmime/net/maildir/maildirMessage.hpp
@@ -62,7 +62,7 @@ public:
int getNumber() const;
- const uid getUniqueId() const;
+ const uid getUID() const;
int getSize() const;
diff --git a/vmime/net/message.hpp b/vmime/net/message.hpp
index 288e08a2..3b94fbf3 100644
--- a/vmime/net/message.hpp
+++ b/vmime/net/message.hpp
@@ -204,11 +204,12 @@ public:
*/
virtual int getNumber() const = 0;
- /** Return the unique identified of this message (must fetch before).
+ /** Return the unique identifier (UID) of this message in its
+ * folder (must fetch before).
*
* @return UID of the message
*/
- virtual const uid getUniqueId() const = 0;
+ virtual const uid getUID() const = 0;
/** Return the size of the message (must fetch before).
*
diff --git a/vmime/net/pop3/POP3Folder.hpp b/vmime/net/pop3/POP3Folder.hpp
index 952b8580..8a97213c 100644
--- a/vmime/net/pop3/POP3Folder.hpp
+++ b/vmime/net/pop3/POP3Folder.hpp
@@ -114,6 +114,7 @@ public:
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
void status(int& count, int& unseen);
+ ref <folderStatus> getStatus();
void expunge();
diff --git a/vmime/net/pop3/POP3FolderStatus.hpp b/vmime/net/pop3/POP3FolderStatus.hpp
new file mode 100644
index 00000000..3e5d15a1
--- /dev/null
+++ b/vmime/net/pop3/POP3FolderStatus.hpp
@@ -0,0 +1,70 @@
+//
+// 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.
+//
+
+#ifndef VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/folderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+/** Holds the status of a POP3 folder.
+ */
+
+class VMIME_EXPORT POP3FolderStatus : public folderStatus
+{
+public:
+
+ // Inherited from folderStatus
+ unsigned int getMessageCount() const;
+ unsigned int getUnseenCount() const;
+
+ void setMessageCount(const unsigned int count);
+ void setUnseenCount(const unsigned int unseen);
+
+private:
+
+ unsigned int m_count;
+ unsigned int m_unseen;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime/net/pop3/POP3Message.hpp b/vmime/net/pop3/POP3Message.hpp
index c415e8a7..31b26154 100644
--- a/vmime/net/pop3/POP3Message.hpp
+++ b/vmime/net/pop3/POP3Message.hpp
@@ -62,7 +62,7 @@ public:
int getNumber() const;
- const uid getUniqueId() const;
+ const uid getUID() const;
int getSize() const;