File indexing completed on 2024-09-22 04:52:51

0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net>
0002 
0003    This file is part of the Trojita Qt IMAP e-mail client,
0004    http://trojita.flaska.net/
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public License as
0008    published by the Free Software Foundation; either version 2 of
0009    the License or (at your option) version 3 or any later version
0010    accepted by the membership of KDE e.V. (or its successor approved
0011    by the membership of KDE e.V.), which shall act as a proxy
0012    defined in Section 14 of version 3 of the license.
0013 
0014    This program is distributed in the hope that it will be useful,
0015    but WITHOUT ANY WARRANTY; without even the implied warranty of
0016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017    GNU General Public License for more details.
0018 
0019    You should have received a copy of the GNU General Public License
0020    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include "Sequence.h"
0024 #include <QStringList>
0025 #include <QTextStream>
0026 #include <algorithm>
0027 
0028 namespace Imap
0029 {
0030 
0031 Sequence::Sequence(const uint num): kind(DISTINCT)
0032 {
0033     numbers << num;
0034 }
0035 
0036 Sequence Sequence::startingAt(const uint lo)
0037 {
0038     Sequence res(lo);
0039     res.lo = lo;
0040     res.kind = UNLIMITED;
0041     return res;
0042 }
0043 
0044 QByteArray Sequence::toByteArray() const
0045 {
0046     switch (kind) {
0047     case DISTINCT:
0048     {
0049         Q_ASSERT(! numbers.isEmpty());
0050 
0051         QStringList res;
0052         int i = 0;
0053         while (i < numbers.size()) {
0054             int old = i;
0055             while (i < numbers.size() - 1 &&
0056                    numbers[i] == numbers[ i + 1 ] - 1)
0057                 ++i;
0058             if (old != i) {
0059                 // we've found a sequence
0060                 res << QString::number(numbers[old]) + QLatin1Char(':') + QString::number(numbers[i]);
0061             } else {
0062                 res << QString::number(numbers[i]);
0063             }
0064             ++i;
0065         }
0066         return res.join(QStringLiteral(",")).toLocal8Bit();
0067     }
0068     case RANGE:
0069         Q_ASSERT(lo <= hi);
0070         if (lo == hi)
0071             return QByteArray::number(lo);
0072         else
0073             return QByteArray::number(lo) + ':' + QByteArray::number(hi);
0074     case UNLIMITED:
0075         return QByteArray::number(lo) + ":*";
0076     }
0077     // fix gcc warning
0078     Q_ASSERT(false);
0079     return QByteArray();
0080 }
0081 
0082 Imap::Uids Sequence::toVector() const
0083 {
0084     switch (kind) {
0085     case DISTINCT:
0086         Q_ASSERT(!numbers.isEmpty());
0087         return numbers;
0088     case RANGE:
0089         Q_ASSERT(lo <= hi);
0090         if (lo == hi) {
0091             return Imap::Uids() << lo;
0092         } else {
0093             Imap::Uids res;
0094             for (uint i = lo; i < hi; ++i)
0095                 res << i;
0096             return res;
0097         }
0098     case UNLIMITED:
0099         Q_ASSERT(false);
0100         return Imap::Uids();
0101     }
0102     Q_ASSERT(false);
0103     return Imap::Uids();
0104 }
0105 
0106 Sequence &Sequence::add(uint num)
0107 {
0108     Q_ASSERT(kind == DISTINCT);
0109     auto it = std::lower_bound(numbers.begin(), numbers.end(), num);
0110     if (it == numbers.end() || *it != num)
0111         numbers.insert(it, num);
0112     return *this;
0113 }
0114 
0115 Sequence Sequence::fromVector(Imap::Uids numbers)
0116 {
0117     Q_ASSERT(!numbers.isEmpty());
0118     std::sort(numbers.begin(), numbers.end());
0119     Sequence seq(numbers.first());
0120     for (int i = 1; i < numbers.size(); ++i) {
0121         seq.add(numbers[i]);
0122     }
0123     return seq;
0124 }
0125 
0126 bool Sequence::isValid() const
0127 {
0128     if (kind == DISTINCT && numbers.isEmpty())
0129         return false;
0130     else
0131         return true;
0132 }
0133 
0134 QTextStream &operator<<(QTextStream &stream, const Sequence &s)
0135 {
0136     return stream << s.toByteArray();
0137 }
0138 
0139 bool operator==(const Sequence &a, const Sequence &b)
0140 {
0141     // This operator is used only in the test suite, so performance doesn't matter and this was *so* easy to hack together...
0142     return a.toVector() == b.toVector();
0143 }
0144 
0145 }