aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/imap
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/imap')
-rw-r--r--src/net/imap/IMAPFolder.cpp361
-rw-r--r--src/net/imap/IMAPMessage.cpp5
-rw-r--r--src/net/imap/IMAPUtils.cpp213
3 files changed, 182 insertions, 397 deletions
diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp
index 3a38182e..dd7f2512 100644
--- a/src/net/imap/IMAPFolder.cpp
+++ b/src/net/imap/IMAPFolder.cpp
@@ -529,135 +529,93 @@ ref <message> IMAPFolder::getMessage(const int num)
}
-std::vector <ref <message> > IMAPFolder::getMessages(const int from, const int to)
+std::vector <ref <message> > IMAPFolder::getMessages(const messageSet& msgs)
{
- const int messageCount = m_status->getMessageCount();
- const int to2 = (to == -1 ? messageCount : to);
-
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
- else if (to2 < from || from < 1 || to2 < 1 || from > messageCount || to2 > messageCount)
- throw exceptions::message_not_found();
-
- std::vector <ref <message> > v;
- ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
-
- for (int i = from ; i <= to2 ; ++i)
- v.push_back(vmime::create <IMAPMessage>(thisFolder, i));
-
- return (v);
-}
-
-
-std::vector <ref <message> > IMAPFolder::getMessages(const std::vector <int>& nums)
-{
- if (!isOpen())
- throw exceptions::illegal_state("Folder not open");
-
- std::vector <ref <message> > v;
- ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
-
- for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it)
- v.push_back(vmime::create <IMAPMessage>(thisFolder, *it));
-
- return (v);
-}
-
-
-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)
+ if (msgs.isEmpty() == 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
+ std::vector <ref <message> > messages;
- // Prepare command and arguments
- std::ostringstream cmd;
- cmd.imbue(std::locale::classic());
+ if (msgs.isNumberSet())
+ {
+ const std::vector <int> numbers = IMAPUtils::messageSetToNumberList(msgs);
- cmd << "UID FETCH " << uids[0];
+ ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
- for (std::vector <message::uid>::size_type i = 1, n = uids.size() ; i < n ; ++i)
- cmd << "," << uids[i];
+ for (std::vector <int>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it)
+ messages.push_back(vmime::create <IMAPMessage>(thisFolder, *it));
+ }
+ else if (msgs.isUIDSet())
+ {
+ // 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
- cmd << " UID";
+ // Prepare command and arguments
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
- // Send the request
- m_connection->send(true, cmd.str(), true);
+ cmd << "UID FETCH " << IMAPUtils::messageSetToSequenceSet(msgs) << " UID";
- // Get the response
- utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+ // Send the request
+ m_connection->send(true, cmd.str(), true);
- if (resp->isBad() || resp->response_done()->response_tagged()->
- resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
- {
- throw exceptions::command_error("UID FETCH ... UID", resp->getErrorLog(), "bad response");
- }
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
- // Process the response
- const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
- resp->continue_req_or_response_data();
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("UID FETCH ... UID", resp->getErrorLog(), "bad response");
+ }
- std::vector <ref <message> > messages;
+ // Process the response
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
- for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
- it = respDataList.begin() ; it != respDataList.end() ; ++it)
- {
- if ((*it)->response_data() == NULL)
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
- throw exceptions::command_error("UID FETCH ... UID",
- resp->getErrorLog(), "invalid response");
- }
+ if ((*it)->response_data() == NULL)
+ {
+ throw exceptions::command_error("UID FETCH ... UID",
+ resp->getErrorLog(), "invalid response");
+ }
- const IMAPParser::message_data* messageData =
- (*it)->response_data()->message_data();
+ 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;
+ // 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;
+ // Get Process fetch response for this message
+ const int msgNum = static_cast <int>(messageData->number());
+ message::uid msgUID;
- // Find UID in message attributes
- const std::vector <IMAPParser::msg_att_item*> atts = messageData->msg_att()->items();
+ // 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)
+ for (std::vector <IMAPParser::msg_att_item*>::const_iterator
+ it = atts.begin() ; it != atts.end() ; ++it)
{
- msgUID = (*it)->unique_id()->value();
- break;
+ if ((*it)->type() == IMAPParser::msg_att_item::UID)
+ {
+ msgUID = (*it)->unique_id()->value();
+ break;
+ }
}
- }
- if (!msgUID.empty())
- {
- ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
- messages.push_back(vmime::create <IMAPMessage>(thisFolder, msgNum, msgUID));
+ if (!msgUID.empty())
+ {
+ ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
+ messages.push_back(vmime::create <IMAPMessage>(thisFolder, msgNum, msgUID));
+ }
}
}
@@ -816,7 +774,9 @@ void IMAPFolder::fetchMessages(std::vector <ref <message> >& msg, const int opti
}
// Send the request
- const string command = IMAPUtils::buildFetchRequest(m_connection, list, options);
+ const string command = IMAPUtils::buildFetchRequest
+ (m_connection, messageSet::byNumber(list), options);
+
m_connection->send(true, command, true);
// Get the response
@@ -945,17 +905,11 @@ void IMAPFolder::onStoreDisconnected()
}
-void IMAPFolder::deleteMessage(const int num)
-{
- deleteMessages(num, num);
-}
-
-
-void IMAPFolder::deleteMessages(const int from, const int to)
+void IMAPFolder::deleteMessages(const messageSet& msgs)
{
ref <IMAPStore> store = m_store.acquire();
- if (from < 1 || (to < from && to != -1))
+ if (msgs.isEmpty())
throw exceptions::invalid_argument();
if (!store)
@@ -969,19 +923,10 @@ void IMAPFolder::deleteMessages(const int from, const int to)
std::ostringstream command;
command.imbue(std::locale::classic());
- command << "STORE ";
-
- if (from == to)
- {
- command << from;
- }
+ if (msgs.isUIDSet())
+ command << "UID STORE" << IMAPUtils::messageSetToSequenceSet(msgs);
else
- {
- command << from << ":";
-
- if (to == -1) command << m_status->getMessageCount();
- else command << to;
- }
+ command << "STORE" << IMAPUtils::messageSetToSequenceSet(msgs);
command << " +FLAGS (\\Deleted)";
@@ -1002,116 +947,16 @@ void IMAPFolder::deleteMessages(const int from, const int to)
}
-void IMAPFolder::deleteMessages(const std::vector <int>& nums)
+void IMAPFolder::setMessageFlags(const messageSet& msgs, const int flags, const int mode)
{
- ref <IMAPStore> store = m_store.acquire();
-
- if (nums.empty())
- throw exceptions::invalid_argument();
-
- if (!store)
- throw exceptions::illegal_state("Store disconnected");
- else if (!isOpen())
- throw exceptions::illegal_state("Folder not open");
- else if (m_mode == MODE_READ_ONLY)
- throw exceptions::illegal_state("Folder is read-only");
-
- // Sort the list of message numbers
- std::vector <int> list;
-
- list.resize(nums.size());
- std::copy(nums.begin(), nums.end(), list.begin());
-
- std::sort(list.begin(), list.end());
-
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
- command << "STORE ";
- command << IMAPUtils::listToSet(list, m_status->getMessageCount(), true);
- command << " +FLAGS (\\Deleted)";
-
- // Send the request
- m_connection->send(true, command.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("STORE",
- resp->getErrorLog(), "bad response");
- }
-
- processStatusUpdate(resp);
-}
-
-
-void IMAPFolder::setMessageFlags(const int from, const int to, const int flags, const int mode)
-{
- ref <IMAPStore> store = m_store.acquire();
-
- if (from < 1 || (to < from && to != -1))
- throw exceptions::invalid_argument();
-
- if (!store)
- throw exceptions::illegal_state("Store disconnected");
- else if (!isOpen())
- throw exceptions::illegal_state("Folder not open");
- else if (m_mode == MODE_READ_ONLY)
- throw exceptions::illegal_state("Folder is read-only");
-
- std::ostringstream oss;
- oss.imbue(std::locale::classic());
-
- if (from == to)
- {
- oss << from;
- }
+ if (msgs.isUIDSet())
+ command << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
else
- {
- if (to == -1)
- oss << from << ":*";
- else
- oss << from << ":" << to;
- }
-
- setMessageFlagsImpl(oss.str(), flags, mode);
-}
-
-
-void IMAPFolder::setMessageFlags(const std::vector <int>& nums, const int flags, const int mode)
-{
- ref <IMAPStore> store = m_store.acquire();
-
- if (!store)
- throw exceptions::illegal_state("Store disconnected");
- else if (!isOpen())
- throw exceptions::illegal_state("Folder not open");
- else if (m_mode == MODE_READ_ONLY)
- throw exceptions::illegal_state("Folder is read-only");
-
- // Sort the list of message numbers
- std::vector <int> list;
-
- list.resize(nums.size());
- std::copy(nums.begin(), nums.end(), list.begin());
- std::sort(list.begin(), list.end());
-
- // Delegates call
- setMessageFlagsImpl(IMAPUtils::listToSet(list, m_status->getMessageCount(), true), flags, mode);
-}
-
-
-void IMAPFolder::setMessageFlagsImpl(const string& set, const int flags, const int mode)
-{
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- command << "STORE " << set;
+ command << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
switch (mode)
{
@@ -1364,27 +1209,7 @@ void IMAPFolder::rename(const folder::path& newPath)
}
-void IMAPFolder::copyMessage(const folder::path& dest, const int num)
-{
- ref <IMAPStore> store = m_store.acquire();
-
- if (!store)
- throw exceptions::illegal_state("Store disconnected");
- else if (!isOpen())
- throw exceptions::illegal_state("Folder not open");
-
- // Construct set
- std::ostringstream set;
- set.imbue(std::locale::classic());
-
- set << num;
-
- // Delegate message copy
- copyMessagesImpl(set.str(), dest);
-}
-
-
-void IMAPFolder::copyMessages(const folder::path& dest, const int from, const int to)
+void IMAPFolder::copyMessages(const folder::path& dest, const messageSet& set)
{
ref <IMAPStore> store = m_store.acquire();
@@ -1392,44 +1217,12 @@ void IMAPFolder::copyMessages(const folder::path& dest, const int from, const in
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
- else if (from < 1 || (to < from && to != -1))
- throw exceptions::invalid_argument();
-
- // Construct set
- std::ostringstream set;
- set.imbue(std::locale::classic());
- if (to == -1)
- set << from << ":*";
- else
- set << from << ":" << to;
-
- // Delegate message copy
- copyMessagesImpl(set.str(), dest);
-}
-
-
-void IMAPFolder::copyMessages(const folder::path& dest, const std::vector <int>& nums)
-{
- ref <IMAPStore> store = m_store.acquire();
-
- if (!store)
- throw exceptions::illegal_state("Store disconnected");
- else if (!isOpen())
- throw exceptions::illegal_state("Folder not open");
-
- // Delegate message copy
- copyMessagesImpl(IMAPUtils::listToSet(nums, m_status->getMessageCount()), dest);
-}
-
-
-void IMAPFolder::copyMessagesImpl(const string& set, const folder::path& dest)
-{
// Build the request text
std::ostringstream command;
command.imbue(std::locale::classic());
- command << "COPY " << set << " ";
+ command << "COPY " << IMAPUtils::messageSetToSequenceSet(set) << " ";
command << IMAPUtils::quoteString(IMAPUtils::pathToString
(m_connection->hierarchySeparator(), dest));
@@ -1599,6 +1392,8 @@ std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid&
}
}
+ processStatusUpdate(resp);
+
return v;
}
diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp
index 96114e94..33599689 100644
--- a/src/net/imap/IMAPMessage.cpp
+++ b/src/net/imap/IMAPMessage.cpp
@@ -531,7 +531,10 @@ void IMAPMessage::setFlags(const int flags, const int mode)
if (!folder)
throw exceptions::folder_not_found();
- folder->setMessageFlags(m_num, m_num, flags, mode);
+ if (!m_uid.empty())
+ folder->setMessageFlags(messageSet::byUID(m_uid), flags, mode);
+ else
+ folder->setMessageFlags(messageSet::byNumber(m_num), flags, mode);
}
diff --git a/src/net/imap/IMAPUtils.cpp b/src/net/imap/IMAPUtils.cpp
index dc583f84..b5f8b38d 100644
--- a/src/net/imap/IMAPUtils.cpp
+++ b/src/net/imap/IMAPUtils.cpp
@@ -472,98 +472,6 @@ const string IMAPUtils::messageFlagList(const int flags)
// static
-const string IMAPUtils::listToSet(const std::vector <int>& list, const int max,
- const bool alreadySorted)
-{
- // Sort a copy of the list (if not already sorted)
- std::vector <int> temp;
-
- if (!alreadySorted)
- {
- temp.resize(list.size());
- std::copy(list.begin(), list.end(), temp.begin());
-
- std::sort(temp.begin(), temp.end());
- }
-
- const std::vector <int>& theList = (alreadySorted ? list : temp);
-
- // Build the set
- std::ostringstream res;
- res.imbue(std::locale::classic());
-
- int previous = -1, setBegin = -1;
-
- for (std::vector <int>::const_iterator it = theList.begin() ;
- it != theList.end() ; ++it)
- {
- const int current = *it;
-
- if (previous == -1)
- {
- res << current;
-
- previous = current;
- setBegin = current;
- }
- else
- {
- if (current == previous + 1)
- {
- previous = current;
- }
- else
- {
- if (setBegin != previous)
- {
- res << ":" << previous << "," << current;
-
- previous = current;
- setBegin = current;
- }
- else
- {
- if (setBegin != current) // skip duplicates
- res << "," << current;
-
- previous = current;
- setBegin = current;
- }
- }
- }
- }
-
- if (previous != setBegin)
- {
- if (previous == max)
- res << ":*";
- else
- res << ":" << previous;
- }
-
- return (res.str());
-}
-
-
-// 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 << list[0];
-
- for (std::vector <message::uid>::size_type i = 1, n = list.size() ; i < n ; ++i)
- res << "," << list[i];
-
- return res.str();
-}
-
-
-// static
const string IMAPUtils::dateTime(const vmime::datetime& date)
{
std::ostringstream res;
@@ -633,8 +541,8 @@ const string IMAPUtils::dateTime(const vmime::datetime& date)
// static
-const string IMAPUtils::buildFetchRequestImpl
- (ref <IMAPConnection> cnt, const string& mode, const string& set, const int options)
+const string IMAPUtils::buildFetchRequest
+ (ref <IMAPConnection> cnt, const messageSet& msgs, const int options)
{
// Example:
// C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
@@ -702,10 +610,10 @@ const string IMAPUtils::buildFetchRequestImpl
std::ostringstream command;
command.imbue(std::locale::classic());
- if (mode == "uid")
- command << "UID FETCH " << set << " (";
+ if (msgs.isUIDSet())
+ command << "UID FETCH " << messageSetToSequenceSet(msgs) << " (";
else
- command << "FETCH " << set << " (";
+ command << "FETCH " << messageSetToSequenceSet(msgs) << " (";
for (std::vector <string>::const_iterator it = items.begin() ;
it != items.end() ; ++it)
@@ -721,22 +629,6 @@ const string IMAPUtils::buildFetchRequestImpl
// static
-const string IMAPUtils::buildFetchRequest
- (ref <IMAPConnection> cnt, const std::vector <int>& list, const int options)
-{
- return buildFetchRequestImpl(cnt, "number", listToSet(list, -1, false), options);
-}
-
-
-// static
-const string IMAPUtils::buildFetchRequest
- (ref <IMAPConnection> cnt, const std::vector <message::uid>& list, const int options)
-{
- return buildFetchRequestImpl(cnt, "uid", listToSet(list), options);
-}
-
-
-// static
void IMAPUtils::convertAddressList
(const IMAPParser::address_list& src, mailboxList& dest)
{
@@ -756,6 +648,101 @@ void IMAPUtils::convertAddressList
}
+
+class IMAPUIDMessageSetEnumerator : public messageSetEnumerator
+{
+public:
+
+ IMAPUIDMessageSetEnumerator()
+ : m_first(true)
+ {
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range)
+ {
+ if (!m_first)
+ m_oss << ",";
+
+ if (range.getFirst() == range.getLast())
+ m_oss << range.getFirst();
+ else
+ m_oss << range.getFirst() << ":" << range.getLast();
+
+ m_first = false;
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& range)
+ {
+ if (!m_first)
+ m_oss << ",";
+
+ if (range.getFirst() == range.getLast())
+ m_oss << range.getFirst();
+ else
+ m_oss << range.getFirst() << ":" << range.getLast();
+
+ m_first = false;
+ }
+
+ const std::string str() const
+ {
+ return m_oss.str();
+ }
+
+private:
+
+ std::ostringstream m_oss;
+ bool m_first;
+};
+
+
+class IMAPMessageSetEnumerator : public messageSetEnumerator
+{
+public:
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range)
+ {
+ for (int i = range.getFirst(), last = range.getLast() ; i <= last ; ++i)
+ m_list.push_back(i);
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */)
+ {
+ // Not used
+ }
+
+ const std::vector <int>& list() const
+ {
+ return m_list;
+ }
+
+public:
+
+ std::vector <int> m_list;
+};
+
+
+
+// static
+const string IMAPUtils::messageSetToSequenceSet(const messageSet& msgs)
+{
+ IMAPUIDMessageSetEnumerator en;
+ msgs.enumerate(en);
+
+ return en.str();
+}
+
+
+// static
+const std::vector <int> IMAPUtils::messageSetToNumberList(const messageSet& msgs)
+{
+ IMAPMessageSetEnumerator en;
+ msgs.enumerate(en);
+
+ return en.list();
+}
+
+
} // imap
} // net
} // vmime