File indexing completed on 2024-12-22 04:57:01

0001 /*
0002     SPDX-FileCopyrightText: 2015-2017 Krzysztof Nowicki <krissn@op.pl>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "ewsfindfolderrequest.h"
0008 
0009 #include <memory>
0010 
0011 #include <QXmlStreamWriter>
0012 
0013 #include "ewsclient_debug.h"
0014 
0015 static const QString traversalTypeNames[] = {
0016     QStringLiteral("Shallow"),
0017     QStringLiteral("Deep"),
0018     QStringLiteral("SoftDeleted"),
0019 };
0020 
0021 class EwsFindFolderResponse : public EwsRequest::Response
0022 {
0023 public:
0024     EwsFindFolderResponse(QXmlStreamReader &reader);
0025     bool parseRootFolder(QXmlStreamReader &reader);
0026     EwsFolder *readFolder(QXmlStreamReader &reader);
0027     unsigned readChildFolders(EwsFolder &parent, unsigned count, QXmlStreamReader &reader);
0028 
0029     QList<EwsFolder> mFolders;
0030 };
0031 
0032 EwsFindFolderRequest::EwsFindFolderRequest(EwsClient &client, QObject *parent)
0033     : EwsRequest(client, parent)
0034     , mTraversal(EwsTraversalDeep)
0035 {
0036 }
0037 
0038 EwsFindFolderRequest::~EwsFindFolderRequest()
0039 {
0040 }
0041 
0042 void EwsFindFolderRequest::setParentFolderId(const EwsId &id)
0043 {
0044     mParentId = id;
0045 }
0046 
0047 void EwsFindFolderRequest::setFolderShape(const EwsFolderShape &shape)
0048 {
0049     mShape = shape;
0050 }
0051 
0052 void EwsFindFolderRequest::start()
0053 {
0054     QString reqString;
0055     QXmlStreamWriter writer(&reqString);
0056 
0057     startSoapDocument(writer);
0058 
0059     writer.writeStartElement(ewsMsgNsUri, QStringLiteral("FindFolder"));
0060     writer.writeAttribute(QStringLiteral("Traversal"), traversalTypeNames[mTraversal]);
0061 
0062     mShape.write(writer);
0063 
0064     writer.writeStartElement(ewsMsgNsUri, QStringLiteral("ParentFolderIds"));
0065     mParentId.writeFolderIds(writer);
0066     writer.writeEndElement();
0067 
0068     writer.writeEndElement();
0069 
0070     endSoapDocument(writer);
0071 
0072     qCDebug(EWSCLI_PROTO_LOG) << reqString;
0073 
0074     prepare(reqString);
0075 
0076     doSend();
0077 }
0078 
0079 bool EwsFindFolderRequest::parseResult(QXmlStreamReader &reader)
0080 {
0081     return parseResponseMessage(reader, QStringLiteral("FindFolder"), [this](QXmlStreamReader &reader) {
0082         return parseFoldersResponse(reader);
0083     });
0084 }
0085 
0086 bool EwsFindFolderRequest::parseFoldersResponse(QXmlStreamReader &reader)
0087 {
0088     auto resp = new EwsFindFolderResponse(reader);
0089     if (resp->responseClass() == EwsResponseUnknown) {
0090         return false;
0091     }
0092 
0093     mFolders = resp->mFolders;
0094 
0095     return true;
0096 }
0097 
0098 EwsFindFolderResponse::EwsFindFolderResponse(QXmlStreamReader &reader)
0099     : EwsRequest::Response(reader)
0100 {
0101     while (reader.readNextStartElement()) {
0102         if (reader.namespaceUri() != ewsMsgNsUri && reader.namespaceUri() != ewsTypeNsUri) {
0103             setErrorMsg(QStringLiteral("Unexpected namespace in %1 element: %2").arg(QStringLiteral("ResponseMessage"), reader.namespaceUri().toString()));
0104             return;
0105         }
0106 
0107         if (reader.name() == QLatin1StringView("RootFolder")) {
0108             if (!parseRootFolder(reader)) {
0109                 return;
0110             }
0111         } else if (!readResponseElement(reader)) {
0112             setErrorMsg(QStringLiteral("Failed to read EWS request - invalid response element."));
0113             return;
0114         }
0115     }
0116 }
0117 
0118 bool EwsFindFolderResponse::parseRootFolder(QXmlStreamReader &reader)
0119 {
0120     if (reader.namespaceUri() != ewsMsgNsUri || reader.name() != QLatin1StringView("RootFolder")) {
0121         return setErrorMsg(
0122             QStringLiteral("Failed to read EWS request - expected %1 element (got %2).").arg(QStringLiteral("RootFolder"), reader.qualifiedName().toString()));
0123     }
0124 
0125     if (!reader.attributes().hasAttribute(QStringLiteral("TotalItemsInView")) || !reader.attributes().hasAttribute(QStringLiteral("TotalItemsInView"))) {
0126         return setErrorMsg(QStringLiteral("Failed to read EWS request - missing attributes of %1 element.").arg(QStringLiteral("RootFolder")));
0127     }
0128     bool ok;
0129     unsigned totalItems = reader.attributes().value(QStringLiteral("TotalItemsInView")).toUInt(&ok);
0130     if (!ok) {
0131         return setErrorMsg(QStringLiteral("Failed to read EWS request - failed to read %1 attribute.").arg(QStringLiteral("TotalItemsInView")));
0132     }
0133 
0134     if (!reader.readNextStartElement()) {
0135         return setErrorMsg(QStringLiteral("Failed to read EWS request - expected a child element in %1 element.").arg(QStringLiteral("RootFolder")));
0136     }
0137 
0138     if (reader.namespaceUri() != ewsTypeNsUri || reader.name() != QLatin1StringView("Folders")) {
0139         return setErrorMsg(
0140             QStringLiteral("Failed to read EWS request - expected %1 element (got %2).").arg(QStringLiteral("Folders"), reader.qualifiedName().toString()));
0141     }
0142 
0143     if (!reader.readNextStartElement()) {
0144         return setErrorMsg(QStringLiteral("Failed to read EWS request - expected a child element in %1 element.").arg(QStringLiteral("Folders")));
0145     }
0146 
0147     if (reader.namespaceUri() != ewsTypeNsUri) {
0148         return setErrorMsg(QStringLiteral("Failed to read EWS request - expected child element from types namespace."));
0149     }
0150 
0151     unsigned i = 0;
0152     for (i = 0; i < totalItems; ++i) {
0153         EwsFolder *folder = readFolder(reader);
0154         reader.readNextStartElement();
0155         if (folder) {
0156             bool okInt;
0157             int childCount = (*folder)[EwsFolderFieldChildFolderCount].toUInt(&okInt);
0158             if (childCount > 0) {
0159                 unsigned readCount = readChildFolders(*folder, childCount, reader);
0160                 if (readCount == 0) {
0161                     return false;
0162                 }
0163                 i += readCount;
0164             }
0165             mFolders.append(*folder);
0166             delete folder;
0167         }
0168     }
0169 
0170     // Finish the Folders element
0171     reader.skipCurrentElement();
0172 
0173     // Finish the RootFolder element
0174     reader.skipCurrentElement();
0175 
0176     return true;
0177 }
0178 
0179 EwsFolder *EwsFindFolderResponse::readFolder(QXmlStreamReader &reader)
0180 {
0181     EwsFolder *folder = nullptr;
0182     const QStringView readerName = reader.name();
0183     if (readerName == QLatin1StringView("Folder") || readerName == QLatin1StringView("CalendarFolder") || readerName == QLatin1StringView("ContactsFolder")
0184         || readerName == QLatin1StringView("TasksFolder") || readerName == QLatin1StringView("SearchFolder")) {
0185         folder = new EwsFolder(reader);
0186         if (!folder->isValid()) {
0187             setErrorMsg(QStringLiteral("Failed to read EWS request - invalid %1 element.").arg(QStringLiteral("Folder")));
0188             delete folder;
0189             return nullptr;
0190         }
0191         QVariant dn = (*folder)[EwsFolderFieldDisplayName];
0192         if (!dn.isNull()) {
0193             EwsClient::folderHash[(*folder)[EwsFolderFieldFolderId].value<EwsId>().id()] = dn.toString();
0194         }
0195     } else {
0196         qCWarning(EWSCLI_LOG).noquote() << QStringLiteral("Unsupported folder type %1").arg(readerName.toString());
0197         reader.skipCurrentElement();
0198     }
0199 
0200     return folder;
0201 }
0202 
0203 unsigned EwsFindFolderResponse::readChildFolders(EwsFolder &parent, unsigned count, QXmlStreamReader &reader)
0204 {
0205     unsigned readCount = 0;
0206     for (unsigned i = 0; i < count; ++i) {
0207         EwsFolder *folder = readFolder(reader);
0208         reader.readNextStartElement();
0209         if (folder) {
0210             bool ok;
0211             int childCount = (*folder)[EwsFolderFieldChildFolderCount].toUInt(&ok);
0212             if (ok && childCount > 0) {
0213                 unsigned readCount2 = readChildFolders(*folder, childCount, reader);
0214                 if (readCount2 == 0) {
0215                     return false;
0216                 }
0217                 readCount += readCount2;
0218             }
0219             parent.addChild(*folder);
0220         }
0221         ++readCount;
0222     }
0223     return readCount;
0224 }
0225 
0226 #include "moc_ewsfindfolderrequest.cpp"