File indexing completed on 2024-12-01 04:48:10

0001 /*
0002     SPDX-FileCopyrightText: 2009 Kevin Ottens <ervin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "imapquotaattribute.h"
0008 
0009 #include <QByteArray>
0010 #include <QString>
0011 #include <QStringList>
0012 
0013 #include <QDebug>
0014 
0015 using namespace Akonadi;
0016 
0017 ImapQuotaAttribute::ImapQuotaAttribute() = default;
0018 
0019 Akonadi::ImapQuotaAttribute::ImapQuotaAttribute(const QList<QByteArray> &roots,
0020                                                 const QList<QMap<QByteArray, qint64>> &limits,
0021                                                 const QList<QMap<QByteArray, qint64>> &usages)
0022     : mRoots(roots)
0023     , mLimits(limits)
0024     , mUsages(usages)
0025 {
0026     Q_ASSERT(roots.size() == limits.size());
0027     Q_ASSERT(roots.size() == usages.size());
0028 }
0029 
0030 void Akonadi::ImapQuotaAttribute::setQuotas(const QList<QByteArray> &roots,
0031                                             const QList<QMap<QByteArray, qint64>> &limits,
0032                                             const QList<QMap<QByteArray, qint64>> &usages)
0033 {
0034     Q_ASSERT(roots.size() == limits.size());
0035     Q_ASSERT(roots.size() == usages.size());
0036 
0037     mRoots = roots;
0038     mLimits = limits;
0039     mUsages = usages;
0040 }
0041 
0042 QList<QByteArray> Akonadi::ImapQuotaAttribute::roots() const
0043 {
0044     return mRoots;
0045 }
0046 
0047 QList<QMap<QByteArray, qint64>> Akonadi::ImapQuotaAttribute::limits() const
0048 {
0049     return mLimits;
0050 }
0051 
0052 QList<QMap<QByteArray, qint64>> Akonadi::ImapQuotaAttribute::usages() const
0053 {
0054     return mUsages;
0055 }
0056 
0057 QByteArray ImapQuotaAttribute::type() const
0058 {
0059     static const QByteArray sType("imapquota");
0060     return sType;
0061 }
0062 
0063 Akonadi::Attribute *ImapQuotaAttribute::clone() const
0064 {
0065     return new ImapQuotaAttribute(mRoots, mLimits, mUsages);
0066 }
0067 
0068 QByteArray ImapQuotaAttribute::serialized() const
0069 {
0070     QByteArray result = "";
0071 
0072     // First the roots list
0073     for (const QByteArray &root : std::as_const(mRoots)) {
0074         result += root + " % ";
0075     }
0076     result.chop(3);
0077 
0078     result += " %%%% "; // Members separator
0079 
0080     // Then the limit maps list
0081     for (int i = 0; i < mLimits.size(); ++i) {
0082         const QMap<QByteArray, qint64> limits = mLimits[i];
0083         for (auto it = limits.cbegin(), end = limits.cend(); it != end; ++it) {
0084             result += it.key();
0085             result += " % "; // We use this separator as '%' is not allowed in keys or values
0086             result += QByteArray::number(it.value());
0087             result += " %% "; // Pairs separator
0088         }
0089         result.chop(4);
0090         result += " %%% "; // Maps separator
0091     }
0092     result.chop(5);
0093 
0094     result += " %%%% "; // Members separator
0095 
0096     // Then the usage maps list
0097     for (int i = 0; i < mUsages.size(); ++i) {
0098         const QMap<QByteArray, qint64> usages = mUsages[i];
0099         for (auto it = usages.cbegin(), end = usages.cend(); it != end; ++it) {
0100             result += it.key();
0101             result += " % "; // We use this separator as '%' is not allowed in keys or values
0102             result += QByteArray::number(it.value());
0103             result += " %% "; // Pairs separator
0104         }
0105         result.chop(4);
0106         result += " %%% "; // Maps separator
0107     }
0108     result.chop(5);
0109 
0110     return result;
0111 }
0112 
0113 void ImapQuotaAttribute::deserialize(const QByteArray &data)
0114 {
0115     mRoots.clear();
0116     mLimits.clear();
0117     mUsages.clear();
0118 
0119     // Nothing was saved.
0120     if (data.trimmed().isEmpty()) {
0121         return;
0122     }
0123 
0124     QString string = QString::fromUtf8(data); // QByteArray has no proper split, so we're forced to convert to QString...
0125 
0126     QStringList members = string.split(QStringLiteral("%%%%"));
0127 
0128     // We expect exactly three members (roots, limits and usages), otherwise something is funky
0129     if (members.size() != 3) {
0130         qWarning() << "We didn't find exactly three members in this quota serialization";
0131         return;
0132     }
0133 
0134     QStringList roots = members[0].trimmed().split(QStringLiteral(" % "));
0135     for (const QString &root : std::as_const(roots)) {
0136         mRoots << root.trimmed().toUtf8();
0137     }
0138 
0139     const QStringList allLimits = members[1].trimmed().split(QStringLiteral("%%%"));
0140 
0141     for (const QString &limits : std::as_const(allLimits)) {
0142         QMap<QByteArray, qint64> limitsMap;
0143         const QStringList strLines = limits.split(QStringLiteral("%%"));
0144         QList<QByteArray> lines;
0145         lines.reserve(strLines.count());
0146         for (const QString &strLine : strLines) {
0147             lines << strLine.trimmed().toUtf8();
0148         }
0149 
0150         for (const QByteArray &line : std::as_const(lines)) {
0151             QByteArray trimmed = line.trimmed();
0152             int wsIndex = trimmed.indexOf('%');
0153             const QByteArray key = trimmed.mid(0, wsIndex).trimmed();
0154             const QByteArray value = trimmed.mid(wsIndex + 1, line.length() - wsIndex).trimmed();
0155             limitsMap[key] = value.toLongLong();
0156         }
0157 
0158         mLimits << limitsMap;
0159     }
0160 
0161     const QStringList allUsages = members[2].trimmed().split(QStringLiteral("%%%"));
0162     mUsages.reserve(allUsages.count());
0163 
0164     for (const QString &usages : std::as_const(allUsages)) {
0165         QMap<QByteArray, qint64> usagesMap;
0166         const QStringList strLines = usages.split(QStringLiteral("%%"));
0167         QList<QByteArray> lines;
0168         lines.reserve(strLines.count());
0169         for (const QString &strLine : std::as_const(strLines)) {
0170             lines << strLine.trimmed().toUtf8();
0171         }
0172 
0173         for (const QByteArray &line : std::as_const(lines)) {
0174             QByteArray trimmed = line.trimmed();
0175             int wsIndex = trimmed.indexOf('%');
0176             const QByteArray key = trimmed.mid(0, wsIndex).trimmed();
0177             const QByteArray value = trimmed.mid(wsIndex + 1, line.length() - wsIndex).trimmed();
0178             usagesMap[key] = value.toLongLong();
0179         }
0180 
0181         mUsages << usagesMap;
0182     }
0183 }