// // VMime library (http://www.vmime.org) // Copyright (C) 2002 Vincent Richard // // 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 #include #include 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 (-1)) { throw std::invalid_argument("first"); } else if (last != static_cast (-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 & numbers) { // Sort a copy of the list std::vector 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 (-1), rangeStart = static_cast (-1); messageSet set; for (std::vector ::const_iterator it = sortedNumbers.begin() ; it != sortedNumbers.end() ; ++it) { const size_t current = *it; if (current == previous) { continue; // skip duplicates } if (current == static_cast (-1)) { throw std::invalid_argument("numbers"); } if (previous == static_cast (-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 & uids) { std::vector 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 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 (-1), rangeStart = static_cast (-1); messageSet set; for (std::vector ::const_iterator it = sortedUIDs.begin() ; it != sortedUIDs.end() ; ++it) { const vmime_uint32 current = *it; if (current == previous) { continue; // skip duplicates } if (previous == static_cast (-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 (m_ranges[0]) != NULL; } bool messageSet::isUIDSet() const { return !isEmpty() && dynamic_cast (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