File indexing completed on 2024-09-15 04:36:26

0001 /*
0002  *  SPDX-FileCopyrightText: 2009 Volker Krause <vkrause@kde.org>
0003  *  SPDX-FileCopyrightText: 2015 Daniel Vrátil <dvratil@redhat.com>
0004  *
0005  *  SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "datastream_p_p.h"
0009 #include "scope_p.h"
0010 
0011 #include <QJsonArray>
0012 #include <QJsonObject>
0013 #include <QStringList>
0014 
0015 #include "imapset_p.h"
0016 
0017 namespace Akonadi
0018 {
0019 class ScopePrivate : public QSharedData
0020 {
0021 public:
0022     ImapSet uidSet;
0023     QStringList ridSet;
0024     QList<Scope::HRID> hridChain;
0025     QStringList gidSet;
0026     Scope::SelectionScope scope = Scope::Invalid;
0027 };
0028 
0029 Scope::HRID::HRID()
0030     : id(-1)
0031 {
0032 }
0033 
0034 Scope::HRID::HRID(qint64 id, const QString &remoteId)
0035     : id(id)
0036     , remoteId(remoteId)
0037 {
0038 }
0039 
0040 Scope::HRID::HRID(const HRID &other)
0041     : id(other.id)
0042     , remoteId(other.remoteId)
0043 {
0044 }
0045 
0046 Scope::HRID::HRID(HRID &&other) noexcept
0047     : id(other.id)
0048 {
0049     remoteId.swap(other.remoteId);
0050 }
0051 
0052 Scope::HRID &Scope::HRID::operator=(const HRID &other)
0053 {
0054     if (*this == other) {
0055         return *this;
0056     }
0057 
0058     id = other.id;
0059     remoteId = other.remoteId;
0060     return *this;
0061 }
0062 
0063 Scope::HRID &Scope::HRID::operator=(HRID &&other) noexcept
0064 {
0065     if (*this == other) {
0066         return *this;
0067     }
0068 
0069     id = other.id;
0070     remoteId.swap(other.remoteId);
0071     return *this;
0072 }
0073 
0074 bool Scope::HRID::isEmpty() const
0075 {
0076     return id <= 0 && remoteId.isEmpty();
0077 }
0078 
0079 bool Scope::HRID::operator==(const HRID &other) const
0080 {
0081     return id == other.id && remoteId == other.remoteId;
0082 }
0083 
0084 void Scope::HRID::toJson(QJsonObject &json) const
0085 {
0086     json[QStringLiteral("ID")] = id;
0087     json[QStringLiteral("RemoteID")] = remoteId;
0088 }
0089 
0090 Scope::Scope()
0091     : d(new ScopePrivate)
0092 {
0093 }
0094 
0095 Scope::Scope(qint64 id)
0096     : d(new ScopePrivate)
0097 {
0098     setUidSet(id);
0099 }
0100 
0101 Scope::Scope(const ImapSet &set)
0102     : d(new ScopePrivate)
0103 {
0104     setUidSet(set);
0105 }
0106 
0107 Scope::Scope(const ImapInterval &interval)
0108     : d(new ScopePrivate)
0109 {
0110     setUidSet(interval);
0111 }
0112 
0113 Scope::Scope(const QList<qint64> &interval)
0114     : d(new ScopePrivate)
0115 {
0116     setUidSet(interval);
0117 }
0118 
0119 Scope::Scope(SelectionScope scope, const QStringList &ids)
0120     : d(new ScopePrivate)
0121 {
0122     Q_ASSERT(scope == Rid || scope == Gid);
0123     if (scope == Rid) {
0124         d->scope = scope;
0125         d->ridSet = ids;
0126     } else if (scope == Gid) {
0127         d->scope = scope;
0128         d->gidSet = ids;
0129     }
0130 }
0131 
0132 Scope::Scope(const QList<HRID> &hrid)
0133     : d(new ScopePrivate)
0134 {
0135     d->scope = HierarchicalRid;
0136     d->hridChain = hrid;
0137 }
0138 
0139 Scope::Scope(const Scope &other)
0140     : d(other.d)
0141 {
0142 }
0143 
0144 Scope::Scope(Scope &&other) noexcept
0145 {
0146     d.swap(other.d);
0147 }
0148 
0149 Scope::~Scope()
0150 {
0151 }
0152 
0153 Scope &Scope::operator=(const Scope &other)
0154 {
0155     d = other.d;
0156     return *this;
0157 }
0158 
0159 Scope &Scope::operator=(Scope &&other) noexcept
0160 {
0161     d.swap(other.d);
0162     return *this;
0163 }
0164 
0165 bool Scope::operator==(const Scope &other) const
0166 {
0167     if (d->scope != other.d->scope) {
0168         return false;
0169     }
0170 
0171     switch (d->scope) {
0172     case Uid:
0173         return d->uidSet == other.d->uidSet;
0174     case Gid:
0175         return d->gidSet == other.d->gidSet;
0176     case Rid:
0177         return d->ridSet == other.d->ridSet;
0178     case HierarchicalRid:
0179         return d->hridChain == other.d->hridChain;
0180     case Invalid:
0181         return true;
0182     }
0183 
0184     Q_ASSERT(false);
0185     return false;
0186 }
0187 
0188 bool Scope::operator!=(const Scope &other) const
0189 {
0190     return !(*this == other);
0191 }
0192 
0193 Scope::SelectionScope Scope::scope() const
0194 {
0195     return d->scope;
0196 }
0197 
0198 bool Scope::isEmpty() const
0199 {
0200     switch (d->scope) {
0201     case Invalid:
0202         return true;
0203     case Uid:
0204         return d->uidSet.isEmpty();
0205     case Rid:
0206         return d->ridSet.isEmpty();
0207     case HierarchicalRid:
0208         return d->hridChain.isEmpty();
0209     case Gid:
0210         return d->gidSet.isEmpty();
0211     }
0212 
0213     Q_ASSERT(false);
0214     return true;
0215 }
0216 
0217 void Scope::setUidSet(const ImapSet &uidSet)
0218 {
0219     d->scope = Uid;
0220     d->uidSet = uidSet;
0221 }
0222 
0223 ImapSet Scope::uidSet() const
0224 {
0225     return d->uidSet;
0226 }
0227 
0228 void Scope::setRidSet(const QStringList &ridSet)
0229 {
0230     d->scope = Rid;
0231     d->ridSet = ridSet;
0232 }
0233 
0234 QStringList Scope::ridSet() const
0235 {
0236     return d->ridSet;
0237 }
0238 
0239 void Scope::setHRidChain(const QList<HRID> &hridChain)
0240 {
0241     d->scope = HierarchicalRid;
0242     d->hridChain = hridChain;
0243 }
0244 
0245 QList<Scope::HRID> Scope::hridChain() const
0246 {
0247     return d->hridChain;
0248 }
0249 
0250 void Scope::setGidSet(const QStringList &gidSet)
0251 {
0252     d->scope = Gid;
0253     d->gidSet = gidSet;
0254 }
0255 
0256 QStringList Scope::gidSet() const
0257 {
0258     return d->gidSet;
0259 }
0260 
0261 qint64 Scope::uid() const
0262 {
0263     if (d->uidSet.intervals().size() == 1 && d->uidSet.intervals().at(0).size() == 1) {
0264         return d->uidSet.intervals().at(0).begin();
0265     }
0266 
0267     // TODO: Error handling!
0268     return -1;
0269 }
0270 
0271 QString Scope::rid() const
0272 {
0273     if (d->ridSet.size() != 1) {
0274         // TODO: Error handling!
0275         Q_ASSERT(d->ridSet.size() == 1);
0276         return QString();
0277     }
0278     return d->ridSet.at(0);
0279 }
0280 
0281 QString Scope::gid() const
0282 {
0283     if (d->gidSet.size() != 1) {
0284         // TODO: Error handling!
0285         Q_ASSERT(d->gidSet.size() == 1);
0286         return QString();
0287     }
0288     return d->gidSet.at(0);
0289 }
0290 
0291 void Scope::toJson(QJsonObject &json) const
0292 {
0293     switch (scope()) {
0294     case Scope::Uid:
0295         json[QStringLiteral("type")] = QStringLiteral("UID");
0296         json[QStringLiteral("value")] = QString::fromUtf8(uidSet().toImapSequenceSet());
0297         break;
0298     case Scope::Rid:
0299         json[QStringLiteral("type")] = QStringLiteral("RID");
0300         json[QStringLiteral("value")] = QJsonArray::fromStringList(ridSet());
0301         break;
0302     case Scope::Gid:
0303         json[QStringLiteral("type")] = QStringLiteral("GID");
0304         json[QStringLiteral("value")] = QJsonArray::fromStringList(gidSet());
0305         break;
0306     case Scope::HierarchicalRid: {
0307         const auto &chain = hridChain();
0308         QJsonArray hridArray;
0309         for (const auto &hrid : chain) {
0310             QJsonObject obj;
0311             hrid.toJson(obj);
0312             hridArray.append(obj);
0313         }
0314         json[QStringLiteral("type")] = QStringLiteral("HRID");
0315         json[QStringLiteral("value")] = hridArray;
0316     } break;
0317     default:
0318         json[QStringLiteral("type")] = QStringLiteral("invalid");
0319         json[QStringLiteral("value")] = QJsonValue(static_cast<int>(scope()));
0320     }
0321 }
0322 
0323 Protocol::DataStream &operator<<(Protocol::DataStream &stream, const Akonadi::Scope &scope)
0324 {
0325     stream << static_cast<quint8>(scope.d->scope);
0326     switch (scope.d->scope) {
0327     case Scope::Invalid:
0328         return stream;
0329     case Scope::Uid:
0330         stream << scope.d->uidSet;
0331         return stream;
0332     case Scope::Rid:
0333         stream << scope.d->ridSet;
0334         return stream;
0335     case Scope::HierarchicalRid:
0336         stream << scope.d->hridChain;
0337         return stream;
0338     case Scope::Gid:
0339         stream << scope.d->gidSet;
0340         return stream;
0341     }
0342 
0343     return stream;
0344 }
0345 
0346 Protocol::DataStream &operator<<(Protocol::DataStream &stream, const Akonadi::Scope::HRID &hrid)
0347 {
0348     return stream << hrid.id << hrid.remoteId;
0349 }
0350 
0351 Protocol::DataStream &operator>>(Protocol::DataStream &stream, Akonadi::Scope::HRID &hrid)
0352 {
0353     return stream >> hrid.id >> hrid.remoteId;
0354 }
0355 
0356 Protocol::DataStream &operator>>(Protocol::DataStream &stream, Akonadi::Scope &scope)
0357 {
0358     scope.d->uidSet = ImapSet();
0359     scope.d->ridSet.clear();
0360     scope.d->hridChain.clear();
0361     scope.d->gidSet.clear();
0362 
0363     stream >> reinterpret_cast<quint8 &>(scope.d->scope);
0364     switch (scope.d->scope) {
0365     case Scope::Invalid:
0366         return stream;
0367     case Scope::Uid:
0368         stream >> scope.d->uidSet;
0369         return stream;
0370     case Scope::Rid:
0371         stream >> scope.d->ridSet;
0372         return stream;
0373     case Scope::HierarchicalRid:
0374         stream >> scope.d->hridChain;
0375         return stream;
0376     case Scope::Gid:
0377         stream >> scope.d->gidSet;
0378         return stream;
0379     }
0380 
0381     return stream;
0382 }
0383 
0384 } // namespace Akonadi
0385 
0386 using namespace Akonadi;
0387 
0388 QDebug operator<<(QDebug dbg, const Akonadi::Scope::HRID &hrid)
0389 {
0390     return dbg.nospace() << "(ID: " << hrid.id << ", RemoteID: " << hrid.remoteId << ")";
0391 }
0392 
0393 QDebug operator<<(QDebug dbg, const Akonadi::Scope &scope)
0394 {
0395     switch (scope.scope()) {
0396     case Scope::Uid:
0397         return dbg.nospace() << "UID " << scope.uidSet();
0398     case Scope::Rid:
0399         return dbg.nospace() << "RID " << scope.ridSet();
0400     case Scope::Gid:
0401         return dbg.nospace() << "GID " << scope.gidSet();
0402     case Scope::HierarchicalRid:
0403         return dbg.nospace() << "HRID " << scope.hridChain();
0404     default:
0405         return dbg.nospace() << "Invalid scope";
0406     }
0407 }