aboutsummaryrefslogtreecommitdiff
path: root/vmime-master/src/vmime/net/messageSet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vmime-master/src/vmime/net/messageSet.cpp')
-rw-r--r--vmime-master/src/vmime/net/messageSet.cpp430
1 files changed, 430 insertions, 0 deletions
diff --git a/vmime-master/src/vmime/net/messageSet.cpp b/vmime-master/src/vmime/net/messageSet.cpp
new file mode 100644
index 0000000..fe2d645
--- /dev/null
+++ b/vmime-master/src/vmime/net/messageSet.cpp
@@ -0,0 +1,430 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 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/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/messageSet.hpp"
+
+#include <iterator>
+#include <algorithm>
+#include <typeinfo>
+
+
+namespace vmime {
+namespace net {
+
+// messageSetEnumerator
+
+messageSetEnumerator::~messageSetEnumerator()
+{
+}
+
+// messageRange
+
+messageRange::messageRange() {
+
+}
+
+
+messageRange::~messageRange() {
+
+}
+
+
+// numberMessageRange
+
+numberMessageRange::numberMessageRange(const size_t number)
+ : m_first(number),
+ m_last(number) {
+
+ if (number < 1) {
+ throw std::invalid_argument("number");
+ }
+}
+
+
+numberMessageRange::numberMessageRange(const size_t first, const size_t last)
+ : m_first(first),
+ m_last(last) {
+
+ if (first < 1 || first == static_cast <size_t>(-1)) {
+ throw std::invalid_argument("first");
+ } else if (last != static_cast <size_t>(-1) && last < first) {
+ throw std::invalid_argument("last");
+ }
+}
+
+
+numberMessageRange::numberMessageRange(const numberMessageRange& other)
+ : messageRange(),
+ m_first(other.m_first),
+ m_last(other.m_last) {
+
+}
+
+
+size_t numberMessageRange::getFirst() const {
+
+ return m_first;
+}
+
+
+size_t 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 (size_t i = 0, n = other.m_ranges.size() ; i < n ; ++i) {
+ m_ranges[i] = other.m_ranges[i]->clone();
+ }
+}
+
+
+messageSet::~messageSet() {
+
+ for (size_t i = 0, n = m_ranges.size() ; i < n ; ++i) {
+ delete m_ranges[i];
+ }
+}
+
+
+// static
+messageSet messageSet::empty() {
+
+ return messageSet();
+}
+
+
+// static
+messageSet messageSet::byNumber(const size_t number) {
+
+ messageSet set;
+ set.m_ranges.push_back(new numberMessageRange(number));
+
+ return set;
+}
+
+
+// static
+messageSet messageSet::byNumber(const size_t first, const size_t last) {
+
+ messageSet set;
+ set.m_ranges.push_back(new numberMessageRange(first, last));
+
+ return set;
+}
+
+
+// static
+messageSet messageSet::byNumber(const std::vector <size_t>& numbers) {
+
+ // Sort a copy of the list
+ std::vector <size_t> 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
+ size_t previous = static_cast <size_t>(-1), rangeStart = static_cast <size_t>(-1);
+ messageSet set;
+
+ for (std::vector <size_t>::const_iterator it = sortedNumbers.begin() ;
+ it != sortedNumbers.end() ; ++it) {
+
+ const size_t current = *it;
+
+ if (current == previous) {
+ continue; // skip duplicates
+ }
+
+ if (current == static_cast <size_t>(-1)) {
+ throw std::invalid_argument("numbers");
+ }
+
+ if (previous == static_cast <size_t>(-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 (size_t i = 0, n = uids.size() ; i < n ; ++i) {
+
+ const string uid = uids[i];
+ int numericUID = 0;
+
+ const char* 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 (size_t 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 = static_cast <vmime_uint32>(-1), rangeStart = static_cast <vmime_uint32>(-1);
+ 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 == static_cast <vmime_uint32>(-1)) {
+
+ previous = current;
+ rangeStart = current;
+
+ } else {
+
+ if (current == previous + 1) {
+
+ previous = current;
+
+ } else {
+
+ set.m_ranges.push_back(
+ new UIDMessageRange(
+ utility::stringUtils::toString(rangeStart),
+ utility::stringUtils::toString(previous)
+ )
+ );
+
+ previous = current;
+ rangeStart = current;
+ }
+ }
+ }
+
+ set.m_ranges.push_back(
+ new UIDMessageRange(
+ utility::stringUtils::toString(rangeStart),
+ utility::stringUtils::toString(previous)
+ )
+ );
+
+ 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 (size_t 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;
+}
+
+
+size_t messageSet::getRangeCount() const {
+
+ return m_ranges.size();
+}
+
+
+const messageRange& messageSet::getRangeAt(const size_t i) const {
+
+ return *m_ranges[i];
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES