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"