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

0001 /*
0002     SPDX-FileCopyrightText: 2009 Andras Mantia <amantia@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "setmetadatajob.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 SetMetaDataJobPrivate : public MetaDataJobBasePrivate
0020 {
0021 public:
0022     SetMetaDataJobPrivate(Session *session, const QString &name)
0023         : MetaDataJobBasePrivate(session, name)
0024         , metaDataErrors({})
0025         , maxAcceptedSize(-1)
0026     {
0027     }
0028     ~SetMetaDataJobPrivate()
0029     {
0030     }
0031 
0032     QMap<QByteArray, QByteArray> entries;
0033     QMap<QByteArray, QByteArray>::ConstIterator entriesIt;
0034     QByteArray entryName;
0035     SetMetaDataJob::MetaDataErrors metaDataErrors;
0036     qint64 maxAcceptedSize;
0037 };
0038 }
0039 
0040 using namespace KIMAP;
0041 
0042 SetMetaDataJob::SetMetaDataJob(Session *session)
0043     : MetaDataJobBase(*new SetMetaDataJobPrivate(session, i18n("SetMetaData")))
0044 {
0045 }
0046 
0047 SetMetaDataJob::~SetMetaDataJob()
0048 {
0049 }
0050 
0051 void SetMetaDataJob::doStart()
0052 {
0053     Q_D(SetMetaDataJob);
0054     QByteArray parameters = '\"' + KIMAP::encodeImapFolderName(d->mailBox.toUtf8()) + "\" ";
0055     d->entriesIt = d->entries.constBegin();
0056 
0057     QByteArray command = "SETMETADATA";
0058     bool bSimpleData = true;
0059 
0060     if (d->serverCapability == Annotatemore) {
0061         command = "SETANNOTATION";
0062         parameters += '\"' + d->entryName + "\" ";
0063     } else {
0064         for (; d->entriesIt != d->entries.constEnd(); ++d->entriesIt) {
0065             if (d->entriesIt.value().contains('\r') || d->entriesIt.value().contains('\n')) {
0066                 bSimpleData = false;
0067                 break;
0068             }
0069         }
0070         d->entriesIt = d->entries.constBegin();
0071     }
0072 
0073     parameters += '(';
0074     if (bSimpleData == true) {
0075         for (; d->entriesIt != d->entries.constEnd(); ++d->entriesIt) {
0076             parameters += '\"' + d->entriesIt.key() + "\" ";
0077             if (d->entriesIt.value().isEmpty()) {
0078                 parameters += "NIL";
0079             } else {
0080                 parameters += "\"" + d->entriesIt.value() + "\"";
0081             }
0082             parameters += " ";
0083         }
0084         parameters[parameters.length() - 1] = ')';
0085     } else {
0086         if (!d->entries.isEmpty()) {
0087             parameters += '\"' + d->entriesIt.key() + "\"";
0088             int size = d->entriesIt.value().size();
0089             parameters += " {" + QByteArray::number(size == 0 ? 3 : size) + '}';
0090         }
0091     }
0092 
0093     if (d->entries.isEmpty()) {
0094         parameters += ')';
0095     }
0096 
0097     d->tags << d->sessionInternal()->sendCommand(command, parameters);
0098     //   qCDebug(KIMAP_LOG) << "SENT: " << command << " " << parameters;
0099 }
0100 
0101 void SetMetaDataJob::handleResponse(const Response &response)
0102 {
0103     Q_D(SetMetaDataJob);
0104 
0105     // TODO: Test if a server can really return more then one untagged NO response. If not, no need to OR the error codes
0106     if (!response.content.isEmpty() && d->tags.contains(response.content.first().toString())) {
0107         if (response.content[1].toString() == "NO") {
0108             setError(UserDefinedError);
0109             setErrorText(i18n("%1 failed, server replied: %2", d->m_name, QLatin1StringView(response.toString().constData())));
0110             const QByteArray responseBa = response.content[2].toString();
0111             if (responseBa == "[ANNOTATEMORE TOOMANY]" || responseBa == "[METADATA TOOMANY]") {
0112                 d->metaDataErrors |= TooMany;
0113             } else if (responseBa == "[ANNOTATEMORE TOOBIG]" || responseBa.startsWith("[METADATA MAXSIZE")) { // krazy:exclude=strings
0114                 d->metaDataErrors |= TooBig;
0115                 d->maxAcceptedSize = -1;
0116                 if (responseBa.startsWith("[METADATA MAXSIZE")) { // krazy:exclude=strings
0117                     QByteArray max = responseBa;
0118                     max.replace("[METADATA MAXSIZE", ""); // krazy:exclude=doublequote_chars
0119                     max.replace("]", ""); // krazy:exclude=doublequote_chars
0120                     d->maxAcceptedSize = max.toLongLong();
0121                 }
0122             } else if (responseBa == "[METADATA NOPRIVATE]") {
0123                 d->metaDataErrors |= NoPrivate;
0124             }
0125         } else if (response.content.size() < 2) {
0126             setErrorText(i18n("%1 failed, malformed reply from the server.", d->m_name));
0127         } else if (response.content[1].toString() != "OK") {
0128             setError(UserDefinedError);
0129             setErrorText(i18n("%1 failed, server replied: %2", d->m_name, QLatin1StringView(response.toString().constData())));
0130         }
0131         emitResult();
0132     } else if (d->serverCapability == Metadata && response.content[0].toString() == "+") {
0133         QByteArray content = "";
0134         if (d->entriesIt.value().isEmpty()) {
0135             content += "NIL";
0136         } else {
0137             content += d->entriesIt.value();
0138         }
0139         ++d->entriesIt;
0140         if (d->entriesIt == d->entries.constEnd()) {
0141             content += ')';
0142         } else {
0143             content += " \"" + d->entriesIt.key() + '\"';
0144             int size = d->entriesIt.value().size();
0145             content += " {" + QByteArray::number(size == 0 ? 3 : size) + '}';
0146         }
0147         //      qCDebug(KIMAP_LOG) << "SENT: " << content;
0148         d->sessionInternal()->sendData(content);
0149     }
0150 }
0151 
0152 void SetMetaDataJob::addMetaData(const QByteArray &name, const QByteArray &value)
0153 {
0154     Q_D(SetMetaDataJob);
0155     if (d->serverCapability == Annotatemore && (name.startsWith("/shared") || name.startsWith("/private"))) {
0156         const QByteArray &attribute = d->getAttribute(name);
0157         d->entries[attribute] = value;
0158         d->entryName = d->removePrefix(name);
0159     } else {
0160         d->entries[name] = value;
0161     }
0162 }
0163 
0164 void SetMetaDataJob::setEntry(const QByteArray &entry)
0165 {
0166     Q_D(SetMetaDataJob);
0167     d->entryName = entry;
0168 }
0169 
0170 SetMetaDataJob::MetaDataErrors SetMetaDataJob::metaDataErrors() const
0171 {
0172     Q_D(const SetMetaDataJob);
0173     return d->metaDataErrors;
0174 }
0175 
0176 #include "moc_setmetadatajob.cpp"