aboutsummaryrefslogtreecommitdiffstats
path: root/src
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 /src
parentFixed issue #10. (diff)
downloadvmime-a68cebf12a775f43b39f8b46851644699320f487.tar.gz
vmime-a68cebf12a775f43b39f8b46851644699320f487.zip
Added functions to get messages by UID (IMAP only for now).
Diffstat (limited to 'src')
-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
5 files changed, 225 insertions, 16 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();