aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Richard <[email protected]>2012-07-28 11:01:48 +0000
committerVincent Richard <[email protected]>2012-07-28 11:01:48 +0000
commita68cebf12a775f43b39f8b46851644699320f487 (patch)
tree59dcf20bbddf00f88da2fab8fcabbdbb84408063
parentFixed issue #10. (diff)
downloadvmime-a68cebf12a775f43b39f8b46851644699320f487.tar.gz
vmime-a68cebf12a775f43b39f8b46851644699320f487.zip
Added functions to get messages by UID (IMAP only for now).
-rw-r--r--src/net/imap/IMAPFolder.cpp109
-rw-r--r--src/net/imap/IMAPMessage.cpp28
-rw-r--r--src/net/imap/IMAPUtils.cpp80
-rw-r--r--src/net/maildir/maildirFolder.cpp12
-rw-r--r--src/net/pop3/POP3Folder.cpp12
-rw-r--r--vmime/net/folder.hpp24
-rw-r--r--vmime/net/imap/IMAPFolder.hpp10
-rw-r--r--vmime/net/imap/IMAPMessage.hpp3
-rw-r--r--vmime/net/imap/IMAPUtils.hpp42
-rw-r--r--vmime/net/maildir/maildirFolder.hpp4
-rw-r--r--vmime/net/pop3/POP3Folder.hpp4
11 files changed, 301 insertions, 27 deletions
diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp
index 81bf3861..3d8c17ea 100644
--- a/src/net/imap/IMAPFolder.cpp
+++ b/src/net/imap/IMAPFolder.cpp
@@ -208,7 +208,7 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable)
{
case IMAPParser::resp_text_code::UIDVALIDITY:
- m_uidValidity = code->nz_number()->value();
+ m_uidValidity = static_cast <unsigned int>(code->nz_number()->value());
break;
default:
@@ -550,6 +550,109 @@ std::vector <ref <message> > IMAPFolder::getMessages(const std::vector <int>& nu
}
+ref <message> IMAPFolder::getMessageByUID(const message::uid& uid)
+{
+ std::vector <message::uid> uids;
+ uids.push_back(uid);
+
+ std::vector <ref <message> > msgs = getMessagesByUID(uids);
+
+ if (msgs.size() == 0)
+ throw exceptions::message_not_found();
+
+ return msgs[0];
+}
+
+
+std::vector <ref <message> > IMAPFolder::getMessagesByUID(const std::vector <message::uid>& uids)
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ if (uids.size() == 0)
+ return std::vector <ref <message> >();
+
+ // C: . UID FETCH uuuu1,uuuu2,uuuu3 UID
+ // S: * nnnn1 FETCH (UID uuuu1)
+ // S: * nnnn2 FETCH (UID uuuu2)
+ // S: * nnnn3 FETCH (UID uuuu3)
+ // S: . OK UID FETCH completed
+
+ // Prepare command and arguments
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ cmd << "UID FETCH " << IMAPUtils::extractUIDFromGlobalUID(uids[0]);
+
+ for (unsigned int i = 1, n = uids.size() ; i < n ; ++i)
+ cmd << "," << IMAPUtils::extractUIDFromGlobalUID(uids[i]);
+
+ cmd << " UID";
+
+ // Send the request
+ m_connection->send(true, cmd.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("UID FETCH ... UID", m_connection->getParser()->lastLine(), "bad response");
+ }
+
+ // Process the response
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+ std::vector <ref <message> > messages;
+
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
+ {
+ if ((*it)->response_data() == NULL)
+ {
+ throw exceptions::command_error("UID FETCH ... UID",
+ m_connection->getParser()->lastLine(), "invalid response");
+ }
+
+ const IMAPParser::message_data* messageData =
+ (*it)->response_data()->message_data();
+
+ // We are only interested in responses of type "FETCH"
+ if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH)
+ continue;
+
+ // Get Process fetch response for this message
+ const int msgNum = static_cast <int>(messageData->number());
+ message::uid msgUID, msgFullUID;
+
+ // Find UID in message attributes
+ const std::vector <IMAPParser::msg_att_item*> atts = messageData->msg_att()->items();
+
+ for (std::vector <IMAPParser::msg_att_item*>::const_iterator
+ it = atts.begin() ; it != atts.end() ; ++it)
+ {
+ if ((*it)->type() == IMAPParser::msg_att_item::UID)
+ {
+ msgFullUID = IMAPUtils::makeGlobalUID(m_uidValidity, (*it)->unique_id()->value());
+ msgUID = (*it)->unique_id()->value();
+
+ break;
+ }
+ }
+
+ if (!msgUID.empty())
+ {
+ ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
+ messages.push_back(vmime::create <IMAPMessage>(thisFolder, msgNum, msgFullUID));
+ }
+ }
+
+ return messages;
+}
+
+
int IMAPFolder::getMessageCount()
{
if (!isOpen())
@@ -730,7 +833,7 @@ void IMAPFolder::fetchMessages(std::vector <ref <message> >& msg, const int opti
if (msg != numberToMsg.end())
{
- (*msg).second->processFetchResponse(options, messageData->msg_att());
+ (*msg).second->processFetchResponse(options, messageData);
if (progress)
progress->progress(++current, total);
@@ -1781,7 +1884,7 @@ std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid&
std::ostringstream command;
command.imbue(std::locale::classic());
- command << "SEARCH UID " << uid;
+ command << "SEARCH UID " << uid << ":*";
// Send the request
m_connection->send(true, command.str(), true);
diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp
index 8006920c..7202a7d2 100644
--- a/src/net/imap/IMAPMessage.cpp
+++ b/src/net/imap/IMAPMessage.cpp
@@ -98,6 +98,14 @@ IMAPMessage::IMAPMessage(ref <IMAPFolder> folder, const int num)
}
+IMAPMessage::IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uniqueId)
+ : m_folder(folder), m_num(num), m_size(-1), m_flags(FLAG_UNDEFINED),
+ m_expunged(false), m_uid(uniqueId), m_structure(NULL)
+{
+ folder->registerMessage(this);
+}
+
+
IMAPMessage::~IMAPMessage()
{
ref <IMAPFolder> folder = m_folder.acquire();
@@ -271,7 +279,11 @@ void IMAPMessage::extract(ref <const part> p, utility::outputStream& os,
std::ostringstream command;
command.imbue(std::locale::classic());
- command << "FETCH " << m_num << " BODY";
+ if (m_uid.empty())
+ command << "FETCH " << m_num << " BODY";
+ else
+ command << "UID FETCH " << IMAPUtils::extractUIDFromGlobalUID(m_uid) << " BODY";
+
if (peek) command << ".PEEK";
command << "[";
@@ -361,19 +373,18 @@ void IMAPMessage::fetch(ref <IMAPFolder> msgFolder, const int options)
continue;
// Process fetch response for this message
- processFetchResponse(options, messageData->msg_att());
+ processFetchResponse(options, messageData);
}
}
void IMAPMessage::processFetchResponse
- (const int options, const IMAPParser::msg_att* msgAtt)
+ (const int options, const IMAPParser::message_data* msgData)
{
ref <IMAPFolder> folder = m_folder.acquire();
// Get message attributes
- const std::vector <IMAPParser::msg_att_item*> atts =
- msgAtt->items();
+ const std::vector <IMAPParser::msg_att_item*> atts = msgData->msg_att()->items();
int flags = 0;
@@ -389,12 +400,7 @@ void IMAPMessage::processFetchResponse
}
case IMAPParser::msg_att_item::UID:
{
- std::ostringstream oss;
- oss.imbue(std::locale::classic());
-
- oss << folder->m_uidValidity << ":" << (*it)->unique_id()->value();
-
- m_uid = oss.str();
+ m_uid = IMAPUtils::makeGlobalUID(folder->m_uidValidity, (*it)->unique_id()->value());
break;
}
case IMAPParser::msg_att_item::ENVELOPE:
diff --git a/src/net/imap/IMAPUtils.cpp b/src/net/imap/IMAPUtils.cpp
index 0d6fc478..eceac16b 100644
--- a/src/net/imap/IMAPUtils.cpp
+++ b/src/net/imap/IMAPUtils.cpp
@@ -540,6 +540,24 @@ const string IMAPUtils::listToSet(const std::vector <int>& list, const int max,
// static
+const string IMAPUtils::listToSet(const std::vector <message::uid>& list)
+{
+ if (list.size() == 0)
+ return "";
+
+ std::ostringstream res;
+ res.imbue(std::locale::classic());
+
+ res << extractUIDFromGlobalUID(list[0]);
+
+ for (unsigned int i = 1, n = list.size() ; i < n ; ++i)
+ res << "," << extractUIDFromGlobalUID(list[i]);
+
+ return res.str();
+}
+
+
+// static
const string IMAPUtils::dateTime(const vmime::datetime& date)
{
std::ostringstream res;
@@ -609,7 +627,8 @@ const string IMAPUtils::dateTime(const vmime::datetime& date)
// static
-const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const int options)
+const string IMAPUtils::buildFetchRequestImpl
+ (const std::string& mode, const std::string& set, const int options)
{
// Example:
// C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
@@ -671,7 +690,10 @@ const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const i
std::ostringstream command;
command.imbue(std::locale::classic());
- command << "FETCH " << listToSet(list, -1, false) << " (";
+ if (mode == "uid")
+ command << "UID FETCH " << set << " (";
+ else
+ command << "FETCH " << set << " (";
for (std::vector <string>::const_iterator it = items.begin() ;
it != items.end() ; ++it)
@@ -687,6 +709,20 @@ const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const i
// static
+const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const int options)
+{
+ return buildFetchRequestImpl("number", listToSet(list, -1, false), options);
+}
+
+
+// static
+const string IMAPUtils::buildFetchRequest(const std::vector <message::uid>& list, const int options)
+{
+ return buildFetchRequestImpl("uid", listToSet(list), options);
+}
+
+
+// static
void IMAPUtils::convertAddressList
(const IMAPParser::address_list& src, mailboxList& dest)
{
@@ -706,6 +742,46 @@ void IMAPUtils::convertAddressList
}
+// static
+unsigned int IMAPUtils::extractUIDFromGlobalUID(const message::uid& uid)
+{
+ message::uid::size_type colonPos = uid.find(':');
+
+ if (colonPos == message::uid::npos)
+ {
+ std::istringstream iss(uid);
+ iss.imbue(std::locale::classic());
+
+ unsigned int n = 0;
+ iss >> n;
+
+ return n;
+ }
+ else
+ {
+ std::istringstream iss(uid.substr(colonPos + 1));
+ iss.imbue(std::locale::classic());
+
+ unsigned int n = 0;
+ iss >> n;
+
+ return n;
+ }
+}
+
+
+// static
+const message::uid IMAPUtils::makeGlobalUID(const unsigned int UIDValidity, const unsigned int messageUID)
+{
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+
+ oss << UIDValidity << ":" << messageUID;
+
+ return message::uid(oss.str());
+}
+
+
} // imap
} // net
} // vmime
diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp
index 8c4b2758..b606cda0 100644
--- a/src/net/maildir/maildirFolder.cpp
+++ b/src/net/maildir/maildirFolder.cpp
@@ -444,6 +444,18 @@ std::vector <ref <message> > maildirFolder::getMessages(const std::vector <int>&
}
+ref <message> maildirFolder::getMessageByUID(const message::uid& /* uid */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+std::vector <ref <message> > maildirFolder::getMessagesByUID(const std::vector <message::uid>& /* uids */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
int maildirFolder::getMessageCount()
{
return (m_messageCount);
diff --git a/src/net/pop3/POP3Folder.cpp b/src/net/pop3/POP3Folder.cpp
index e0856090..21e7a8b3 100644
--- a/src/net/pop3/POP3Folder.cpp
+++ b/src/net/pop3/POP3Folder.cpp
@@ -249,6 +249,18 @@ std::vector <ref <message> > POP3Folder::getMessages(const int from, const int t
}
+ref <message> POP3Folder::getMessageByUID(const message::uid& /* uid */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+std::vector <ref <message> > POP3Folder::getMessagesByUID(const std::vector <message::uid>& /* uids */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
std::vector <ref <message> > POP3Folder::getMessages(const std::vector <int>& nums)
{
ref <POP3Store> store = m_store.acquire();
diff --git a/vmime/net/folder.hpp b/vmime/net/folder.hpp
index df9cbaf5..a50ee0e5 100644
--- a/vmime/net/folder.hpp
+++ b/vmime/net/folder.hpp
@@ -169,7 +169,7 @@ public:
*/
virtual bool isOpen() const = 0;
- /** Get a new reference to a message in this folder.
+ /** Get a new reference to a message in this folder, given its number.
*
* @param num message sequence number
* @return a new object referencing the specified message
@@ -177,7 +177,7 @@ public:
*/
virtual ref <message> getMessage(const int num) = 0;
- /** Get new references to messages in this folder.
+ /** Get new references to messages in this folder, given their numbers.
*
* @param from sequence number of the first message to get
* @param to sequence number of the last message to get
@@ -186,14 +186,30 @@ public:
*/
virtual std::vector <ref <message> > getMessages(const int from = 1, const int to = -1) = 0;
- /** Get new references to messages in this folder.
+ /** Get new references to messages in this folder, given their numbers.
*
- * @param nums sequence numbers of the messages to delete
+ * @param nums sequence numbers of the messages to retrieve
* @return new objects referencing the specified messages
* @throw net_exception if an error occurs
*/
virtual std::vector <ref <message> > getMessages(const std::vector <int>& nums) = 0;
+ /** Get message in this folder, given its UID.
+ *
+ * @param uid UID of message to retrieve
+ * @return a new object referencing the specified message
+ * @throw net_exception if an error occurs
+ */
+ virtual ref <message> getMessageByUID(const message::uid& uid) = 0;
+
+ /** Get messages in this folder, given their UIDs.
+ *
+ * @param uids UIDs of messages to retrieve
+ * @return new objects referencing the specified messages
+ * @throw net_exception if an error occurs
+ */
+ virtual std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids) = 0;
+
/** Return the number of messages in this folder.
*
* @return number of messages in the folder
diff --git a/vmime/net/imap/IMAPFolder.hpp b/vmime/net/imap/IMAPFolder.hpp
index cc52596f..33378581 100644
--- a/vmime/net/imap/IMAPFolder.hpp
+++ b/vmime/net/imap/IMAPFolder.hpp
@@ -84,6 +84,12 @@ public:
ref <message> getMessage(const int num);
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
+
+ ref <message> getMessageByUID(const message::uid& uid);
+ std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids);
+
+ std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid);
+
int getMessageCount();
ref <folder> getFolder(const folder::path::component& name);
@@ -120,8 +126,6 @@ public:
int getFetchCapabilities() const;
- std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid);
-
private:
void registerMessage(IMAPMessage* msg);
@@ -152,7 +156,7 @@ private:
int m_messageCount;
- int m_uidValidity;
+ unsigned int m_uidValidity;
std::vector <IMAPMessage*> m_messages;
};
diff --git a/vmime/net/imap/IMAPMessage.hpp b/vmime/net/imap/IMAPMessage.hpp
index edbf69ff..fbba6e7d 100644
--- a/vmime/net/imap/IMAPMessage.hpp
+++ b/vmime/net/imap/IMAPMessage.hpp
@@ -50,6 +50,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(const IMAPMessage&) : message() { }
~IMAPMessage();
@@ -83,7 +84,7 @@ private:
void fetch(ref <IMAPFolder> folder, const int options);
- void processFetchResponse(const int options, const IMAPParser::msg_att* msgAtt);
+ void processFetchResponse(const int options, const IMAPParser::message_data* msgData);
/** Recursively fetch part header for all parts in the structure.
*
diff --git a/vmime/net/imap/IMAPUtils.hpp b/vmime/net/imap/IMAPUtils.hpp
index d1ed5c86..9c9c4205 100644
--- a/vmime/net/imap/IMAPUtils.hpp
+++ b/vmime/net/imap/IMAPUtils.hpp
@@ -29,6 +29,7 @@
#include "vmime/dateTime.hpp"
#include "vmime/net/folder.hpp"
+#include "vmime/net/message.hpp"
#include "vmime/net/imap/IMAPParser.hpp"
#include "vmime/mailboxList.hpp"
@@ -65,8 +66,8 @@ public:
static const string messageFlagList(const int flags);
- /** Build an "IMAP set" given a list. The function tries to group
- * consecutive message numbers to reduce the list.
+ /** Build an "IMAP set" given a list of message numbers. The function tries
+ * to group consecutive message numbers to reduce the list.
*
* Example:
* IN = "1,2,3,4,5,7,8,13,15,16,17"
@@ -81,6 +82,13 @@ public:
static const string listToSet(const std::vector <int>& list,
const int max = -1, const bool alreadySorted = false);
+ /** Build an "IMAP set" set given a list of message UIDs.
+ *
+ * @param list list of message UIDs
+ * @return a set corresponding to the list
+ */
+ static const string listToSet(const std::vector <message::uid>& list);
+
/** Format a date/time to IMAP date/time format.
*
* @param date date/time to format
@@ -88,7 +96,7 @@ public:
*/
static const string dateTime(const vmime::datetime& date);
- /** Construct a fetch request for the specified messages.
+ /** Construct a fetch request for the specified messages, designated by their sequence numbers.
*
* @param list list of message numbers
* @param options fetch options
@@ -96,12 +104,40 @@ public:
*/
static const string buildFetchRequest(const std::vector <int>& list, const int options);
+ /** Construct a fetch request for the specified messages, designated by their UIDs.
+ *
+ * @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);
+
/** Convert a parser-style address list to a mailbox list.
*
* @param src input address list
* @param dest output mailbox list
*/
static void convertAddressList(const IMAPParser::address_list& src, mailboxList& dest);
+
+ /** Extract the message UID from a globally unique UID.
+ *
+ * @param uid globally unique UID (as returned by makeGlobalUID(), for example)
+ * @return message UID
+ */
+ static unsigned int extractUIDFromGlobalUID(const message::uid& uid);
+
+ /** Construct a globally unique UID from UID Validity and a message UID.
+ *
+ * @param UIDValidity UID Validity of the folder
+ * @param messageUID UID of the message
+ * @return global UID
+ */
+ static const message::uid makeGlobalUID(const unsigned int UIDValidity, const unsigned int messageUID);
+
+private:
+
+ static const string buildFetchRequestImpl
+ (const std::string& mode, const std::string& set, const int options);
};
diff --git a/vmime/net/maildir/maildirFolder.hpp b/vmime/net/maildir/maildirFolder.hpp
index 68b5b898..c9ba8996 100644
--- a/vmime/net/maildir/maildirFolder.hpp
+++ b/vmime/net/maildir/maildirFolder.hpp
@@ -85,6 +85,10 @@ public:
ref <message> getMessage(const int num);
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
+
+ ref <message> getMessageByUID(const message::uid& uid);
+ std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids);
+
int getMessageCount();
ref <folder> getFolder(const folder::path::component& name);
diff --git a/vmime/net/pop3/POP3Folder.hpp b/vmime/net/pop3/POP3Folder.hpp
index c4829085..090f948b 100644
--- a/vmime/net/pop3/POP3Folder.hpp
+++ b/vmime/net/pop3/POP3Folder.hpp
@@ -83,6 +83,10 @@ public:
ref <message> getMessage(const int num);
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
+
+ ref <message> getMessageByUID(const message::uid& uid);
+ std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids);
+
int getMessageCount();
ref <folder> getFolder(const folder::path::component& name);