Implemented IMAP multi-fetching.
This commit is contained in:
parent
09d4fca9ba
commit
6c946267b1
@ -2,6 +2,11 @@
|
||||
VERSION 0.8.1cvs
|
||||
================
|
||||
|
||||
2006-01-15 Vincent Richard <vincent@vincent-richard.net>
|
||||
|
||||
* IMAP: implemented multi-fetching. Now using "FETCH x:y" instead of
|
||||
sending (y-x+1) "FETCH" requests.
|
||||
|
||||
2005-12-26 Vincent Richard <vincent@vincent-richard.net>
|
||||
|
||||
* posixSocket.cpp: use getaddrinfo() if available. This should bring
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
command << ")";
|
||||
|
||||
// Send the request
|
||||
m_folder->m_connection->send(true, command.str(), true);
|
||||
std::vector <int> list;
|
||||
list.push_back(m_num);
|
||||
|
||||
const string command = IMAPUtils::buildFetchRequest(list, options);
|
||||
|
||||
m_folder->m_connection->send(true, command, true);
|
||||
|
||||
// Get the response
|
||||
utility::auto_ptr <IMAPParser::response> resp(m_folder->m_connection->readResponse());
|
||||
|
@ -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
|
||||
|
@ -49,6 +49,11 @@ public:
|
||||
static const string toModifiedUTF7(const char hierarchySeparator, const folder::path::component& text);
|
||||
static const folder::path::component fromModifiedUTF7(const string& text);
|
||||
|
||||
/** Quote string if it contains IMAP-special characters.
|
||||
*
|
||||
* @param text string to quote
|
||||
* @return quoted string
|
||||
*/
|
||||
static const string quoteString(const string& text);
|
||||
|
||||
static const int folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list);
|
||||
@ -58,9 +63,36 @@ public:
|
||||
|
||||
static const string messageFlagList(const int flags);
|
||||
|
||||
static const string listToSet(const std::vector <int>& list, const int max = -1, const bool alreadySorted = false);
|
||||
/** Build an "IMAP set" given a list. 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"
|
||||
* OUT = "1:5,7:8,13,15:*" for a mailbox with a total of 17 messages (max = 17)
|
||||
*
|
||||
* @param list list of message numbers
|
||||
* @param max number of messages in the mailbox (or -1 if not known)
|
||||
* @param alreadySorted set to true if the list of message numbers is
|
||||
* already sorted in ascending order
|
||||
* @return a set corresponding to the message list
|
||||
*/
|
||||
static const string listToSet(const std::vector <int>& list,
|
||||
const int max = -1, const bool alreadySorted = false);
|
||||
|
||||
/** Format a date/time to IMAP date/time format.
|
||||
*
|
||||
* @param date date/time to format
|
||||
* @return IMAP-formatted date/time
|
||||
*/
|
||||
static const string dateTime(const vmime::datetime& date);
|
||||
|
||||
/** Construct a fetch request for the specified messages.
|
||||
*
|
||||
* @param list list of message numbers
|
||||
* @param options fetch options
|
||||
* @return fetch request
|
||||
*/
|
||||
static const string buildFetchRequest(const std::vector <int>& list, const int options);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user