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

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 "ewssyncfolderitemsrequest.h"
0008 
0009 #include <memory>
0010 
0011 #include <QXmlStreamWriter>
0012 
0013 #include "ewsclient_debug.h"
0014 #include "ewsxml.h"
0015 
0016 enum SyncFolderItemsResponseElementType {
0017     SyncFolderItemsResponseElementInvalid = -1,
0018     SyncState,
0019     IncludesLastItemInRange,
0020     Changes,
0021 };
0022 
0023 enum SyncFolderItemsChangeElementType {
0024     SyncFolderITemsChangeElemnentInvalid = -1,
0025     Item,
0026     ItemId,
0027     IsRead,
0028 };
0029 
0030 class EwsSyncFolderItemsRequest::Response : public EwsRequest::Response
0031 {
0032 public:
0033     Response(QXmlStreamReader &reader);
0034 
0035     static bool changeReader(QXmlStreamReader &reader, QVariant &val);
0036 
0037     EwsSyncFolderItemsRequest::Change::List mChanges;
0038     bool mIncludesLastItem;
0039     QString mSyncState;
0040 };
0041 
0042 EwsSyncFolderItemsRequest::EwsSyncFolderItemsRequest(EwsClient &client, QObject *parent)
0043     : EwsRequest(client, parent)
0044     , mMaxChanges(100)
0045     , mIncludesLastItem(false)
0046 {
0047     qRegisterMetaType<EwsSyncFolderItemsRequest::Change::List>();
0048     qRegisterMetaType<EwsItem>();
0049 }
0050 
0051 EwsSyncFolderItemsRequest::~EwsSyncFolderItemsRequest() = default;
0052 
0053 void EwsSyncFolderItemsRequest::setFolderId(const EwsId &id)
0054 {
0055     mFolderId = id;
0056 }
0057 
0058 void EwsSyncFolderItemsRequest::setItemShape(const EwsItemShape &shape)
0059 {
0060     mShape = shape;
0061 }
0062 
0063 void EwsSyncFolderItemsRequest::setSyncState(const QString &state)
0064 {
0065     mSyncState = state;
0066 }
0067 
0068 void EwsSyncFolderItemsRequest::setMaxChanges(uint max)
0069 {
0070     mMaxChanges = max;
0071 }
0072 
0073 void EwsSyncFolderItemsRequest::start()
0074 {
0075     QString reqString;
0076     QXmlStreamWriter writer(&reqString);
0077 
0078     startSoapDocument(writer);
0079 
0080     writer.writeStartElement(ewsMsgNsUri, QStringLiteral("SyncFolderItems"));
0081 
0082     mShape.write(writer);
0083 
0084     writer.writeStartElement(ewsMsgNsUri, QStringLiteral("SyncFolderId"));
0085     mFolderId.writeFolderIds(writer);
0086     writer.writeEndElement();
0087 
0088     if (!mSyncState.isNull()) {
0089         writer.writeTextElement(ewsMsgNsUri, QStringLiteral("SyncState"), mSyncState);
0090     }
0091 
0092     writer.writeTextElement(ewsMsgNsUri, QStringLiteral("MaxChangesReturned"), QString::number(mMaxChanges));
0093 
0094     writer.writeEndElement();
0095 
0096     endSoapDocument(writer);
0097 
0098     qCDebug(EWSCLI_PROTO_LOG) << reqString;
0099 
0100     if (EWSCLI_REQUEST_LOG().isDebugEnabled()) {
0101         QString st = mSyncState.isNull() ? QStringLiteral("none") : ewsHash(mSyncState);
0102         qCDebugNCS(EWSCLI_REQUEST_LOG) << QStringLiteral("Starting SyncFolderItems request (folder: ") << mFolderId << QStringLiteral(", state: %1").arg(st);
0103     }
0104 
0105     prepare(reqString);
0106 
0107     doSend();
0108 }
0109 
0110 bool EwsSyncFolderItemsRequest::parseResult(QXmlStreamReader &reader)
0111 {
0112     return parseResponseMessage(reader, QStringLiteral("SyncFolderItems"), [this](QXmlStreamReader &reader) {
0113         return parseItemsResponse(reader);
0114     });
0115 }
0116 
0117 bool EwsSyncFolderItemsRequest::parseItemsResponse(QXmlStreamReader &reader)
0118 {
0119     QScopedPointer<EwsSyncFolderItemsRequest::Response> resp(new EwsSyncFolderItemsRequest::Response(reader));
0120     if (resp->responseClass() == EwsResponseUnknown) {
0121         return false;
0122     }
0123 
0124     mChanges = resp->mChanges;
0125     mIncludesLastItem = resp->mIncludesLastItem;
0126     mSyncState = resp->mSyncState;
0127 
0128     if (EWSCLI_REQUEST_LOG().isDebugEnabled()) {
0129         if (resp->isSuccess()) {
0130             qCDebugNC(EWSCLI_REQUEST_LOG) << QStringLiteral("Got SyncFolderItems response (%1 changes, last included: %2, state: %3)")
0131                                                  .arg(mChanges.size())
0132                                                  .arg(mIncludesLastItem ? QStringLiteral("true") : QStringLiteral("false"))
0133                                                  .arg(qHash(mSyncState), 0, 36);
0134         } else {
0135             qCDebugNC(EWSCLI_REQUEST_LOG) << QStringLiteral("Got SyncFolderItems response - %1").arg(resp->responseMessage());
0136         }
0137     }
0138 
0139     return true;
0140 }
0141 
0142 EwsSyncFolderItemsRequest::Response::Response(QXmlStreamReader &reader)
0143     : EwsRequest::Response(reader)
0144 {
0145     if (mClass == EwsResponseParseError) {
0146         return;
0147     }
0148 
0149     static const QList<EwsXml<SyncFolderItemsResponseElementType>::Item> items = {
0150         {SyncState, QStringLiteral("SyncState"), &ewsXmlTextReader},
0151         {IncludesLastItemInRange, QStringLiteral("IncludesLastItemInRange"), &ewsXmlBoolReader},
0152         {Changes, QStringLiteral("Changes"), &EwsSyncFolderItemsRequest::Response::changeReader},
0153     };
0154     static const EwsXml<SyncFolderItemsResponseElementType> staticReader(items);
0155 
0156     EwsXml<SyncFolderItemsResponseElementType> ewsReader(staticReader);
0157 
0158     if (!ewsReader.readItems(reader, ewsMsgNsUri, [this](QXmlStreamReader &reader, const QString &) {
0159             if (!readResponseElement(reader)) {
0160                 setErrorMsg(QStringLiteral("Failed to read EWS request - invalid response element."));
0161                 return false;
0162             }
0163             return true;
0164         })) {
0165         mClass = EwsResponseParseError;
0166         return;
0167     }
0168 
0169     QHash<SyncFolderItemsResponseElementType, QVariant> values = ewsReader.values();
0170 
0171     mSyncState = values[SyncState].toString();
0172     mIncludesLastItem = values[IncludesLastItemInRange].toBool();
0173     mChanges = values[Changes].value<Change::List>();
0174 }
0175 
0176 bool EwsSyncFolderItemsRequest::Response::changeReader(QXmlStreamReader &reader, QVariant &val)
0177 {
0178     Change::List changes;
0179     QString elmName(reader.name().toString());
0180 
0181     while (reader.readNextStartElement()) {
0182         Change change(reader);
0183         if (!change.isValid()) {
0184             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element").arg(elmName);
0185             return false;
0186         }
0187         changes.append(change);
0188     }
0189 
0190     val = QVariant::fromValue<Change::List>(changes);
0191     return true;
0192 }
0193 
0194 EwsSyncFolderItemsRequest::Change::Change(QXmlStreamReader &reader)
0195 {
0196     static const QList<EwsXml<SyncFolderItemsChangeElementType>::Item> items = {
0197         {Item, QStringLiteral("Item"), &ewsXmlItemReader},
0198         {Item, QStringLiteral("Message"), &ewsXmlItemReader},
0199         {Item, QStringLiteral("CalendarItem"), &ewsXmlItemReader},
0200         {Item, QStringLiteral("Contact"), &ewsXmlItemReader},
0201         {Item, QStringLiteral("DistributionList"), &ewsXmlItemReader},
0202         {Item, QStringLiteral("MeetingMessage"), &ewsXmlItemReader},
0203         {Item, QStringLiteral("MeetingRequest"), &ewsXmlItemReader},
0204         {Item, QStringLiteral("MeetingResponse"), &ewsXmlItemReader},
0205         {Item, QStringLiteral("MeetingCancellation"), &ewsXmlItemReader},
0206         {Item, QStringLiteral("Task"), &ewsXmlItemReader},
0207         {ItemId, QStringLiteral("ItemId"), &ewsXmlIdReader},
0208         {IsRead, QStringLiteral("IsRead"), &ewsXmlBoolReader},
0209     };
0210     static const EwsXml<SyncFolderItemsChangeElementType> staticReader(items);
0211 
0212     EwsXml<SyncFolderItemsChangeElementType> ewsReader(staticReader);
0213 
0214     if (reader.name() == QLatin1StringView("Create")) {
0215         mType = Create;
0216     } else if (reader.name() == QLatin1StringView("Update")) {
0217         mType = Update;
0218     } else if (reader.name() == QLatin1StringView("Delete")) {
0219         mType = Delete;
0220     } else if (reader.name() == QLatin1StringView("ReadFlagChange")) {
0221         mType = ReadFlagChange;
0222     }
0223     if (!ewsReader.readItems(reader, ewsTypeNsUri)) {
0224         return;
0225     }
0226 
0227     QHash<SyncFolderItemsChangeElementType, QVariant> values = ewsReader.values();
0228 
0229     switch (mType) {
0230     case Create:
0231     case Update:
0232         mItem = values[Item].value<EwsItem>();
0233         mId = mItem[EwsItemFieldItemId].value<EwsId>();
0234         break;
0235     case ReadFlagChange:
0236         mIsRead = values[IsRead].toBool();
0237         /* fall through */
0238         [[fallthrough]];
0239     case Delete:
0240         mId = values[ItemId].value<EwsId>();
0241         break;
0242     default:
0243         break;
0244     }
0245 }
0246 
0247 #include "moc_ewssyncfolderitemsrequest.cpp"