diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/net/imap/IMAPFolder.cpp | 361 | ||||
-rw-r--r-- | src/net/imap/IMAPMessage.cpp | 5 | ||||
-rw-r--r-- | src/net/imap/IMAPUtils.cpp | 213 | ||||
-rw-r--r-- | src/net/maildir/maildirFolder.cpp | 380 | ||||
-rw-r--r-- | src/net/maildir/maildirMessage.cpp | 2 | ||||
-rw-r--r-- | src/net/maildir/maildirUtils.cpp | 32 | ||||
-rw-r--r-- | src/net/messageSet.cpp | 369 | ||||
-rw-r--r-- | src/net/pop3/POP3Folder.cpp | 173 | ||||
-rw-r--r-- | src/net/pop3/POP3Utils.cpp | 32 |
9 files changed, 739 insertions, 828 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 diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp index 3042d4b5..42a2c5ff 100644 --- a/src/net/maildir/maildirFolder.cpp +++ b/src/net/maildir/maildirFolder.cpp @@ -419,49 +419,32 @@ ref <message> maildirFolder::getMessage(const int num) } -std::vector <ref <message> > maildirFolder::getMessages(const int from, const int to) -{ - const int to2 = (to == -1 ? m_messageCount : to); - - if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - else if (to2 < from || from < 1 || to2 < 1 || from > m_messageCount || to2 > m_messageCount) - throw exceptions::message_not_found(); - - std::vector <ref <message> > v; - ref <maildirFolder> thisFolder = thisRef().dynamicCast <maildirFolder>(); - - for (int i = from ; i <= to2 ; ++i) - v.push_back(vmime::create <maildirMessage>(thisFolder, i)); - - return (v); -} - - -std::vector <ref <message> > maildirFolder::getMessages(const std::vector <int>& nums) +std::vector <ref <message> > maildirFolder::getMessages(const messageSet& msgs) { if (!isOpen()) throw exceptions::illegal_state("Folder not open"); - std::vector <ref <message> > v; - ref <maildirFolder> thisFolder = thisRef().dynamicCast <maildirFolder>(); - - for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it) - v.push_back(vmime::create <maildirMessage>(thisFolder, *it)); - - return (v); -} + if (msgs.isNumberSet()) + { + const std::vector <int> numbers = maildirUtils::messageSetToNumberList(msgs); + std::vector <ref <message> > messages; + ref <maildirFolder> thisFolder = thisRef().dynamicCast <maildirFolder>(); -ref <message> maildirFolder::getMessageByUID(const message::uid& /* uid */) -{ - throw exceptions::operation_not_supported(); -} + for (std::vector <int>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) + { + if (*it < 1|| *it > m_messageCount) + throw exceptions::message_not_found(); + messages.push_back(vmime::create <maildirMessage>(thisFolder, *it)); + } -std::vector <ref <message> > maildirFolder::getMessagesByUID(const std::vector <message::uid>& /* uids */) -{ - throw exceptions::operation_not_supported(); + return messages; + } + else + { + throw exceptions::operation_not_supported(); + } } @@ -590,35 +573,18 @@ void maildirFolder::rename(const folder::path& newPath) } -void maildirFolder::deleteMessage(const int num) -{ - // Mark messages as deleted - setMessageFlags(num, num, message::FLAG_DELETED, message::FLAG_MODE_ADD); -} - - -void maildirFolder::deleteMessages(const int from, const int to) -{ - // Mark messages as deleted - setMessageFlags(from, to, message::FLAG_DELETED, message::FLAG_MODE_ADD); -} - - -void maildirFolder::deleteMessages(const std::vector <int>& nums) +void maildirFolder::deleteMessages(const messageSet& msgs) { // Mark messages as deleted - setMessageFlags(nums, message::FLAG_DELETED, message::FLAG_MODE_ADD); + setMessageFlags(msgs, message::FLAG_DELETED, message::FLAG_MODE_ADD); } void maildirFolder::setMessageFlags - (const int from, const int to, const int flags, const int mode) + (const messageSet& msgs, const int flags, const int mode) { ref <maildirStore> 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()) @@ -626,210 +592,116 @@ void maildirFolder::setMessageFlags else if (m_mode == MODE_READ_ONLY) throw exceptions::illegal_state("Folder is read-only"); - // Construct the list of message numbers - const int to2 = (to == -1) ? m_messageCount : to; - const int count = to - from + 1; - - std::vector <int> nums; - nums.resize(count); + if (msgs.isNumberSet()) + { + const std::vector <int> nums = maildirUtils::messageSetToNumberList(msgs); - for (int i = from, j = 0 ; i <= to2 ; ++i, ++j) - nums[j] = i; + // Change message flags + ref <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); - // Change message flags - setMessageFlagsImpl(nums, flags, mode); + utility::file::path curDirPath = store->getFormat()-> + folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); - // Update local flags - switch (mode) - { - case message::FLAG_MODE_ADD: - { - for (std::vector <maildirMessage*>::iterator it = - m_messages.begin() ; it != m_messages.end() ; ++it) - { - if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 && - (*it)->m_flags != message::FLAG_UNDEFINED) - { - (*it)->m_flags |= flags; - } - } - - break; - } - case message::FLAG_MODE_REMOVE: - { - for (std::vector <maildirMessage*>::iterator it = - m_messages.begin() ; it != m_messages.end() ; ++it) + for (std::vector <int>::const_iterator it = + nums.begin() ; it != nums.end() ; ++it) { - if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 && - (*it)->m_flags != message::FLAG_UNDEFINED) - { - (*it)->m_flags &= ~flags; - } - } + const int num = *it - 1; - break; - } - default: - case message::FLAG_MODE_SET: - { - for (std::vector <maildirMessage*>::iterator it = - m_messages.begin() ; it != m_messages.end() ; ++it) - { - if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 && - (*it)->m_flags != message::FLAG_UNDEFINED) + try { - (*it)->m_flags = flags; - } - } - - break; - } - - } - - // Notify message flags changed - ref <events::messageChangedEvent> event = - vmime::create <events::messageChangedEvent> - (thisRef().dynamicCast <folder>(), - events::messageChangedEvent::TYPE_FLAGS, nums); - - notifyMessageChanged(event); - - // TODO: notify other folders with the same path -} - + const utility::file::path::component path = m_messageInfos[num].path; + ref <utility::file> file = fsf->create(curDirPath / path); -void maildirFolder::setMessageFlags - (const std::vector <int>& nums, const int flags, const int mode) -{ - ref <maildirStore> 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"); + int newFlags = maildirUtils::extractFlags(path); - // Sort the list of message numbers - std::vector <int> list; + switch (mode) + { + case message::FLAG_MODE_ADD: newFlags |= flags; break; + case message::FLAG_MODE_REMOVE: newFlags &= ~flags; break; + default: + case message::FLAG_MODE_SET: newFlags = flags; break; + } - list.resize(nums.size()); - std::copy(nums.begin(), nums.end(), list.begin()); + const utility::file::path::component newPath = maildirUtils::buildFilename + (maildirUtils::extractId(path), newFlags); - std::sort(list.begin(), list.end()); + file->rename(curDirPath / newPath); - // Change message flags - setMessageFlagsImpl(list, flags, mode); + if (flags & message::FLAG_DELETED) + m_messageInfos[num].type = messageInfos::TYPE_DELETED; + else + m_messageInfos[num].type = messageInfos::TYPE_CUR; - // Update local flags - switch (mode) - { - case message::FLAG_MODE_ADD: - { - for (std::vector <maildirMessage*>::iterator it = - m_messages.begin() ; it != m_messages.end() ; ++it) - { - if (std::binary_search(list.begin(), list.end(), (*it)->getNumber()) && - (*it)->m_flags != message::FLAG_UNDEFINED) + m_messageInfos[num].path = newPath; + } + catch (exceptions::filesystem_exception& e) { - (*it)->m_flags |= flags; + // Ignore (not important) } } - break; - } - case message::FLAG_MODE_REMOVE: - { - for (std::vector <maildirMessage*>::iterator it = - m_messages.begin() ; it != m_messages.end() ; ++it) + // Update local flags + switch (mode) + { + case message::FLAG_MODE_ADD: { - if (std::binary_search(list.begin(), list.end(), (*it)->getNumber()) && - (*it)->m_flags != message::FLAG_UNDEFINED) + for (std::vector <maildirMessage*>::iterator it = + m_messages.begin() ; it != m_messages.end() ; ++it) { - (*it)->m_flags &= ~flags; + if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) && + (*it)->m_flags != message::FLAG_UNDEFINED) + { + (*it)->m_flags |= flags; + } } - } - break; - } - default: - case message::FLAG_MODE_SET: - { - for (std::vector <maildirMessage*>::iterator it = - m_messages.begin() ; it != m_messages.end() ; ++it) + break; + } + case message::FLAG_MODE_REMOVE: { - if (std::binary_search(list.begin(), list.end(), (*it)->getNumber()) && - (*it)->m_flags != message::FLAG_UNDEFINED) + for (std::vector <maildirMessage*>::iterator it = + m_messages.begin() ; it != m_messages.end() ; ++it) { - (*it)->m_flags = flags; + if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) && + (*it)->m_flags != message::FLAG_UNDEFINED) + { + (*it)->m_flags &= ~flags; + } } - } - - break; - } - - } - - // Notify message flags changed - ref <events::messageChangedEvent> event = - vmime::create <events::messageChangedEvent> - (thisRef().dynamicCast <folder>(), - events::messageChangedEvent::TYPE_FLAGS, nums); - - notifyMessageChanged(event); - // TODO: notify other folders with the same path -} - - -void maildirFolder::setMessageFlagsImpl - (const std::vector <int>& nums, const int flags, const int mode) -{ - ref <maildirStore> store = m_store.acquire(); - - ref <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); - - utility::file::path curDirPath = store->getFormat()-> - folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); - - for (std::vector <int>::const_iterator it = - nums.begin() ; it != nums.end() ; ++it) - { - const int num = *it - 1; - - try + break; + } + default: + case message::FLAG_MODE_SET: { - const utility::file::path::component path = m_messageInfos[num].path; - ref <utility::file> file = fsf->create(curDirPath / path); - - int newFlags = maildirUtils::extractFlags(path); - - switch (mode) + for (std::vector <maildirMessage*>::iterator it = + m_messages.begin() ; it != m_messages.end() ; ++it) { - case message::FLAG_MODE_ADD: newFlags |= flags; break; - case message::FLAG_MODE_REMOVE: newFlags &= ~flags; break; - default: - case message::FLAG_MODE_SET: newFlags = flags; break; + if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) && + (*it)->m_flags != message::FLAG_UNDEFINED) + { + (*it)->m_flags = flags; + } } - const utility::file::path::component newPath = maildirUtils::buildFilename - (maildirUtils::extractId(path), newFlags); + break; + } - file->rename(curDirPath / newPath); + } - if (flags & message::FLAG_DELETED) - m_messageInfos[num].type = messageInfos::TYPE_DELETED; - else - m_messageInfos[num].type = messageInfos::TYPE_CUR; + // Notify message flags changed + ref <events::messageChangedEvent> event = + vmime::create <events::messageChangedEvent> + (thisRef().dynamicCast <folder>(), + events::messageChangedEvent::TYPE_FLAGS, nums); - m_messageInfos[num].path = newPath; - } - catch (exceptions::filesystem_exception& e) - { - // Ignore (not important) - } + notifyMessageChanged(event); + + // TODO: notify other folders with the same path + } + else + { + throw exceptions::operation_not_supported(); } } @@ -1032,46 +904,7 @@ void maildirFolder::copyMessageImpl(const utility::file::path& tmpDirPath, } -void maildirFolder::copyMessage(const folder::path& dest, const int num) -{ - ref <maildirStore> store = m_store.acquire(); - - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - copyMessages(dest, num, num); -} - - -void maildirFolder::copyMessages(const folder::path& dest, const int from, const int to) -{ - ref <maildirStore> store = m_store.acquire(); - - if (!store) - 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 the list of message numbers - const int to2 = (to == -1) ? m_messageCount : to; - const int count = to - from + 1; - - std::vector <int> nums; - nums.resize(count); - - for (int i = from, j = 0 ; i <= to2 ; ++i, ++j) - nums[j] = i; - - // Copy messages - copyMessagesImpl(dest, nums); -} - - -void maildirFolder::copyMessages(const folder::path& dest, const std::vector <int>& nums) +void maildirFolder::copyMessages(const folder::path& dest, const messageSet& msgs) { ref <maildirStore> store = m_store.acquire(); @@ -1080,15 +913,6 @@ void maildirFolder::copyMessages(const folder::path& dest, const std::vector <in else if (!isOpen()) throw exceptions::illegal_state("Folder not open"); - // Copy messages - copyMessagesImpl(dest, nums); -} - - -void maildirFolder::copyMessagesImpl(const folder::path& dest, const std::vector <int>& nums) -{ - ref <maildirStore> store = m_store.acquire(); - ref <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory(); utility::file::path curDirPath = store->getFormat()->folderPathToFileSystemPath @@ -1121,6 +945,8 @@ void maildirFolder::copyMessagesImpl(const folder::path& dest, const std::vector } // Copy messages + const std::vector <int> nums = maildirUtils::messageSetToNumberList(msgs); + try { for (std::vector <int>::const_iterator it = diff --git a/src/net/maildir/maildirMessage.cpp b/src/net/maildir/maildirMessage.cpp index e63d5edf..a7c2a22f 100644 --- a/src/net/maildir/maildirMessage.cpp +++ b/src/net/maildir/maildirMessage.cpp @@ -140,7 +140,7 @@ void maildirMessage::setFlags(const int flags, const int mode) if (!folder) throw exceptions::folder_not_found(); - folder->setMessageFlags(m_num, m_num, flags, mode); + folder->setMessageFlags(messageSet::byNumber(m_num), flags, mode); } diff --git a/src/net/maildir/maildirUtils.cpp b/src/net/maildir/maildirUtils.cpp index 9028fa59..c4ba2857 100644 --- a/src/net/maildir/maildirUtils.cpp +++ b/src/net/maildir/maildirUtils.cpp @@ -214,6 +214,38 @@ void maildirUtils::recursiveFSDelete(ref <utility::file> dir) +class maildirMessageSetEnumerator : public messageSetEnumerator +{ +public: + + void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) + { + for (int i = range.getFirst(), last = range.getLast() ; i <= last ; ++i) + list.push_back(i); + } + + void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) + { + // Not supported + } + +public: + + std::vector <int> list; +}; + + +// static +const std::vector <int> maildirUtils::messageSetToNumberList(const messageSet& msgs) +{ + maildirMessageSetEnumerator en; + msgs.enumerate(en); + + return en.list; +} + + + // // messageIdComparator // diff --git a/src/net/messageSet.cpp b/src/net/messageSet.cpp new file mode 100644 index 00000000..04f1debb --- /dev/null +++ b/src/net/messageSet.cpp @@ -0,0 +1,369 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/net/messageSet.hpp" + +#include <iterator> +#include <algorithm> +#include <typeinfo> + + +namespace vmime { +namespace net { + + +// messageRange + +messageRange::messageRange() +{ +} + + +messageRange::~messageRange() +{ +} + + +// numberMessageRange + +numberMessageRange::numberMessageRange(const int number) + : m_first(number), m_last(number) +{ + if (number < 1) + throw std::invalid_argument("number"); +} + + +numberMessageRange::numberMessageRange(const int first, const int last) + : m_first(first), m_last(last) +{ + if (first < 1) + throw std::invalid_argument("first"); + else if (last != -1 && last < first) + throw std::invalid_argument("last"); +} + + +numberMessageRange::numberMessageRange(const numberMessageRange& other) + : messageRange(), m_first(other.m_first), m_last(other.m_last) +{ +} + + +int numberMessageRange::getFirst() const +{ + return m_first; +} + + +int numberMessageRange::getLast() const +{ + return m_last; +} + + +void numberMessageRange::enumerate(messageSetEnumerator& en) const +{ + en.enumerateNumberMessageRange(*this); +} + + +messageRange* numberMessageRange::clone() const +{ + return new numberMessageRange(*this); +} + + +// UIDMessageRange + +UIDMessageRange::UIDMessageRange(const message::uid& uid) + : m_first(uid), m_last(uid) +{ +} + + +UIDMessageRange::UIDMessageRange(const message::uid& first, const message::uid& last) + : m_first(first), m_last(last) +{ +} + + +UIDMessageRange::UIDMessageRange(const UIDMessageRange& other) + : messageRange(), m_first(other.m_first), m_last(other.m_last) +{ +} + + +const message::uid UIDMessageRange::getFirst() const +{ + return m_first; +} + + +const message::uid UIDMessageRange::getLast() const +{ + return m_last; +} + + +void UIDMessageRange::enumerate(messageSetEnumerator& en) const +{ + en.enumerateUIDMessageRange(*this); +} + + +messageRange* UIDMessageRange::clone() const +{ + return new UIDMessageRange(*this); +} + + +// messageSet + + +messageSet::messageSet() +{ +} + + +messageSet::messageSet(const messageSet& other) + : object() +{ + m_ranges.resize(other.m_ranges.size()); + + for (unsigned int i = 0, n = other.m_ranges.size() ; i < n ; ++i) + m_ranges[i] = other.m_ranges[i]->clone(); +} + + +messageSet::~messageSet() +{ + for (unsigned int i = 0, n = m_ranges.size() ; i < n ; ++i) + delete m_ranges[i]; +} + + +// static +messageSet messageSet::byNumber(const int number) +{ + messageSet set; + set.m_ranges.push_back(new numberMessageRange(number)); + + return set; +} + + +// static +messageSet messageSet::byNumber(const int first, const int last) +{ + messageSet set; + set.m_ranges.push_back(new numberMessageRange(first, last)); + + return set; +} + + +// static +messageSet messageSet::byNumber(const std::vector <int>& numbers) +{ + // Sort a copy of the list + std::vector <int> sortedNumbers; + + sortedNumbers.resize(numbers.size()); + + std::copy(numbers.begin(), numbers.end(), sortedNumbers.begin()); + std::sort(sortedNumbers.begin(), sortedNumbers.end()); + + // Build the set by detecting ranges of continuous numbers + int previous = -1, rangeStart = -1; + messageSet set; + + for (std::vector <int>::const_iterator it = sortedNumbers.begin() ; + it != sortedNumbers.end() ; ++it) + { + const int current = *it; + + if (current == previous) + continue; // skip duplicates + + if (previous == -1) + { + previous = current; + rangeStart = current; + } + else + { + if (current == previous + 1) + { + previous = current; + } + else + { + set.m_ranges.push_back(new numberMessageRange(rangeStart, previous)); + + previous = current; + rangeStart = current; + } + } + } + + set.m_ranges.push_back(new numberMessageRange(rangeStart, previous)); + + return set; +} + + +// static +messageSet messageSet::byUID(const message::uid& uid) +{ + messageSet set; + set.m_ranges.push_back(new UIDMessageRange(uid)); + + return set; +} + + +messageSet messageSet::byUID(const message::uid& first, const message::uid& last) +{ + messageSet set; + set.m_ranges.push_back(new UIDMessageRange(first, last)); + + return set; +} + + +messageSet messageSet::byUID(const std::vector <message::uid>& uids) +{ + std::vector <vmime_uint32> numericUIDs; + + for (unsigned int i = 0, n = uids.size() ; i < n ; ++i) + { + const string uid = uids[i]; + int numericUID = 0; + + const string::value_type* p = uid.c_str(); + + for ( ; *p >= '0' && *p <= '9' ; ++p) + numericUID = (numericUID * 10) + (*p - '0'); + + if (*p != '\0') + { + messageSet set; + + // Non-numeric UID, fall back to plain UID list (single-UID ranges) + for (unsigned int i = 0, n = uids.size() ; i < n ; ++i) + set.m_ranges.push_back(new UIDMessageRange(uids[i])); + + return set; + } + + numericUIDs.push_back(numericUID); + } + + // Sort a copy of the list + std::vector <vmime_uint32> sortedUIDs; + + sortedUIDs.resize(numericUIDs.size()); + + std::copy(numericUIDs.begin(), numericUIDs.end(), sortedUIDs.begin()); + std::sort(sortedUIDs.begin(), sortedUIDs.end()); + + // Build the set by detecting ranges of continuous numbers + vmime_uint32 previous = -1U, rangeStart = -1U; + messageSet set; + + for (std::vector <vmime_uint32>::const_iterator it = sortedUIDs.begin() ; + it != sortedUIDs.end() ; ++it) + { + const vmime_uint32 current = *it; + + if (current == previous) + continue; // skip duplicates + + if (previous == -1U) + { + previous = current; + rangeStart = current; + } + else + { + if (current == previous + 1) + { + previous = current; + } + else + { + set.m_ranges.push_back(new UIDMessageRange + (static_cast <std::ostringstream*>(&(std::ostringstream() << rangeStart))->str(), + static_cast <std::ostringstream*>(&(std::ostringstream() << previous))->str())); + + previous = current; + rangeStart = current; + } + } + } + + set.m_ranges.push_back(new UIDMessageRange + (static_cast <std::ostringstream*>(&(std::ostringstream() << rangeStart))->str(), + static_cast <std::ostringstream*>(&(std::ostringstream() << previous))->str())); + + return set; +} + + +void messageSet::addRange(const messageRange& range) +{ + if (!m_ranges.empty() && typeid(*m_ranges[0]) != typeid(range)) + throw std::invalid_argument("range"); + + m_ranges.push_back(range.clone()); +} + + +void messageSet::enumerate(messageSetEnumerator& en) const +{ + for (unsigned int i = 0, n = m_ranges.size() ; i < n ; ++i) + m_ranges[i]->enumerate(en); +} + + +bool messageSet::isEmpty() const +{ + return m_ranges.empty(); +} + + +bool messageSet::isNumberSet() const +{ + return !isEmpty() && dynamic_cast <numberMessageRange*>(m_ranges[0]) != NULL; +} + + +bool messageSet::isUIDSet() const +{ + return !isEmpty() && dynamic_cast <UIDMessageRange*>(m_ranges[0]) != NULL; +} + + +} // net +} // vmime diff --git a/src/net/pop3/POP3Folder.cpp b/src/net/pop3/POP3Folder.cpp index 9dc4589b..6a652de0 100644 --- a/src/net/pop3/POP3Folder.cpp +++ b/src/net/pop3/POP3Folder.cpp @@ -230,62 +230,36 @@ ref <message> POP3Folder::getMessage(const int num) } -std::vector <ref <message> > POP3Folder::getMessages(const int from, const int to) +std::vector <ref <message> > POP3Folder::getMessages(const messageSet& msgs) { ref <POP3Store> store = m_store.acquire(); - const int to2 = (to == -1 ? m_messageCount : to); - if (!store) throw exceptions::illegal_state("Store disconnected"); else if (!isOpen()) throw exceptions::illegal_state("Folder not open"); - else if (to2 < from || from < 1 || to2 < 1 || from > m_messageCount || to2 > m_messageCount) - throw exceptions::message_not_found(); - - std::vector <ref <message> > v; - ref <POP3Folder> thisFolder = thisRef().dynamicCast <POP3Folder>(); - - for (int i = from ; i <= to2 ; ++i) - v.push_back(vmime::create <POP3Message>(thisFolder, i)); - - return (v); -} - - -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(); -} + if (msgs.isNumberSet()) + { + const std::vector <int> numbers = POP3Utils::messageSetToNumberList(msgs); -std::vector <ref <message> > POP3Folder::getMessages(const std::vector <int>& nums) -{ - ref <POP3Store> store = m_store.acquire(); + std::vector <ref <message> > messages; + ref <POP3Folder> thisFolder = thisRef().dynamicCast <POP3Folder>(); - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); + for (std::vector <int>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) + { + if (*it < 1|| *it > m_messageCount) + throw exceptions::message_not_found(); - std::vector <ref <message> > v; - ref <POP3Folder> thisFolder = thisRef().dynamicCast <POP3Folder>(); + messages.push_back(vmime::create <POP3Message>(thisFolder, *it)); + } - for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it) + return messages; + } + else { - if (*it < 1|| *it > m_messageCount) - throw exceptions::message_not_found(); - - v.push_back(vmime::create <POP3Message>(thisFolder, *it)); + throw exceptions::operation_not_supported(); } - - return (v); } @@ -560,99 +534,11 @@ void POP3Folder::onStoreDisconnected() } -void POP3Folder::deleteMessage(const int num) +void POP3Folder::deleteMessages(const messageSet& msgs) { ref <POP3Store> store = m_store.acquire(); - if (!store) - throw exceptions::illegal_state("Store disconnected"); - else if (!isOpen()) - throw exceptions::illegal_state("Folder not open"); - - POP3Command::DELE(num)->send(store->getConnection()); - - ref <POP3Response> response = - POP3Response::readResponse(store->getConnection()); - - if (!response->isSuccess()) - throw exceptions::command_error("DELE", response->getFirstLine()); - - // Update local flags - for (std::map <POP3Message*, int>::iterator it = - m_messages.begin() ; it != m_messages.end() ; ++it) - { - POP3Message* msg = (*it).first; - - if (msg->getNumber() == num) - msg->m_deleted = true; - } - - // Notify message flags changed - std::vector <int> nums; - nums.push_back(num); - - ref <events::messageChangedEvent> event = - vmime::create <events::messageChangedEvent> - (thisRef().dynamicCast <folder>(), - events::messageChangedEvent::TYPE_FLAGS, nums); - - notifyMessageChanged(event); -} - - -void POP3Folder::deleteMessages(const int from, const int to) -{ - ref <POP3Store> 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"); - - const int to2 = (to == -1 ? m_messageCount : to); - - for (int i = from ; i <= to2 ; ++i) - { - POP3Command::DELE(i)->send(store->getConnection()); - - ref <POP3Response> response = - POP3Response::readResponse(store->getConnection()); - - if (!response->isSuccess()) - throw exceptions::command_error("DELE", response->getFirstLine()); - } - - // Update local flags - for (std::map <POP3Message*, int>::iterator it = - m_messages.begin() ; it != m_messages.end() ; ++it) - { - POP3Message* msg = (*it).first; - - if (msg->getNumber() >= from && msg->getNumber() <= to2) - msg->m_deleted = true; - } - - // Notify message flags changed - std::vector <int> nums; - - for (int i = from ; i <= to2 ; ++i) - nums.push_back(i); - - ref <events::messageChangedEvent> event = - vmime::create <events::messageChangedEvent> - (thisRef().dynamicCast <folder>(), - events::messageChangedEvent::TYPE_FLAGS, nums); - - notifyMessageChanged(event); -} - - -void POP3Folder::deleteMessages(const std::vector <int>& nums) -{ - ref <POP3Store> store = m_store.acquire(); + const std::vector <int> nums = POP3Utils::messageSetToNumberList(msgs); if (nums.empty()) throw exceptions::invalid_argument(); @@ -702,14 +588,7 @@ void POP3Folder::deleteMessages(const std::vector <int>& nums) } -void POP3Folder::setMessageFlags(const int /* from */, const int /* to */, - const int /* flags */, const int /* mode */) -{ - throw exceptions::operation_not_supported(); -} - - -void POP3Folder::setMessageFlags(const std::vector <int>& /* nums */, +void POP3Folder::setMessageFlags(const messageSet& /* msgs */, const int /* flags */, const int /* mode */) { throw exceptions::operation_not_supported(); @@ -736,19 +615,7 @@ void POP3Folder::addMessage(utility::inputStream& /* is */, const int /* size */ } -void POP3Folder::copyMessage(const folder::path& /* dest */, const int /* num */) -{ - throw exceptions::operation_not_supported(); -} - - -void POP3Folder::copyMessages(const folder::path& /* dest */, const int /* from */, const int /* to */) -{ - throw exceptions::operation_not_supported(); -} - - -void POP3Folder::copyMessages(const folder::path& /* dest */, const std::vector <int>& /* nums */) +void POP3Folder::copyMessages(const folder::path& /* dest */, const messageSet& /* msgs */) { throw exceptions::operation_not_supported(); } diff --git a/src/net/pop3/POP3Utils.cpp b/src/net/pop3/POP3Utils.cpp index f239627f..e2722104 100644 --- a/src/net/pop3/POP3Utils.cpp +++ b/src/net/pop3/POP3Utils.cpp @@ -73,6 +73,38 @@ void POP3Utils::parseMultiListOrUidlResponse(ref <POP3Response> response, std::m } + +class POP3MessageSetEnumerator : public messageSetEnumerator +{ +public: + + void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) + { + for (int i = range.getFirst(), last = range.getLast() ; i <= last ; ++i) + list.push_back(i); + } + + void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) + { + // Not supported + } + +public: + + std::vector <int> list; +}; + + +// static +const std::vector <int> POP3Utils::messageSetToNumberList(const messageSet& msgs) +{ + POP3MessageSetEnumerator en; + msgs.enumerate(en); + + return en.list; +} + + } // pop3 } // net } // vmime |