diff options
author | Vincent Richard <[email protected]> | 2012-07-28 11:01:48 +0000 |
---|---|---|
committer | Vincent Richard <[email protected]> | 2012-07-28 11:01:48 +0000 |
commit | a68cebf12a775f43b39f8b46851644699320f487 (patch) | |
tree | 59dcf20bbddf00f88da2fab8fcabbdbb84408063 /src | |
parent | Fixed issue #10. (diff) | |
download | vmime-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.cpp | 109 | ||||
-rw-r--r-- | src/net/imap/IMAPMessage.cpp | 28 | ||||
-rw-r--r-- | src/net/imap/IMAPUtils.cpp | 80 | ||||
-rw-r--r-- | src/net/maildir/maildirFolder.cpp | 12 | ||||
-rw-r--r-- | src/net/pop3/POP3Folder.cpp | 12 |
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(); |