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

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