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

0001 /*
0002     SPDX-FileCopyrightText: 2015-2017 Krzysztof Nowicki <krissn@op.pl>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <functional>
0010 
0011 #include <QList>
0012 #include <QXmlStreamReader>
0013 
0014 #include "ewsclient_debug.h"
0015 
0016 template<typename T>
0017 class EwsXml
0018 {
0019 public:
0020     typedef std::function<bool(QXmlStreamReader &, QVariant &)> ReadFunction;
0021     typedef std::function<bool(QXmlStreamWriter &, const QVariant &)> WriteFunction;
0022     typedef std::function<bool(QXmlStreamReader &, const QString &)> UnknownElementFunction;
0023 
0024     typedef QHash<T, QVariant> ValueHash;
0025 
0026     static constexpr T Ignore = static_cast<T>(-1);
0027 
0028     struct Item {
0029         Item()
0030             : key(Ignore)
0031         {
0032         }
0033 
0034         Item(T k, const QString &n, const ReadFunction &rfn = ReadFunction(), const WriteFunction &wfn = WriteFunction())
0035             : key(k)
0036             , elmName(n)
0037             , readFn(rfn)
0038             , writeFn(wfn)
0039         {
0040         }
0041 
0042         T key;
0043         QString elmName;
0044         ReadFunction readFn;
0045         WriteFunction writeFn;
0046     };
0047 
0048     EwsXml()
0049     {
0050     }
0051 
0052     EwsXml(const QList<Item> &items)
0053         : mItems(items)
0054     {
0055         rebuildItemHash();
0056     }
0057 
0058     EwsXml(const EwsXml &other)
0059         : mItems(other.mItems)
0060         , mValues(other.mValues)
0061         , mItemHash(other.mItemHash)
0062     {
0063     }
0064 
0065     void setItems(const QList<Item> &items)
0066     {
0067         mItems = items;
0068         rebuildItemHash();
0069     }
0070 
0071     bool readItem(QXmlStreamReader &reader, const QString &parentElm, const QString &nsUri, UnknownElementFunction unknownElmFn = &defaultUnknownElmFunction)
0072     {
0073         typename QHash<QString, Item>::iterator it = mItemHash.find(reader.name().toString());
0074         if (it != mItemHash.end() && nsUri == reader.namespaceUri()) {
0075             if (it->key == Ignore) {
0076                 qCInfoNC(EWSCLI_LOG) << QStringLiteral("Unsupported %1 child element %2 - ignoring.").arg(parentElm, reader.name().toString());
0077                 reader.skipCurrentElement();
0078                 return true;
0079             } else if (!it->readFn) {
0080                 qCWarning(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - no read support for %2 element.").arg(parentElm, reader.name().toString());
0081                 return false;
0082             } else {
0083                 QVariant val = mValues[it->key];
0084                 if (it->readFn(reader, val)) {
0085                     mValues[it->key] = val;
0086                     return true;
0087                 }
0088                 return false;
0089             }
0090         }
0091         return unknownElmFn(reader, parentElm);
0092     }
0093 
0094     bool readItems(QXmlStreamReader &reader, const QString &nsUri, const UnknownElementFunction &unknownElmFn = &defaultUnknownElmFunction)
0095     {
0096         QString elmName(reader.name().toString());
0097         while (reader.readNextStartElement()) {
0098             if (!readItem(reader, elmName, nsUri, unknownElmFn)) {
0099                 return false;
0100             }
0101         }
0102         return true;
0103     }
0104 
0105     bool writeItems(QXmlStreamWriter &writer,
0106                     const QString &parentElm,
0107                     const QString &nsUri,
0108                     const ValueHash &values,
0109                     const QList<T> &keysToWrite = QList<T>()) const
0110     {
0111         bool hasKeysToWrite = !keysToWrite.isEmpty();
0112         for (const Item &item : std::as_const(mItems)) {
0113             if (!hasKeysToWrite || keysToWrite.contains(item.key)) {
0114                 typename ValueHash::const_iterator it = values.find(item.key);
0115                 if (it != values.end()) {
0116                     if (!item.writeFn) {
0117                         qCWarning(EWSCLI_LOG) << QStringLiteral("Failed to write %1 element - no write support for %2 element.").arg(parentElm, item.elmName);
0118                         return false;
0119                     }
0120                     writer.writeStartElement(nsUri, item.elmName);
0121                     bool status = item.writeFn(writer, *it);
0122                     writer.writeEndElement();
0123                     if (!status) {
0124                         return false;
0125                     }
0126                 }
0127             }
0128         }
0129         return true;
0130     }
0131 
0132     ValueHash values() const
0133     {
0134         return mValues;
0135     }
0136 
0137 private:
0138     static bool defaultUnknownElmFunction(QXmlStreamReader &reader, const QString &parentElm)
0139     {
0140         qCWarning(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(parentElm, reader.name().toString());
0141         return false;
0142     }
0143 
0144     const QList<Item> mItems;
0145     ValueHash mValues;
0146     QHash<QString, Item> mItemHash;
0147 
0148     void rebuildItemHash()
0149     {
0150         for (const Item &item : std::as_const(mItems)) {
0151             mItemHash.insert(item.elmName, item);
0152         }
0153     }
0154 };
0155 
0156 template<typename T>
0157 T readXmlElementValue(QXmlStreamReader &reader, bool &ok, const QString &parentElement);
0158 
0159 extern bool ewsXmlBoolReader(QXmlStreamReader &reader, QVariant &val);
0160 extern bool ewsXmlBoolWriter(QXmlStreamWriter &writer, const QVariant &val);
0161 extern bool ewsXmlBase64Reader(QXmlStreamReader &reader, QVariant &val);
0162 extern bool ewsXmlBase64Writer(QXmlStreamWriter &writer, const QVariant &val);
0163 extern bool ewsXmlIdReader(QXmlStreamReader &reader, QVariant &val);
0164 extern bool ewsXmlIdWriter(QXmlStreamWriter &writer, const QVariant &val);
0165 extern bool ewsXmlTextReader(QXmlStreamReader &reader, QVariant &val);
0166 extern bool ewsXmlTextWriter(QXmlStreamWriter &writer, const QVariant &val);
0167 extern bool ewsXmlUIntReader(QXmlStreamReader &reader, QVariant &val);
0168 extern bool ewsXmlUIntWriter(QXmlStreamWriter &writer, const QVariant &val);
0169 extern bool ewsXmlDateTimeReader(QXmlStreamReader &reader, QVariant &val);
0170 extern bool ewsXmlItemReader(QXmlStreamReader &reader, QVariant &val);
0171 extern bool ewsXmlFolderReader(QXmlStreamReader &reader, QVariant &val);
0172 
0173 extern bool ewsXmlEnumReader(QXmlStreamReader &reader, QVariant &val, const QList<QString> &items);
0174 extern bool ewsXmlSensitivityReader(QXmlStreamReader &reader, QVariant &val);
0175 extern bool ewsXmlImportanceReader(QXmlStreamReader &reader, QVariant &val);
0176 extern bool ewsXmlCalendarItemTypeReader(QXmlStreamReader &reader, QVariant &val);
0177 extern bool ewsXmlLegacyFreeBusyStatusReader(QXmlStreamReader &reader, QVariant &val);
0178 extern bool ewsXmlResponseTypeReader(QXmlStreamReader &reader, QVariant &val);