Added functions to get messages by UID (IMAP only for now).
This commit is contained in:
parent
891aba49ff
commit
a68cebf12a
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -539,6 +539,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)
|
||||
{
|
||||
@ -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)
|
||||
@ -686,6 +708,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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user