File indexing completed on 2025-01-05 04:50:01

0001 /*
0002     SPDX-FileCopyrightText: 2015-2016 Krzysztof Nowicki <krissn@op.pl>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "ewseventrequestbase.h"
0008 #include "ewsclient_debug.h"
0009 #include "ewsxml.h"
0010 
0011 enum NotificationElementType {
0012     InvalidNotificationElement = -1,
0013     SubscriptionId,
0014     PreviousWatermark,
0015     MoreEvents,
0016     Events,
0017 };
0018 typedef EwsXml<NotificationElementType> NotificationReader;
0019 
0020 enum EventElementType {
0021     InvalidEventElement = -1,
0022     Watermark,
0023     Timestamp,
0024     ItemId,
0025     FolderId,
0026     ParentFolderId,
0027     OldItemId,
0028     OldFolderId,
0029     OldParentFolderId,
0030     UnreadCount,
0031 };
0032 typedef EwsXml<EventElementType> EventReader;
0033 
0034 EwsEventRequestBase::EwsEventRequestBase(EwsClient &client, const QString &reqName, QObject *parent)
0035     : EwsRequest(client, parent)
0036     , mReqName(reqName)
0037 {
0038     qRegisterMetaType<EwsEventRequestBase::Event::List>();
0039 }
0040 
0041 EwsEventRequestBase::~EwsEventRequestBase()
0042 {
0043 }
0044 
0045 bool EwsEventRequestBase::parseResult(QXmlStreamReader &reader)
0046 {
0047     return parseResponseMessage(reader, mReqName, [this](QXmlStreamReader &reader) {
0048         return parseNotificationsResponse(reader);
0049     });
0050 }
0051 
0052 bool EwsEventRequestBase::parseNotificationsResponse(QXmlStreamReader &reader)
0053 {
0054     Response resp(reader);
0055     if (resp.responseClass() == EwsResponseUnknown) {
0056         return false;
0057     }
0058 
0059     if (EWSCLI_REQUEST_LOG().isDebugEnabled()) {
0060         if (resp.isSuccess()) {
0061             int numEv = 0;
0062             const auto notifications = resp.notifications();
0063             for (const Notification &nfy : notifications) {
0064                 numEv += nfy.events().size();
0065             }
0066             qCDebugNC(EWSCLI_REQUEST_LOG)
0067                 << QStringLiteral("Got %1 response (%2 notifications, %3 events)").arg(mReqName).arg(resp.notifications().size()).arg(numEv);
0068         } else {
0069             qCDebug(EWSCLI_REQUEST_LOG) << QStringLiteral("Got %1 response - %2").arg(mReqName, resp.responseMessage());
0070         }
0071     }
0072 
0073     mResponses.append(resp);
0074     return true;
0075 }
0076 
0077 EwsEventRequestBase::Response::Response(QXmlStreamReader &reader)
0078     : EwsRequest::Response(reader)
0079 {
0080     if (mClass == EwsResponseParseError) {
0081         return;
0082     }
0083 
0084     while (reader.readNextStartElement()) {
0085         if (reader.namespaceUri() != ewsMsgNsUri && reader.namespaceUri() != ewsTypeNsUri) {
0086             setErrorMsg(QStringLiteral("Unexpected namespace in %1 element: %2").arg(QStringLiteral("ResponseMessage"), reader.namespaceUri().toString()));
0087             return;
0088         }
0089 
0090         if (reader.name() == QLatin1StringView("Notification")) {
0091             Notification nfy(reader);
0092             if (!nfy.isValid()) {
0093                 setErrorMsg(QStringLiteral("Failed to process notification."));
0094                 reader.skipCurrentElement();
0095                 return;
0096             }
0097             mNotifications.append(nfy);
0098         } else if (reader.name() == QLatin1StringView("Notifications")) {
0099             while (reader.readNextStartElement()) {
0100                 if (reader.name() == QLatin1StringView("Notification")) {
0101                     Notification nfy(reader);
0102                     if (!nfy.isValid()) {
0103                         setErrorMsg(QStringLiteral("Failed to process notification."));
0104                         reader.skipCurrentElement();
0105                         return;
0106                     }
0107                     mNotifications.append(nfy);
0108                 } else {
0109                     setErrorMsg(QStringLiteral("Failed to read EWS request - expected Notification inside Notifications"));
0110                 }
0111             }
0112         } else if (reader.name() == QLatin1StringView("ConnectionStatus")) {
0113             reader.skipCurrentElement();
0114         } else if (!readResponseElement(reader)) {
0115             setErrorMsg(QStringLiteral("Failed to read EWS request - invalid response element '%1'").arg(reader.name().toString()));
0116             return;
0117         }
0118     }
0119 }
0120 
0121 EwsEventRequestBase::Notification::Notification(QXmlStreamReader &reader)
0122 {
0123     static const QList<NotificationReader::Item> items = {
0124         {SubscriptionId, QStringLiteral("SubscriptionId"), &ewsXmlTextReader},
0125         {PreviousWatermark, QStringLiteral("PreviousWatermark"), &ewsXmlTextReader},
0126         {MoreEvents, QStringLiteral("MoreEvents"), &ewsXmlBoolReader},
0127         {Events, QStringLiteral("CopiedEvent"), &eventsReader},
0128         {Events, QStringLiteral("CreatedEvent"), &eventsReader},
0129         {Events, QStringLiteral("DeletedEvent"), &eventsReader},
0130         {Events, QStringLiteral("ModifiedEvent"), &eventsReader},
0131         {Events, QStringLiteral("MovedEvent"), &eventsReader},
0132         {Events, QStringLiteral("NewMailEvent"), &eventsReader},
0133         {Events, QStringLiteral("FreeBusyChangeEvent"), &eventsReader},
0134         {Events, QStringLiteral("StatusEvent"), &eventsReader},
0135     };
0136     static const NotificationReader staticReader(items);
0137 
0138     NotificationReader ewsreader(staticReader);
0139 
0140     if (!ewsreader.readItems(reader, ewsTypeNsUri)) {
0141         return;
0142     }
0143 
0144     QHash<NotificationElementType, QVariant> values = ewsreader.values();
0145 
0146     mSubscriptionId = values[SubscriptionId].toString();
0147     mWatermark = values[PreviousWatermark].toString();
0148     mMoreEvents = values[MoreEvents].toBool();
0149     mEvents = values[Events].value<Event::List>();
0150 }
0151 
0152 bool EwsEventRequestBase::Notification::eventsReader(QXmlStreamReader &reader, QVariant &val)
0153 {
0154     Event::List events = val.value<Event::List>();
0155     const QString elmName(reader.name().toString());
0156 
0157     Event event(reader);
0158     if (!event.isValid()) {
0159         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element").arg(elmName);
0160         return false;
0161     }
0162 
0163     events.append(event);
0164 
0165     val = QVariant::fromValue<Event::List>(events);
0166     return true;
0167 }
0168 
0169 EwsEventRequestBase::Event::Event(QXmlStreamReader &reader)
0170     : mType(EwsUnknownEvent)
0171 {
0172     static const QList<EventReader::Item> items = {
0173         {Watermark, QStringLiteral("Watermark"), &ewsXmlTextReader},
0174         {Timestamp, QStringLiteral("TimeStamp"), &ewsXmlDateTimeReader},
0175         {FolderId, QStringLiteral("FolderId"), &ewsXmlIdReader},
0176         {ItemId, QStringLiteral("ItemId"), &ewsXmlIdReader},
0177         {ParentFolderId, QStringLiteral("ParentFolderId"), &ewsXmlIdReader},
0178         {OldFolderId, QStringLiteral("OldFolderId"), &ewsXmlIdReader},
0179         {OldItemId, QStringLiteral("OldItemId"), &ewsXmlIdReader},
0180         {OldParentFolderId, QStringLiteral("OldParentFolderId"), &ewsXmlIdReader},
0181         {UnreadCount, QStringLiteral("UnreadCount"), &ewsXmlUIntReader},
0182     };
0183     static const EventReader staticReader(items);
0184 
0185     EventReader ewsreader(staticReader);
0186     const QStringView elmName = reader.name();
0187     if (elmName == QLatin1StringView("CopiedEvent")) {
0188         mType = EwsCopiedEvent;
0189     } else if (elmName == QLatin1StringView("CreatedEvent")) {
0190         mType = EwsCreatedEvent;
0191     } else if (elmName == QLatin1StringView("DeletedEvent")) {
0192         mType = EwsDeletedEvent;
0193     } else if (elmName == QLatin1StringView("ModifiedEvent")) {
0194         mType = EwsModifiedEvent;
0195     } else if (elmName == QLatin1StringView("MovedEvent")) {
0196         mType = EwsMovedEvent;
0197     } else if (elmName == QLatin1StringView("NewMailEvent")) {
0198         mType = EwsNewMailEvent;
0199     } else if (elmName == QLatin1StringView("StatusEvent")) {
0200         mType = EwsStatusEvent;
0201     } else if (elmName == QLatin1StringView("FreeBusyChangedEvent")) {
0202         mType = EwsFreeBusyChangedEvent;
0203     } else {
0204         qCWarning(EWSCLI_LOG) << QStringLiteral("Unknown notification event type: %1").arg(elmName.toString());
0205         return;
0206     }
0207 
0208     if (!ewsreader.readItems(reader, ewsTypeNsUri)) {
0209         mType = EwsUnknownEvent;
0210         return;
0211     }
0212 
0213     QHash<EventElementType, QVariant> values = ewsreader.values();
0214 
0215     mWatermark = values[Watermark].toString();
0216     mTimestamp = values[Timestamp].toDateTime();
0217     if (values.contains(ItemId)) {
0218         mId = values[ItemId].value<EwsId>();
0219         mOldId = values[OldItemId].value<EwsId>();
0220         mIsFolder = false;
0221     } else {
0222         mId = values[FolderId].value<EwsId>();
0223         mOldId = values[OldFolderId].value<EwsId>();
0224         mIsFolder = true;
0225     }
0226     mParentFolderId = values[ParentFolderId].value<EwsId>();
0227     mOldParentFolderId = values[OldParentFolderId].value<EwsId>();
0228     mUnreadCount = values[UnreadCount].toUInt();
0229 
0230     if (mType == EwsStatusEvent) {
0231         qCDebugNCS(EWSCLI_LOG) << QStringLiteral(" %1").arg(elmName.toString());
0232     } else {
0233         qCDebugNCS(EWSCLI_LOG) << QStringLiteral(" %1, %2, parent: ").arg(elmName.toString()).arg(mIsFolder ? 'F' : 'I') << mParentFolderId
0234                                << QStringLiteral(", id: ") << mId;
0235     }
0236 }
0237 
0238 bool EwsEventRequestBase::Response::operator==(const Response &other) const
0239 {
0240     return mNotifications == other.mNotifications;
0241 }
0242 
0243 bool EwsEventRequestBase::Notification::operator==(const Notification &other) const
0244 {
0245     return (mSubscriptionId == other.mSubscriptionId) && (mWatermark == other.mWatermark) && (mMoreEvents == other.mMoreEvents) && (mEvents == other.mEvents);
0246 }
0247 
0248 bool EwsEventRequestBase::Event::operator==(const Event &other) const
0249 {
0250     return (mType == other.mType) && (mWatermark == other.mWatermark) && (mTimestamp == other.mTimestamp) && (mId == other.mId)
0251         && (mParentFolderId == other.mParentFolderId) && (mUnreadCount == other.mUnreadCount) && (mOldId == other.mOldId)
0252         && (mOldParentFolderId == other.mOldParentFolderId) && (mIsFolder == other.mIsFolder);
0253 }
0254 
0255 #include "moc_ewseventrequestbase.cpp"