File indexing completed on 2024-05-12 05:17:13

0001 /*
0002     SPDX-FileCopyrightText: 2009 Andras Mantia <amantia@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "getmetadatajob.h"
0008 
0009 #include "kimap_debug.h"
0010 #include <KLocalizedString>
0011 
0012 #include "metadatajobbase_p.h"
0013 #include "response_p.h"
0014 #include "rfccodecs.h"
0015 #include "session_p.h"
0016 
0017 namespace KIMAP
0018 {
0019 class GetMetaDataJobPrivate : public MetaDataJobBasePrivate
0020 {
0021 public:
0022     GetMetaDataJobPrivate(Session *session, const QString &name)
0023         : MetaDataJobBasePrivate(session, name)
0024         , depth("0")
0025     {
0026     }
0027     ~GetMetaDataJobPrivate()
0028     {
0029     }
0030 
0031     qint64 maxSize = -1;
0032     QByteArray depth;
0033     QSet<QByteArray> entries;
0034     QSet<QByteArray> attributes;
0035     QMap<QString, QMap<QByteArray, QMap<QByteArray, QByteArray>>> metadata;
0036     //    ^ mailbox        ^ entry          ^attribute  ^ value
0037 };
0038 }
0039 
0040 using namespace KIMAP;
0041 
0042 GetMetaDataJob::GetMetaDataJob(Session *session)
0043     : MetaDataJobBase(*new GetMetaDataJobPrivate(session, i18n("GetMetaData")))
0044 {
0045 }
0046 
0047 GetMetaDataJob::~GetMetaDataJob()
0048 {
0049 }
0050 
0051 static QList<QByteArray> sort(const QSet<QByteArray> &set)
0052 {
0053     QList<QByteArray> sortedEntries = set.values();
0054     std::sort(sortedEntries.begin(), sortedEntries.end());
0055     return sortedEntries;
0056 }
0057 
0058 void GetMetaDataJob::doStart()
0059 {
0060     Q_D(GetMetaDataJob);
0061     QByteArray parameters;
0062     parameters = '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + "\" ";
0063 
0064     QByteArray command = "GETMETADATA";
0065     if (d->serverCapability == Annotatemore) {
0066         d->m_name = i18n("GetAnnotation");
0067         command = "GETANNOTATION";
0068         if (d->entries.size() > 1) {
0069             parameters += '(';
0070         }
0071         const auto sortedEntries = sort(d->entries);
0072         for (const QByteArray &entry : sortedEntries) {
0073             parameters += '\"' + entry + "\" ";
0074         }
0075         if (d->entries.size() > 1) {
0076             parameters[parameters.length() - 1] = ')';
0077             parameters += ' ';
0078         }
0079 
0080         if (d->attributes.size() > 1) {
0081             parameters += '(';
0082         }
0083         const auto sortedAttributes = sort(d->attributes);
0084         for (const QByteArray &attribute : sortedAttributes) {
0085             parameters += '\"' + attribute + "\" ";
0086         }
0087         if (d->attributes.size() > 1) {
0088             parameters[parameters.length() - 1] = ')';
0089         } else {
0090             parameters.chop(1);
0091         }
0092 
0093     } else {
0094         QByteArray options;
0095         if (d->depth != "0") {
0096             options = "DEPTH " + d->depth;
0097         }
0098         if (d->maxSize != -1) {
0099             if (!options.isEmpty()) {
0100                 options += ' ';
0101             }
0102             options += "MAXSIZE " + QByteArray::number(d->maxSize);
0103         }
0104 
0105         if (!options.isEmpty()) {
0106             parameters = "(" + options + ") " + parameters;
0107         }
0108 
0109         if (d->entries.size() >= 1) {
0110             parameters += '(';
0111             const auto sortedEntries = sort(d->entries);
0112             for (const QByteArray &entry : sortedEntries) {
0113                 parameters += entry + " ";
0114             }
0115             parameters[parameters.length() - 1] = ')';
0116         } else {
0117             parameters.chop(1);
0118         }
0119     }
0120 
0121     d->tags << d->sessionInternal()->sendCommand(command, parameters);
0122     //  qCDebug(KIMAP_LOG) << "SENT: " << command << " " << parameters;
0123 }
0124 
0125 void GetMetaDataJob::handleResponse(const Response &response)
0126 {
0127     Q_D(GetMetaDataJob);
0128     //  qCDebug(KIMAP_LOG) << "GOT: " << response.toString();
0129 
0130     // TODO: handle NO error messages having [METADATA MAXSIZE NNN], [METADATA TOOMANY], [METADATA NOPRIVATE] (see rfc5464)
0131     // or [ANNOTATEMORE TOOBIG], [ANNOTATEMORE TOOMANY] respectively
0132     if (handleErrorReplies(response) == NotHandled) {
0133         if (response.content.size() >= 4) {
0134             if (d->serverCapability == Annotatemore && response.content[1].toString() == "ANNOTATION") {
0135                 QString mailBox = QString::fromUtf8(KIMAP::decodeImapFolderName(response.content[2].toString()));
0136 
0137                 int i = 3;
0138                 while (i < response.content.size() - 1) {
0139                     QByteArray entry = response.content[i].toString();
0140                     QList<QByteArray> attributes = response.content[i + 1].toList();
0141                     int j = 0;
0142                     while (j < attributes.size() - 1) {
0143                         d->metadata[mailBox][entry][attributes[j]] = attributes[j + 1];
0144                         j += 2;
0145                     }
0146                     i += 2;
0147                 }
0148             } else if (d->serverCapability == Metadata && response.content[1].toString() == "METADATA") {
0149                 QString mailBox = QString::fromUtf8(KIMAP::decodeImapFolderName(response.content[2].toString()));
0150 
0151                 const QList<QByteArray> &entries = response.content[3].toList();
0152                 int i = 0;
0153                 while (i < entries.size() - 1) {
0154                     const QByteArray &value = entries[i + 1];
0155                     QByteArray &targetValue = d->metadata[mailBox][entries[i]][""];
0156                     if (value != "NIL") { // This just indicates no value
0157                         targetValue = value;
0158                     }
0159                     i += 2;
0160                 }
0161             }
0162         }
0163     }
0164 }
0165 
0166 void GetMetaDataJob::addEntry(const QByteArray &entry, const QByteArray &attribute)
0167 {
0168     Q_D(GetMetaDataJob);
0169     if (d->serverCapability == Annotatemore && attribute.isNull()) {
0170         qCWarning(KIMAP_LOG) << "In ANNOTATEMORE mode an attribute must be specified with addEntry!";
0171     }
0172     d->entries.insert(entry);
0173     d->attributes.insert(attribute);
0174 }
0175 
0176 void GetMetaDataJob::addRequestedEntry(const QByteArray &entry)
0177 {
0178     Q_D(GetMetaDataJob);
0179     d->entries.insert(d->removePrefix(entry));
0180     d->attributes.insert(d->getAttribute(entry));
0181 }
0182 
0183 void GetMetaDataJob::setMaximumSize(qint64 size)
0184 {
0185     Q_D(GetMetaDataJob);
0186     d->maxSize = size;
0187 }
0188 
0189 void GetMetaDataJob::setDepth(Depth depth)
0190 {
0191     Q_D(GetMetaDataJob);
0192 
0193     switch (depth) {
0194     case OneLevel:
0195         d->depth = "1"; // krazy:exclude=doublequote_chars
0196         break;
0197     case AllLevels:
0198         d->depth = "infinity";
0199         break;
0200     default:
0201         d->depth = "0"; // krazy:exclude=doublequote_chars
0202     }
0203 }
0204 
0205 QByteArray GetMetaDataJob::metaData(const QString &mailBox, const QByteArray &entry, const QByteArray &attribute) const
0206 {
0207     Q_D(const GetMetaDataJob);
0208     QByteArray attr = attribute;
0209 
0210     if (d->serverCapability == Metadata) {
0211         attr = "";
0212     }
0213 
0214     QByteArray result;
0215     if (d->metadata.contains(mailBox)) {
0216         if (d->metadata[mailBox].contains(entry)) {
0217             result = d->metadata[mailBox][entry].value(attr);
0218         }
0219     }
0220     return result;
0221 }
0222 
0223 QByteArray GetMetaDataJob::metaData(const QByteArray &entry) const
0224 {
0225     qCDebug(KIMAP_LOG) << entry;
0226     Q_D(const GetMetaDataJob);
0227     return d->metadata.value(d->mailBox).value(d->removePrefix(entry)).value(d->getAttribute(entry));
0228 }
0229 
0230 QMap<QByteArray, QMap<QByteArray, QByteArray>> GetMetaDataJob::allMetaData(const QString &mailBox) const
0231 {
0232     Q_D(const GetMetaDataJob);
0233     return d->metadata[mailBox];
0234 }
0235 
0236 QMap<QByteArray, QByteArray> GetMetaDataJob::allMetaData() const
0237 {
0238     Q_D(const GetMetaDataJob);
0239     return allMetaDataForMailbox(d->mailBox);
0240 }
0241 
0242 QMap<QByteArray, QByteArray> GetMetaDataJob::allMetaDataForMailbox(const QString &mailbox) const
0243 {
0244     Q_D(const GetMetaDataJob);
0245     const QMap<QByteArray, QMap<QByteArray, QByteArray>> &entries = d->metadata[mailbox];
0246     QMap<QByteArray, QByteArray> map;
0247     const auto entriesKeys = entries.keys();
0248     for (const QByteArray &entry : entriesKeys) {
0249         const QMap<QByteArray, QByteArray> &values = entries[entry];
0250         const auto valuesKeys = values.keys();
0251         for (const QByteArray &attribute : valuesKeys) {
0252             map.insert(d->addPrefix(entry, attribute), values[attribute]);
0253         }
0254     }
0255     return map;
0256 }
0257 
0258 QHash<QString, QMap<QByteArray, QByteArray>> GetMetaDataJob::allMetaDataForMailboxes() const
0259 {
0260     Q_D(const GetMetaDataJob);
0261     QHash<QString, QMap<QByteArray, QByteArray>> mailboxHash;
0262 
0263     QMapIterator<QString, QMap<QByteArray, QMap<QByteArray, QByteArray>>> i(d->metadata);
0264     while (i.hasNext()) {
0265         i.next();
0266         mailboxHash.insert(i.key(), allMetaDataForMailbox(i.key()));
0267     }
0268     return mailboxHash;
0269 }
0270 
0271 #include "moc_getmetadatajob.cpp"