aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/net/imap/IMAPFolder.cpp68
-rw-r--r--src/net/imap/IMAPMessage.cpp77
-rw-r--r--src/net/imap/IMAPUtils.cpp87
3 files changed, 149 insertions, 83 deletions
diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp
index 81584dd0..e9849515 100644
--- a/src/net/imap/IMAPFolder.cpp
+++ b/src/net/imap/IMAPFolder.cpp
@@ -609,19 +609,79 @@ void IMAPFolder::fetchMessages(std::vector <ref <message> >& msg, const int opti
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
+ // Build message numbers list
+ std::vector <int> list;
+ list.reserve(msg.size());
+
+ std::map <int, ref <IMAPMessage> > numberToMsg;
+
+ for (std::vector <ref <message> >::iterator it = msg.begin() ; it != msg.end() ; ++it)
+ {
+ list.push_back((*it)->getNumber());
+ numberToMsg[(*it)->getNumber()] = (*it).dynamicCast <IMAPMessage>();
+ }
+
+ // Send the request
+ const string command = IMAPUtils::buildFetchRequest(list, options);
+ m_connection->send(true, command, 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("FETCH",
+ m_connection->getParser()->lastLine(), "bad response");
+ }
+
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
const int total = msg.size();
int current = 0;
if (progress)
progress->start(total);
- for (std::vector <ref <message> >::iterator it = msg.begin() ;
- it != msg.end() ; ++it)
+ try
{
- (*it).dynamicCast <IMAPMessage>()->fetch(this, options);
+ 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",
+ 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;
+
+ // Process fetch response for this message
+ const int num = static_cast <int>(messageData->number());
+ std::map <int, ref <IMAPMessage> >::iterator msg = numberToMsg.find(num);
+
+ if (msg != numberToMsg.end())
+ {
+ (*msg).second->processFetchResponse(options, messageData->msg_att());
+
+ if (progress)
+ progress->progress(++current, total);
+ }
+ }
+ }
+ catch (...)
+ {
if (progress)
- progress->progress(++current, total);
+ progress->stop(total);
+
+ throw;
}
if (progress)
diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp
index cce01196..d345db38 100644
--- a/src/net/imap/IMAPMessage.cpp
+++ b/src/net/imap/IMAPMessage.cpp
@@ -463,80 +463,13 @@ void IMAPMessage::fetch(IMAPFolder* folder, const int options)
if (m_folder != folder)
throw exceptions::folder_not_found();
- // TODO: optimization: send the request for multiple
- // messages at the same time (FETCH x:y)
-
- // Example:
- // C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
- // S: * 2 FETCH ....
- // S: * 3 FETCH ....
- // S: * 4 FETCH ....
- // S: A654 OK FETCH completed
-
- std::vector <string> items;
-
- if (options & folder::FETCH_SIZE)
- items.push_back("RFC822.SIZE");
-
- if (options & folder::FETCH_FLAGS)
- items.push_back("FLAGS");
-
- if (options & folder::FETCH_STRUCTURE)
- items.push_back("BODYSTRUCTURE");
-
- if (options & folder::FETCH_UID)
- items.push_back("UID");
-
- if (options & folder::FETCH_FULL_HEADER)
- items.push_back("RFC822.HEADER");
- else
- {
- if (options & folder::FETCH_ENVELOPE)
- items.push_back("ENVELOPE");
-
- std::vector <string> headerFields;
-
- if (options & folder::FETCH_CONTENT_INFO)
- headerFields.push_back("CONTENT_TYPE");
-
- if (options & folder::FETCH_IMPORTANCE)
- {
- headerFields.push_back("IMPORTANCE");
- headerFields.push_back("X-PRIORITY");
- }
-
- if (!headerFields.empty())
- {
- string list;
-
- for (std::vector <string>::iterator it = headerFields.begin() ;
- it != headerFields.end() ; ++it)
- {
- if (it != headerFields.begin())
- list += " ";
-
- list += *it;
- }
-
- items.push_back("BODY[HEADER.FIELDS (" + list + ")]");
- }
- }
-
- // Build the request text
- std::ostringstream command;
- command << "FETCH " << m_num << " (";
-
- for (std::vector <string>::const_iterator it = items.begin() ;
- it != items.end() ; ++it)
- {
- if (it != items.begin()) command << " ";
- command << *it;
- }
+ // Send the request
+ std::vector <int> list;
+ list.push_back(m_num);
- command << ")";
+ const string command = IMAPUtils::buildFetchRequest(list, options);
- // Send the request
- m_folder->m_connection->send(true, command.str(), true);
+ m_folder->m_connection->send(true, command, true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_folder->m_connection->readResponse());
diff --git a/src/net/imap/IMAPUtils.cpp b/src/net/imap/IMAPUtils.cpp
index dbd62a86..a4ed9fb2 100644
--- a/src/net/imap/IMAPUtils.cpp
+++ b/src/net/imap/IMAPUtils.cpp
@@ -19,6 +19,7 @@
#include "vmime/net/imap/IMAPUtils.hpp"
#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
#include <sstream>
#include <iterator>
@@ -30,6 +31,7 @@ namespace net {
namespace imap {
+// static
const string IMAPUtils::quoteString(const string& text)
{
//
@@ -405,13 +407,7 @@ const string IMAPUtils::messageFlagList(const int flags)
}
-// This function builds a "IMAP set" given a list. Try to group consecutive
-// message numbers to reduce the list.
-//
-// Example:
-// IN = "1,2,3,4,5,7,8,13,15,16,17"
-// OUT = "1:5,7:8,13,15:*" for a mailbox with a total of 17 messages (max = 17)
-
+// static
const string IMAPUtils::listToSet(const std::vector <int>& list, const int max,
const bool alreadySorted)
{
@@ -483,6 +479,7 @@ const string IMAPUtils::listToSet(const std::vector <int>& list, const int max,
}
+// static
const string IMAPUtils::dateTime(const vmime::datetime& date)
{
std::ostringstream res;
@@ -550,6 +547,82 @@ const string IMAPUtils::dateTime(const vmime::datetime& date)
}
+// static
+const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const int options)
+{
+ // Example:
+ // C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
+ // S: * 2 FETCH ....
+ // S: * 3 FETCH ....
+ // S: * 4 FETCH ....
+ // S: A654 OK FETCH completed
+
+ std::vector <string> items;
+
+ if (options & folder::FETCH_SIZE)
+ items.push_back("RFC822.SIZE");
+
+ if (options & folder::FETCH_FLAGS)
+ items.push_back("FLAGS");
+
+ if (options & folder::FETCH_STRUCTURE)
+ items.push_back("BODYSTRUCTURE");
+
+ if (options & folder::FETCH_UID)
+ items.push_back("UID");
+
+ if (options & folder::FETCH_FULL_HEADER)
+ items.push_back("RFC822.HEADER");
+ else
+ {
+ if (options & folder::FETCH_ENVELOPE)
+ items.push_back("ENVELOPE");
+
+ std::vector <string> headerFields;
+
+ if (options & folder::FETCH_CONTENT_INFO)
+ headerFields.push_back("CONTENT_TYPE");
+
+ if (options & folder::FETCH_IMPORTANCE)
+ {
+ headerFields.push_back("IMPORTANCE");
+ headerFields.push_back("X-PRIORITY");
+ }
+
+ if (!headerFields.empty())
+ {
+ string list;
+
+ for (std::vector <string>::iterator it = headerFields.begin() ;
+ it != headerFields.end() ; ++it)
+ {
+ if (it != headerFields.begin())
+ list += " ";
+
+ list += *it;
+ }
+
+ items.push_back("BODY[HEADER.FIELDS (" + list + ")]");
+ }
+ }
+
+ // Build the request text
+ std::ostringstream command;
+ command << "FETCH " << listToSet(list, -1, false) << " (";
+
+ for (std::vector <string>::const_iterator it = items.begin() ;
+ it != items.end() ; ++it)
+ {
+ if (it != items.begin()) command << " ";
+ command << *it;
+ }
+
+ command << ")";
+
+ return command.str();
+}
+
+
} // imap
} // net
} // vmime