Allow messages to be designated either by their number or their UID.
Warning: this is an API-breaking change.
This commit is contained in:
parent
820d44377e
commit
b0845eff0d
@ -206,6 +206,7 @@ libvmime_messaging_sources = [
|
||||
'net/folder.cpp', 'net/folder.hpp',
|
||||
'net/folderStatus.hpp',
|
||||
'net/message.cpp', 'net/message.hpp',
|
||||
'net/messageSet.cpp', 'net/messageSet.hpp',
|
||||
'net/securedConnectionInfos.hpp',
|
||||
'net/service.cpp', 'net/service.hpp',
|
||||
'net/serviceFactory.cpp', 'net/serviceFactory.hpp',
|
||||
@ -412,6 +413,7 @@ libvmimetest_sources = [
|
||||
'tests/security/digest/md5Test.cpp',
|
||||
'tests/security/digest/sha1Test.cpp',
|
||||
# =============================== Net ================================
|
||||
'tests/net/messageSetTest.cpp',
|
||||
'tests/net/pop3/POP3CommandTest.cpp',
|
||||
'tests/net/pop3/POP3ResponseTest.cpp',
|
||||
'tests/net/pop3/POP3UtilsTest.cpp',
|
||||
|
@ -555,7 +555,9 @@ The following code shows how to list all the messages in a folder, and
|
||||
retrieve basic information to show them to the user:
|
||||
|
||||
\begin{lstlisting}[caption={Fetching information about multiple messages}]
|
||||
std::vector <ref <vmime::net::message> > allMessages = folder->getMessages();
|
||||
std::vector <ref <vmime::net::message> > allMessages =
|
||||
folder->getMessages(vmime::net::messageSet::byNumber(1, -1));
|
||||
// -1 is a special value to mean "the number of the last message in the folder"
|
||||
|
||||
folder->fetchMessages(allMessages,
|
||||
vmime::net::folder::FETCH_FLAGS |
|
||||
@ -628,17 +630,17 @@ store.
|
||||
\begin{lstlisting}[caption={Deleting messages}]
|
||||
vmime::ref <vmime::net::folder> folder = store->getDefaultFolder();
|
||||
|
||||
folder->deleteMessage(3);
|
||||
folder->deleteMessage(2);
|
||||
folder->deleteMessages(vmime::net::messageSet::byNumber(/* from */ 2, /* to */ 3));
|
||||
|
||||
// This is equivalent
|
||||
std::vector <int> nums;
|
||||
nums.push_back(2);
|
||||
nums.push_back(3);
|
||||
folder->deleteMessages(nums);
|
||||
folder->deleteMessages(vmime::net::messageSet::byNumber(nums));
|
||||
|
||||
// This is also equivalent
|
||||
folder->deleteMessages(/* from */ 2, /* to */ 3);
|
||||
// This is also equivalent (but will require 2 roundtrips to server)
|
||||
folder->deleteMessages(vmime::net::messageSet::byNumber(2));
|
||||
folder->deleteMessages(vmime::net::messageSet::byNumber(2)); // renumbered, 3 becomes 2
|
||||
\end{lstlisting}
|
||||
|
||||
\subsection{Events} % --------------------------------------------------------
|
||||
|
@ -529,63 +529,27 @@ ref <message> IMAPFolder::getMessage(const int num)
|
||||
}
|
||||
|
||||
|
||||
std::vector <ref <message> > IMAPFolder::getMessages(const int from, const int to)
|
||||
{
|
||||
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)
|
||||
std::vector <ref <message> > IMAPFolder::getMessages(const messageSet& msgs)
|
||||
{
|
||||
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> >();
|
||||
|
||||
std::vector <ref <message> > messages;
|
||||
|
||||
if (msgs.isNumberSet())
|
||||
{
|
||||
const std::vector <int> numbers = IMAPUtils::messageSetToNumberList(msgs);
|
||||
|
||||
ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>();
|
||||
|
||||
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)
|
||||
@ -596,12 +560,7 @@ std::vector <ref <message> > IMAPFolder::getMessagesByUID(const std::vector <mes
|
||||
std::ostringstream cmd;
|
||||
cmd.imbue(std::locale::classic());
|
||||
|
||||
cmd << "UID FETCH " << uids[0];
|
||||
|
||||
for (std::vector <message::uid>::size_type i = 1, n = uids.size() ; i < n ; ++i)
|
||||
cmd << "," << uids[i];
|
||||
|
||||
cmd << " UID";
|
||||
cmd << "UID FETCH " << IMAPUtils::messageSetToSequenceSet(msgs) << " UID";
|
||||
|
||||
// Send the request
|
||||
m_connection->send(true, cmd.str(), true);
|
||||
@ -619,8 +578,6 @@ std::vector <ref <message> > IMAPFolder::getMessagesByUID(const std::vector <mes
|
||||
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)
|
||||
{
|
||||
@ -660,6 +617,7 @@ std::vector <ref <message> > IMAPFolder::getMessagesByUID(const std::vector <mes
|
||||
messages.push_back(vmime::create <IMAPMessage>(thisFolder, msgNum, msgUID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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)
|
||||
void IMAPFolder::setMessageFlags(const messageSet& msgs, const int flags, const int mode)
|
||||
{
|
||||
// Build the request text
|
||||
std::ostringstream command;
|
||||
command.imbue(std::locale::classic());
|
||||
|
||||
command << "STORE " << set;
|
||||
if (msgs.isUIDSet())
|
||||
command << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
|
||||
else
|
||||
command << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
@ -1364,7 +1209,7 @@ void IMAPFolder::rename(const folder::path& newPath)
|
||||
}
|
||||
|
||||
|
||||
void IMAPFolder::copyMessage(const folder::path& dest, const int num)
|
||||
void IMAPFolder::copyMessages(const folder::path& dest, const messageSet& set)
|
||||
{
|
||||
ref <IMAPStore> store = m_store.acquire();
|
||||
|
||||
@ -1373,63 +1218,11 @@ void IMAPFolder::copyMessage(const folder::path& dest, const int num)
|
||||
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)
|
||||
{
|
||||
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 (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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -471,98 +471,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)
|
||||
{
|
||||
@ -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)
|
||||
@ -720,22 +628,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
|
||||
|
@ -419,49 +419,32 @@ ref <message> maildirFolder::getMessage(const int num)
|
||||
}
|
||||
|
||||
|
||||
std::vector <ref <message> > maildirFolder::getMessages(const int from, const int to)
|
||||
std::vector <ref <message> > maildirFolder::getMessages(const messageSet& msgs)
|
||||
{
|
||||
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)
|
||||
|
||||
if (msgs.isNumberSet())
|
||||
{
|
||||
const std::vector <int> numbers = maildirUtils::messageSetToNumberList(msgs);
|
||||
|
||||
std::vector <ref <message> > messages;
|
||||
ref <maildirFolder> thisFolder = thisRef().dynamicCast <maildirFolder>();
|
||||
|
||||
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 <maildirFolder> thisFolder = thisRef().dynamicCast <maildirFolder>();
|
||||
messages.push_back(vmime::create <maildirMessage>(thisFolder, *it));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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 */)
|
||||
{
|
||||
return messages;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw exceptions::operation_not_supported();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -590,118 +573,15 @@ void maildirFolder::rename(const folder::path& newPath)
|
||||
}
|
||||
|
||||
|
||||
void maildirFolder::deleteMessage(const int num)
|
||||
void maildirFolder::deleteMessages(const messageSet& msgs)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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())
|
||||
throw exceptions::illegal_state("Folder not open");
|
||||
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);
|
||||
|
||||
for (int i = from, j = 0 ; i <= to2 ; ++i, ++j)
|
||||
nums[j] = i;
|
||||
|
||||
// Change message flags
|
||||
setMessageFlagsImpl(nums, flags, mode);
|
||||
|
||||
// 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)
|
||||
{
|
||||
if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 &&
|
||||
(*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)
|
||||
{
|
||||
if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 &&
|
||||
(*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::setMessageFlags
|
||||
(const std::vector <int>& nums, const int flags, const int mode)
|
||||
(const messageSet& msgs, const int flags, const int mode)
|
||||
{
|
||||
ref <maildirStore> store = m_store.acquire();
|
||||
|
||||
@ -712,83 +592,11 @@ void maildirFolder::setMessageFlags
|
||||
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());
|
||||
if (msgs.isNumberSet())
|
||||
{
|
||||
const std::vector <int> nums = maildirUtils::messageSetToNumberList(msgs);
|
||||
|
||||
// Change message flags
|
||||
setMessageFlagsImpl(list, flags, mode);
|
||||
|
||||
// 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)
|
||||
{
|
||||
(*it)->m_flags |= flags;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case message::FLAG_MODE_REMOVE:
|
||||
{
|
||||
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)
|
||||
{
|
||||
(*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)
|
||||
{
|
||||
if (std::binary_search(list.begin(), list.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()->
|
||||
@ -831,6 +639,70 @@ void maildirFolder::setMessageFlagsImpl
|
||||
// Ignore (not important)
|
||||
}
|
||||
}
|
||||
|
||||
// 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(nums.begin(), nums.end(), (*it)->getNumber()) &&
|
||||
(*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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
}
|
||||
else
|
||||
{
|
||||
throw exceptions::operation_not_supported();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1032,7 +904,7 @@ void maildirFolder::copyMessageImpl(const utility::file::path& tmpDirPath,
|
||||
}
|
||||
|
||||
|
||||
void maildirFolder::copyMessage(const folder::path& dest, const int num)
|
||||
void maildirFolder::copyMessages(const folder::path& dest, const messageSet& msgs)
|
||||
{
|
||||
ref <maildirStore> store = m_store.acquire();
|
||||
|
||||
@ -1041,54 +913,6 @@ void maildirFolder::copyMessage(const folder::path& dest, const int num)
|
||||
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)
|
||||
{
|
||||
ref <maildirStore> store = m_store.acquire();
|
||||
|
||||
if (!store)
|
||||
throw exceptions::illegal_state("Store disconnected");
|
||||
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 =
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
//
|
||||
|
369
src/net/messageSet.cpp
Normal file
369
src/net/messageSet.cpp
Normal file
@ -0,0 +1,369 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
|
||||
//
|
||||
// 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
|
@ -230,42 +230,7 @@ ref <message> POP3Folder::getMessage(const int num)
|
||||
}
|
||||
|
||||
|
||||
std::vector <ref <message> > POP3Folder::getMessages(const int from, const int to)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
std::vector <ref <message> > POP3Folder::getMessages(const std::vector <int>& nums)
|
||||
std::vector <ref <message> > POP3Folder::getMessages(const messageSet& msgs)
|
||||
{
|
||||
ref <POP3Store> store = m_store.acquire();
|
||||
|
||||
@ -274,18 +239,27 @@ std::vector <ref <message> > POP3Folder::getMessages(const std::vector <int>& nu
|
||||
else if (!isOpen())
|
||||
throw exceptions::illegal_state("Folder not open");
|
||||
|
||||
std::vector <ref <message> > v;
|
||||
if (msgs.isNumberSet())
|
||||
{
|
||||
const std::vector <int> numbers = POP3Utils::messageSetToNumberList(msgs);
|
||||
|
||||
std::vector <ref <message> > messages;
|
||||
ref <POP3Folder> thisFolder = thisRef().dynamicCast <POP3Folder>();
|
||||
|
||||
for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it)
|
||||
for (std::vector <int>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it)
|
||||
{
|
||||
if (*it < 1|| *it > m_messageCount)
|
||||
throw exceptions::message_not_found();
|
||||
|
||||
v.push_back(vmime::create <POP3Message>(thisFolder, *it));
|
||||
messages.push_back(vmime::create <POP3Message>(thisFolder, *it));
|
||||
}
|
||||
|
||||
return (v);
|
||||
return messages;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw exceptions::operation_not_supported();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
200
tests/net/messageSetTest.cpp
Normal file
200
tests/net/messageSetTest.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
|
||||
//
|
||||
// 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 "tests/testUtils.hpp"
|
||||
|
||||
#include "vmime/net/messageSet.hpp"
|
||||
|
||||
|
||||
VMIME_TEST_SUITE_BEGIN(messageSetTest)
|
||||
|
||||
VMIME_TEST_LIST_BEGIN
|
||||
VMIME_TEST(testNumberSet_Single)
|
||||
VMIME_TEST(testNumberSet_Range)
|
||||
VMIME_TEST(testNumberSet_InfiniteRange)
|
||||
VMIME_TEST(testNumberSet_Multiple)
|
||||
VMIME_TEST(testUIDSet_Single)
|
||||
VMIME_TEST(testUIDSet_Range)
|
||||
VMIME_TEST(testUIDSet_InfiniteRange)
|
||||
VMIME_TEST(testUIDSet_MultipleNumeric)
|
||||
VMIME_TEST(testUIDSet_MultipleNonNumeric)
|
||||
VMIME_TEST(testIsNumberSet)
|
||||
VMIME_TEST(testIsUIDSet)
|
||||
VMIME_TEST_LIST_END
|
||||
|
||||
|
||||
class messageSetStringEnumerator : public vmime::net::messageSetEnumerator
|
||||
{
|
||||
public:
|
||||
|
||||
messageSetStringEnumerator()
|
||||
: 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;
|
||||
};
|
||||
|
||||
|
||||
const std::string enumerateAsString(const vmime::net::messageSet& set)
|
||||
{
|
||||
messageSetStringEnumerator en;
|
||||
set.enumerate(en);
|
||||
|
||||
return en.str();
|
||||
}
|
||||
|
||||
|
||||
void testNumberSet_Single()
|
||||
{
|
||||
VASSERT_EQ("str", "42", enumerateAsString(vmime::net::messageSet::byNumber(42)));
|
||||
}
|
||||
|
||||
void testNumberSet_Range()
|
||||
{
|
||||
VASSERT_EQ("str", "42:100", enumerateAsString(vmime::net::messageSet::byNumber(42, 100)));
|
||||
}
|
||||
|
||||
void testNumberSet_InfiniteRange()
|
||||
{
|
||||
VASSERT_EQ("str", "42:-1", enumerateAsString(vmime::net::messageSet::byNumber(42, -1)));
|
||||
}
|
||||
|
||||
void testNumberSet_Multiple()
|
||||
{
|
||||
std::vector <int> numbers;
|
||||
numbers.push_back(1); // test grouping 1:3
|
||||
numbers.push_back(89); // test sorting
|
||||
numbers.push_back(2);
|
||||
numbers.push_back(3);
|
||||
numbers.push_back(42);
|
||||
numbers.push_back(53); // test grouping 53:57
|
||||
numbers.push_back(54);
|
||||
numbers.push_back(55);
|
||||
numbers.push_back(56);
|
||||
numbers.push_back(56); // test duplicates
|
||||
numbers.push_back(57);
|
||||
numbers.push_back(99);
|
||||
|
||||
VASSERT_EQ("str", "1:3,42,53:57,89,99", enumerateAsString(vmime::net::messageSet::byNumber(numbers)));
|
||||
}
|
||||
|
||||
|
||||
void testUIDSet_Single()
|
||||
{
|
||||
VASSERT_EQ("str", "abcdef", enumerateAsString(vmime::net::messageSet::byUID("abcdef")));
|
||||
}
|
||||
|
||||
void testUIDSet_Range()
|
||||
{
|
||||
VASSERT_EQ("str", "abc:def", enumerateAsString(vmime::net::messageSet::byUID("abc:def")));
|
||||
}
|
||||
|
||||
void testUIDSet_InfiniteRange()
|
||||
{
|
||||
VASSERT_EQ("str", "abc:*", enumerateAsString(vmime::net::messageSet::byUID("abc", "*")));
|
||||
}
|
||||
|
||||
void testUIDSet_MultipleNumeric()
|
||||
{
|
||||
std::vector <vmime::net::message::uid> uids;
|
||||
uids.push_back("1"); // test grouping 1:3
|
||||
uids.push_back("89"); // test sorting
|
||||
uids.push_back("2");
|
||||
uids.push_back("3");
|
||||
uids.push_back("42");
|
||||
uids.push_back("53"); // test grouping 53:57
|
||||
uids.push_back("54");
|
||||
uids.push_back("55");
|
||||
uids.push_back("56");
|
||||
uids.push_back("56"); // test duplicates
|
||||
uids.push_back("57");
|
||||
uids.push_back("99");
|
||||
|
||||
VASSERT_EQ("str", "1:3,42,53:57,89,99", enumerateAsString(vmime::net::messageSet::byUID(uids)));
|
||||
}
|
||||
|
||||
void testUIDSet_MultipleNonNumeric()
|
||||
{
|
||||
std::vector <vmime::net::message::uid> uids;
|
||||
uids.push_back("12");
|
||||
uids.push_back("34");
|
||||
uids.push_back("ab56");
|
||||
uids.push_back("78cd");
|
||||
|
||||
VASSERT_EQ("str", "12,34,ab56,78cd", enumerateAsString(vmime::net::messageSet::byUID(uids)));
|
||||
}
|
||||
|
||||
void testIsNumberSet()
|
||||
{
|
||||
VASSERT_TRUE("number1", vmime::net::messageSet::byNumber(42).isNumberSet());
|
||||
VASSERT_FALSE("uid1", vmime::net::messageSet::byUID("42").isNumberSet());
|
||||
|
||||
VASSERT_TRUE("number2", vmime::net::messageSet::byNumber(42, -1).isNumberSet());
|
||||
VASSERT_FALSE("uid2", vmime::net::messageSet::byUID("42", "*").isNumberSet());
|
||||
}
|
||||
|
||||
void testIsUIDSet()
|
||||
{
|
||||
VASSERT_FALSE("number1", vmime::net::messageSet::byNumber(42).isUIDSet());
|
||||
VASSERT_TRUE("uid1", vmime::net::messageSet::byUID("42").isUIDSet());
|
||||
|
||||
VASSERT_FALSE("number2", vmime::net::messageSet::byNumber(42, -1).isUIDSet());
|
||||
VASSERT_TRUE("uid2", vmime::net::messageSet::byUID("42", "*").isUIDSet());
|
||||
}
|
||||
|
||||
VMIME_TEST_SUITE_END
|
@ -38,6 +38,7 @@
|
||||
|
||||
#include "vmime/message.hpp"
|
||||
#include "vmime/net/message.hpp"
|
||||
#include "vmime/net/messageSet.hpp"
|
||||
#include "vmime/net/events.hpp"
|
||||
#include "vmime/net/folderStatus.hpp"
|
||||
|
||||
@ -186,38 +187,34 @@ public:
|
||||
*/
|
||||
virtual ref <message> getMessage(const int num) = 0;
|
||||
|
||||
/** Get new references to messages in this folder, given their numbers.
|
||||
/** Get new references to messages in this folder, given either their
|
||||
* sequence numbers or UIDs.
|
||||
*
|
||||
* @param from sequence number of the first message to get
|
||||
* @param to sequence number of the last message to get
|
||||
* To retrieve messages by their number, use:
|
||||
* \code{.cpp}
|
||||
* // Get messages from sequence number 5 to sequence number 8 (including)
|
||||
* folder->getMessage(vmime::net::messageSet::byNumber(5, 8));
|
||||
*
|
||||
* // Get all messages in the folder, starting from number 42
|
||||
* folder->getMessage(vmime::net::messageSet::byNumber(42, -1));
|
||||
* \endcode
|
||||
* Or, to retrieve messages by their UID, use:
|
||||
* \code{.cpp}
|
||||
* // Get messages from UID 1000 to UID 1042 (including)
|
||||
* folder->getMessage(vmime::net::messageSet::byUID(1000, 1042));
|
||||
*
|
||||
* // Get message with UID 1042
|
||||
* folder->getMessage(vmime::net::messageSet::byUID(1042));
|
||||
*
|
||||
* // Get all messages in the folder, starting from UID 1000
|
||||
* folder->getMessage(vmime::net::messageSet::byUID(1000, "*"));
|
||||
* \endcode
|
||||
*
|
||||
* @param msgs index set of messages to retrieve
|
||||
* @return new objects referencing the specified messages
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual std::vector <ref <message> > getMessages(const int from = 1, const int to = -1) = 0;
|
||||
|
||||
/** Get new references to messages in this folder, given their numbers.
|
||||
*
|
||||
* @param nums sequence numbers of the messages to retrieve
|
||||
* @return new objects referencing the specified messages
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual std::vector <ref <message> > getMessages(const std::vector <int>& nums) = 0;
|
||||
|
||||
/** Get message in this folder, given its UID.
|
||||
*
|
||||
* @param uid UID of message to retrieve
|
||||
* @return a new object referencing the specified message
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual ref <message> getMessageByUID(const message::uid& uid) = 0;
|
||||
|
||||
/** Get messages in this folder, given their UIDs.
|
||||
*
|
||||
* @param uids UIDs of messages to retrieve
|
||||
* @return new objects referencing the specified messages
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids) = 0;
|
||||
virtual std::vector <ref <message> > getMessages(const messageSet& msgs) = 0;
|
||||
|
||||
/** Return the number of messages in this folder.
|
||||
*
|
||||
@ -249,46 +246,21 @@ public:
|
||||
*/
|
||||
virtual void rename(const folder::path& newPath) = 0;
|
||||
|
||||
/** Remove a message in this folder.
|
||||
*
|
||||
* @param num sequence number of the message to delete
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual void deleteMessage(const int num) = 0;
|
||||
|
||||
/** Remove one or more messages from this folder.
|
||||
*
|
||||
* @param from sequence number of the first message to delete
|
||||
* @param to sequence number of the last message to delete
|
||||
* @param msgs index set of messages to delete
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual void deleteMessages(const int from = 1, const int to = -1) = 0;
|
||||
|
||||
/** Remove one or more messages from this folder.
|
||||
*
|
||||
* @param nums sequence numbers of the messages to delete
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual void deleteMessages(const std::vector <int>& nums) = 0;
|
||||
virtual void deleteMessages(const messageSet& msgs) = 0;
|
||||
|
||||
/** Change the flags for one or more messages in this folder.
|
||||
*
|
||||
* @param from sequence number of the first message to modify
|
||||
* @param to sequence number of the last message to modify
|
||||
* @param msgs index set of messages on which to set the flags
|
||||
* @param flags set of flags (see message::Flags)
|
||||
* @param mode indicate how to treat old and new flags (see message::FlagsModes)
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET) = 0;
|
||||
|
||||
/** Change the flags for one or more messages in this folder.
|
||||
*
|
||||
* @param nums sequence numbers of the messages to modify
|
||||
* @param flags set of flags (see message::Flags)
|
||||
* @param mode indicate how to treat old and new flags (see message::FlagsModes)
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET) = 0;
|
||||
virtual void setMessageFlags(const messageSet& msgs, const int flags, const int mode = message::FLAG_MODE_SET) = 0;
|
||||
|
||||
/** Add a message to this folder.
|
||||
*
|
||||
@ -311,30 +283,13 @@ public:
|
||||
*/
|
||||
virtual void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressListener* progress = NULL) = 0;
|
||||
|
||||
/** Copy a message from this folder to another folder.
|
||||
*
|
||||
* @param dest destination folder path
|
||||
* @param num sequence number of the message to copy
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual void copyMessage(const folder::path& dest, const int num) = 0;
|
||||
|
||||
/** Copy messages from this folder to another folder.
|
||||
*
|
||||
* @param dest destination folder path
|
||||
* @param from sequence number of the first message to copy
|
||||
* @param to sequence number of the last message to copy
|
||||
* @param msgs index set of messages to copy
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual void copyMessages(const folder::path& dest, const int from = 1, const int to = -1) = 0;
|
||||
|
||||
/** Copy messages from this folder to another folder.
|
||||
*
|
||||
* @param dest destination folder path
|
||||
* @param nums sequence numbers of the messages to copy
|
||||
* @throw exceptions::net_exception if an error occurs
|
||||
*/
|
||||
virtual void copyMessages(const folder::path& dest, const std::vector <int>& nums) = 0;
|
||||
virtual void copyMessages(const folder::path& dest, const messageSet& msgs) = 0;
|
||||
|
||||
/** Request folder status without opening it.
|
||||
*
|
||||
|
@ -91,11 +91,7 @@ public:
|
||||
bool isOpen() const;
|
||||
|
||||
ref <message> getMessage(const int num);
|
||||
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
|
||||
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
|
||||
|
||||
ref <message> getMessageByUID(const message::uid& uid);
|
||||
std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids);
|
||||
std::vector <ref <message> > getMessages(const messageSet& msgs);
|
||||
|
||||
std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid);
|
||||
|
||||
@ -106,19 +102,14 @@ public:
|
||||
|
||||
void rename(const folder::path& newPath);
|
||||
|
||||
void deleteMessage(const int num);
|
||||
void deleteMessages(const int from = 1, const int to = -1);
|
||||
void deleteMessages(const std::vector <int>& nums);
|
||||
void deleteMessages(const messageSet& msgs);
|
||||
|
||||
void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
void setMessageFlags(const messageSet& msgs, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
|
||||
void addMessage(ref <vmime::message> msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressListener* progress = NULL);
|
||||
void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressListener* progress = NULL);
|
||||
|
||||
void copyMessage(const folder::path& dest, const int num);
|
||||
void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
|
||||
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
|
||||
void copyMessages(const folder::path& dest, const messageSet& msgs);
|
||||
|
||||
void status(int& count, int& unseen);
|
||||
ref <folderStatus> getStatus();
|
||||
|
@ -73,29 +73,6 @@ public:
|
||||
|
||||
static const string messageFlagList(const int flags);
|
||||
|
||||
/** Build an "IMAP set" given a list of message numbers. 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);
|
||||
|
||||
/** Build an "IMAP set" set given a list of message UIDs.
|
||||
*
|
||||
* @param list list of message UIDs
|
||||
* @return a set corresponding to the list
|
||||
*/
|
||||
static const string listToSet(const std::vector <message::uid>& list);
|
||||
|
||||
/** Format a date/time to IMAP date/time format.
|
||||
*
|
||||
* @param date date/time to format
|
||||
@ -103,25 +80,16 @@ public:
|
||||
*/
|
||||
static const string dateTime(const vmime::datetime& date);
|
||||
|
||||
/** Construct a fetch request for the specified messages, designated by their sequence numbers.
|
||||
/** Construct a fetch request for the specified messages, designated
|
||||
* either by their sequence numbers or their UIDs.
|
||||
*
|
||||
* @param cnt connection
|
||||
* @param list list of message numbers
|
||||
* @param msgs message set
|
||||
* @param options fetch options
|
||||
* @return fetch request
|
||||
*/
|
||||
static const string buildFetchRequest
|
||||
(ref <IMAPConnection> cnt, const std::vector <int>& list, const int options);
|
||||
|
||||
/** Construct a fetch request for the specified messages, designated by their UIDs.
|
||||
*
|
||||
* @param cnt connection
|
||||
* @param list list of message UIDs
|
||||
* @param options fetch options
|
||||
* @return fetch request
|
||||
*/
|
||||
static const string buildFetchRequest
|
||||
(ref <IMAPConnection> cnt, const std::vector <message::uid>& list, const int options);
|
||||
(ref <IMAPConnection> cnt, const messageSet& msgs, const int options);
|
||||
|
||||
/** Convert a parser-style address list to a mailbox list.
|
||||
*
|
||||
@ -130,6 +98,20 @@ public:
|
||||
*/
|
||||
static void convertAddressList(const IMAPParser::address_list& src, mailboxList& dest);
|
||||
|
||||
/** Returns an IMAP-formatted sequence set given a message set.
|
||||
*
|
||||
* @param msgs message set
|
||||
* @return IMAP sequence set (eg. "1:5,7,15:*")
|
||||
*/
|
||||
static const string messageSetToSequenceSet(const messageSet& msgs);
|
||||
|
||||
/** Returns a list of message sequence numbers given a message set.
|
||||
*
|
||||
* @param msgs message set
|
||||
* @return list of message numbers
|
||||
*/
|
||||
static const std::vector <int> messageSetToNumberList(const messageSet& msgs);
|
||||
|
||||
private:
|
||||
|
||||
static const string buildFetchRequestImpl
|
||||
|
@ -89,11 +89,7 @@ public:
|
||||
bool isOpen() const;
|
||||
|
||||
ref <message> getMessage(const int num);
|
||||
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
|
||||
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
|
||||
|
||||
ref <message> getMessageByUID(const message::uid& uid);
|
||||
std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids);
|
||||
std::vector <ref <message> > getMessages(const messageSet& msgs);
|
||||
|
||||
int getMessageCount();
|
||||
|
||||
@ -102,19 +98,14 @@ public:
|
||||
|
||||
void rename(const folder::path& newPath);
|
||||
|
||||
void deleteMessage(const int num);
|
||||
void deleteMessages(const int from = 1, const int to = -1);
|
||||
void deleteMessages(const std::vector <int>& nums);
|
||||
void deleteMessages(const messageSet& msgs);
|
||||
|
||||
void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
void setMessageFlags(const messageSet& msgs, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
|
||||
void addMessage(ref <vmime::message> msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressListener* progress = NULL);
|
||||
void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressListener* progress = NULL);
|
||||
|
||||
void copyMessage(const folder::path& dest, const int num);
|
||||
void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
|
||||
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
|
||||
void copyMessages(const folder::path& dest, const messageSet& msgs);
|
||||
|
||||
void status(int& count, int& unseen);
|
||||
ref <folderStatus> getStatus();
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "vmime/utility/file.hpp"
|
||||
#include "vmime/utility/path.hpp"
|
||||
|
||||
#include "vmime/net/messageSet.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
@ -129,6 +131,13 @@ public:
|
||||
* @param dir directory to delete
|
||||
*/
|
||||
static void recursiveFSDelete(ref <utility::file> dir);
|
||||
|
||||
/** Returns a list of message numbers given a message set.
|
||||
*
|
||||
* @param msgs message set
|
||||
* @return list of message numbers
|
||||
*/
|
||||
static const std::vector <int> messageSetToNumberList(const messageSet& msgs);
|
||||
};
|
||||
|
||||
|
||||
|
335
vmime/net/messageSet.hpp
Normal file
335
vmime/net/messageSet.hpp
Normal file
@ -0,0 +1,335 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_NET_MESSAGESET_HPP_INCLUDED
|
||||
#define VMIME_NET_MESSAGESET_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/net/message.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
// Forward references
|
||||
class numberMessageRange;
|
||||
class UIDMessageRange;
|
||||
|
||||
|
||||
/** Enumerator used to retrieve the message number/UID ranges contained
|
||||
* in a messageSet object.
|
||||
*/
|
||||
|
||||
class VMIME_EXPORT messageSetEnumerator
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void enumerateNumberMessageRange(const numberMessageRange& range) = 0;
|
||||
virtual void enumerateUIDMessageRange(const UIDMessageRange& range) = 0;
|
||||
};
|
||||
|
||||
|
||||
/** A range of (continuous) messages, designated either by their
|
||||
* sequence number, or by their UID.
|
||||
*/
|
||||
|
||||
class messageRange : public object
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~messageRange();
|
||||
|
||||
/** Enumerates this range with the specified enumerator.
|
||||
*
|
||||
* @param en enumerator that will receive the method calls while
|
||||
* enumerating this range
|
||||
*/
|
||||
virtual void enumerate(messageSetEnumerator& en) const = 0;
|
||||
|
||||
/** Clones this message range.
|
||||
*/
|
||||
virtual messageRange* clone() const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
messageRange();
|
||||
messageRange(const messageRange&);
|
||||
};
|
||||
|
||||
|
||||
/** A range of (continuous) messages designated by their sequence number.
|
||||
*/
|
||||
|
||||
class numberMessageRange : public messageRange
|
||||
{
|
||||
public:
|
||||
|
||||
/** Constructs a message range containing a single message.
|
||||
*
|
||||
* @param number message number (numbering starts at 1, not 0)
|
||||
*/
|
||||
numberMessageRange(const int number);
|
||||
|
||||
/** Constructs a message range for multiple messages.
|
||||
*
|
||||
* @param first number of the first message in the range (numbering
|
||||
* starts at 1, not 0)
|
||||
* @param last number of the last message in the range, or use the
|
||||
* special value -1 to designate the last message in the folder
|
||||
*/
|
||||
numberMessageRange(const int first, const int last);
|
||||
|
||||
/** Constructs a message range by copying from another range.
|
||||
*
|
||||
* @param other range to copy
|
||||
*/
|
||||
numberMessageRange(const numberMessageRange& other);
|
||||
|
||||
/** Returns the number of the first message in the range.
|
||||
*
|
||||
* @return number of the first message
|
||||
*/
|
||||
int getFirst() const;
|
||||
|
||||
/** Returns the number of the last message in the range, or -1
|
||||
* to designate the last message in the folder
|
||||
*
|
||||
* @return number of the last message
|
||||
*/
|
||||
int getLast() const;
|
||||
|
||||
void enumerate(messageSetEnumerator& en) const;
|
||||
|
||||
messageRange* clone() const;
|
||||
|
||||
private:
|
||||
|
||||
int m_first, m_last;
|
||||
};
|
||||
|
||||
|
||||
/** A range of (continuous) messages represented by their UID.
|
||||
*/
|
||||
|
||||
class UIDMessageRange : public messageRange
|
||||
{
|
||||
public:
|
||||
|
||||
/** Constructs a message range containing a single message.
|
||||
*
|
||||
* @param uid message UID
|
||||
*/
|
||||
UIDMessageRange(const message::uid& uid);
|
||||
|
||||
/** Constructs a message range for multiple messages.
|
||||
*
|
||||
* @param first UID of the first message in the range
|
||||
* @param last UID of the last message in the range, or use the
|
||||
* special value '*' to designate the last message in the folder
|
||||
*/
|
||||
UIDMessageRange(const message::uid& first, const message::uid& last);
|
||||
|
||||
/** Constructs a message range by copying from another range.
|
||||
*
|
||||
* @param other range to copy
|
||||
*/
|
||||
UIDMessageRange(const UIDMessageRange& other);
|
||||
|
||||
/** Returns the UID of the first message in the range.
|
||||
*
|
||||
* @return UID of the first message
|
||||
*/
|
||||
const message::uid getFirst() const;
|
||||
|
||||
/** Returns the UID of the last message in the range, or '*'
|
||||
* to designate the last message in the folder
|
||||
*
|
||||
* @return UID of the last message
|
||||
*/
|
||||
const message::uid getLast() const;
|
||||
|
||||
void enumerate(messageSetEnumerator& en) const;
|
||||
|
||||
messageRange* clone() const;
|
||||
|
||||
private:
|
||||
|
||||
message::uid m_first, m_last;
|
||||
};
|
||||
|
||||
|
||||
/** Represents a set of messages, designated either by their sequence
|
||||
* number, or by their UID (but not both).
|
||||
*
|
||||
* Following is example code to designate messages by their number:
|
||||
* \code{.cpp}
|
||||
* // Designate a single message with sequence number 42
|
||||
* vmime::net::messageSet::byNumber(42)
|
||||
*
|
||||
* // Designate messages from sequence number 5 to sequence number 8 (including)
|
||||
* vmime::net::messageSet::byNumber(5, 8)
|
||||
*
|
||||
* // Designate all messages in the folder, starting from number 42
|
||||
* vmime::net::messageSet::byNumber(42, -1)
|
||||
* \endcode
|
||||
* Or, to designate messages by their UID, use:
|
||||
* \code{.cpp}
|
||||
* // Designate a single message with UID 1042
|
||||
* vmime::net::messageSet::byUID(1042)
|
||||
*
|
||||
* // Designate messages from UID 1000 to UID 1042 (including)
|
||||
* vmime::net::messageSet::byUID(1000, 1042)
|
||||
*
|
||||
* // Designate all messages in the folder, starting from UID 1000
|
||||
* vmime::net::messageSet::byUID(1000, "*")
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
class VMIME_EXPORT messageSet : public object
|
||||
{
|
||||
public:
|
||||
|
||||
~messageSet();
|
||||
|
||||
messageSet(const messageSet& other);
|
||||
|
||||
/** Constructs a new message set and initializes it with a single
|
||||
* message represented by its sequence number.
|
||||
*
|
||||
* @param number message number (numbering starts at 1, not 0)
|
||||
* @return new message set
|
||||
*/
|
||||
static messageSet byNumber(const int number);
|
||||
|
||||
/** Constructs a new message set and initializes it with a range
|
||||
* of messages represented by their sequence number.
|
||||
*
|
||||
* @param first number of the first message in the range (numbering
|
||||
* starts at 1, not 0)
|
||||
* @param last number of the last message in the range, or use the
|
||||
* special value -1 to designate the last message in the folder
|
||||
* @return new message set
|
||||
*/
|
||||
static messageSet byNumber(const int first, const int last);
|
||||
|
||||
/** Constructs a new message set and initializes it with a possibly
|
||||
* unsorted list of messages represented by their sequence number.
|
||||
* Please note that numbering starts at 1, not 0.
|
||||
*
|
||||
* The function tries to group consecutive message numbers into
|
||||
* ranges to reduce the size of the resulting set.
|
||||
*
|
||||
* For example, given the list "1,2,3,4,5,7,8,13,15,16,17" it will
|
||||
* result in the following ranges: "1:5,7:8,13,15:17".
|
||||
*
|
||||
* @param numbers a vector containing numbers of the messages
|
||||
* @return new message set
|
||||
*/
|
||||
static messageSet byNumber(const std::vector <int>& numbers);
|
||||
|
||||
/** Constructs a new message set and initializes it with a single
|
||||
* message represented by its UID.
|
||||
*
|
||||
* @param uid message UID
|
||||
* @return new message set
|
||||
*/
|
||||
static messageSet byUID(const message::uid& uid);
|
||||
|
||||
/** Constructs a new message set and initializes it with a range
|
||||
* of messages represented by their sequence number.
|
||||
*
|
||||
* @param first UID of the first message in the range
|
||||
* @param last UID of the last message in the range, or use the
|
||||
* special value '*' to designate the last message in the folder
|
||||
* @return new message set
|
||||
*/
|
||||
static messageSet byUID(const message::uid& first, const message::uid& last);
|
||||
|
||||
/** Constructs a new message set and initializes it with a possibly
|
||||
* unsorted list of messages represented by their UID.
|
||||
*
|
||||
* For UIDs that actually are numbers (this is the case for IMAP), the
|
||||
* function tries to group consecutive UIDs into ranges to reduce the
|
||||
* size of the resulting set.
|
||||
*
|
||||
* For example, given the list "1,2,3,4,5,7,8,13,15,16,17" it will
|
||||
* result in the following ranges: "1:5,7:8,13,15:17".
|
||||
*
|
||||
* @param uids a vector containing UIDs of the messages
|
||||
* @return new message set
|
||||
*/
|
||||
static messageSet byUID(const std::vector <message::uid>& uids);
|
||||
|
||||
/** Adds the specified range to this set. The type of message range
|
||||
* (either number or UID) must match the type of the ranges already
|
||||
* contained in this set (ie. it's not possible to have a message
|
||||
* set which contains both number ranges and UID ranges).
|
||||
*
|
||||
* @param range range to add
|
||||
* @throw std::invalid_argument exception if the range type does
|
||||
* not match the type of the ranges in this set
|
||||
*/
|
||||
void addRange(const messageRange& range);
|
||||
|
||||
/** Enumerates this set with the specified enumerator.
|
||||
*
|
||||
* @param en enumerator that will receive the method calls while
|
||||
* enumerating the ranges in this set
|
||||
*/
|
||||
void enumerate(messageSetEnumerator& en) const;
|
||||
|
||||
/** Returns whether this set is empty (contains no range).
|
||||
*
|
||||
* @return true if this set is empty, or false otherwise
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
/** Returns whether this set references messages by their sequence
|
||||
* number.
|
||||
*
|
||||
* @return true if this set references messages by their sequence
|
||||
* number, or false otherwise
|
||||
*/
|
||||
bool isNumberSet() const;
|
||||
|
||||
/** Returns whether this set references messages by their UID.
|
||||
*
|
||||
* @return true if this set references messages by their UID,
|
||||
* or false otherwise
|
||||
*/
|
||||
bool isUIDSet() const;
|
||||
|
||||
private:
|
||||
|
||||
messageSet();
|
||||
|
||||
std::vector <messageRange*> m_ranges;
|
||||
};
|
||||
|
||||
|
||||
} // net
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_NET_MESSAGESET_HPP_INCLUDED
|
@ -86,11 +86,7 @@ public:
|
||||
bool isOpen() const;
|
||||
|
||||
ref <message> getMessage(const int num);
|
||||
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
|
||||
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
|
||||
|
||||
ref <message> getMessageByUID(const message::uid& uid);
|
||||
std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids);
|
||||
std::vector <ref <message> > getMessages(const messageSet& msgs);
|
||||
|
||||
int getMessageCount();
|
||||
|
||||
@ -99,19 +95,14 @@ public:
|
||||
|
||||
void rename(const folder::path& newPath);
|
||||
|
||||
void deleteMessage(const int num);
|
||||
void deleteMessages(const int from = 1, const int to = -1);
|
||||
void deleteMessages(const std::vector <int>& nums);
|
||||
void deleteMessages(const messageSet& msgs);
|
||||
|
||||
void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
void setMessageFlags(const messageSet& msgs, const int flags, const int mode = message::FLAG_MODE_SET);
|
||||
|
||||
void addMessage(ref <vmime::message> msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressListener* progress = NULL);
|
||||
void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressListener* progress = NULL);
|
||||
|
||||
void copyMessage(const folder::path& dest, const int num);
|
||||
void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
|
||||
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
|
||||
void copyMessages(const folder::path& dest, const messageSet& msgs);
|
||||
|
||||
void status(int& count, int& unseen);
|
||||
ref <folderStatus> getStatus();
|
||||
|
@ -35,6 +35,8 @@
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
|
||||
#include "vmime/net/messageSet.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
@ -63,6 +65,13 @@ public:
|
||||
*/
|
||||
static void parseMultiListOrUidlResponse
|
||||
(ref <POP3Response> response, std::map <int, string>& result);
|
||||
|
||||
/** Returns a list of message numbers given a message set.
|
||||
*
|
||||
* @param msgs message set
|
||||
* @return list of message numbers
|
||||
*/
|
||||
static const std::vector <int> messageSetToNumberList(const messageSet& msgs);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user