1 /*
2     SPDX-FileCopyrightText: 2015-2017 Krzysztof Nowicki <krissn@op.pl>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "ewsxml.h"
8 
9 #include <QDateTime>
10 
11 #include "ewsfolder.h"
12 #include "ewsid.h"
13 #include "ewsitem.h"
14 
15 static const QVector<QString> messageSensitivityNames = {
16     QStringLiteral("Normal"),
17     QStringLiteral("Personal"),
18     QStringLiteral("Private"),
19     QStringLiteral("Confidential"),
20 };
21 
22 static const QVector<QString> messageImportanceNames = {QStringLiteral("Low"), QStringLiteral("Normal"), QStringLiteral("High")};
23 
24 static const QVector<QString> calendarItemTypeNames = {
25     QStringLiteral("Single"),
26     QStringLiteral("Occurrence"),
27     QStringLiteral("Exception"),
28     QStringLiteral("RecurringMaster"),
29 };
30 
31 static const QVector<QString> legacyFreeBusyStatusNames = {
32     QStringLiteral("Free"),
33     QStringLiteral("Tentative"),
34     QStringLiteral("Busy"),
35     QStringLiteral("OOF"),
36     QStringLiteral("NoData"),
37 };
38 
39 static const QVector<QString> responseTypeNames = {
40     QStringLiteral("Unknown"),
41     QStringLiteral("Organizer"),
42     QStringLiteral("Tentative"),
43     QStringLiteral("Accept"),
44     QStringLiteral("Decline"),
45     QStringLiteral("NoResponseReceived"),
46 };
47 
ewsXmlBoolReader(QXmlStreamReader & reader,QVariant & val)48 bool ewsXmlBoolReader(QXmlStreamReader &reader, QVariant &val)
49 {
50     const QString elmText = reader.readElementText();
51     if (reader.error() != QXmlStreamReader::NoError) {
52         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading %1 element").arg(reader.name().toString());
53         reader.skipCurrentElement();
54         return false;
55     }
56     if (elmText == QLatin1String("true")) {
57         val = true;
58     } else if (elmText == QLatin1String("false")) {
59         val = false;
60     } else {
61         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected invalid boolean value in %1 element:").arg(reader.name().toString()) << elmText;
62         return false;
63     }
64 
65     return true;
66 }
67 
ewsXmlBoolWriter(QXmlStreamWriter & writer,const QVariant & val)68 bool ewsXmlBoolWriter(QXmlStreamWriter &writer, const QVariant &val)
69 {
70     writer.writeCharacters(val.toBool() ? QStringLiteral("true") : QStringLiteral("false"));
71 
72     return true;
73 }
74 
ewsXmlBase64Reader(QXmlStreamReader & reader,QVariant & val)75 bool ewsXmlBase64Reader(QXmlStreamReader &reader, QVariant &val)
76 {
77     QString elmName = reader.name().toString();
78     val = QByteArray::fromBase64(reader.readElementText().toLatin1());
79     if (reader.error() != QXmlStreamReader::NoError) {
80         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(elmName);
81         reader.skipCurrentElement();
82         return false;
83     }
84 
85     return true;
86 }
87 
ewsXmlBase64Writer(QXmlStreamWriter & writer,const QVariant & val)88 bool ewsXmlBase64Writer(QXmlStreamWriter &writer, const QVariant &val)
89 {
90     writer.writeCharacters(QString::fromLatin1(val.toByteArray().toBase64()));
91 
92     return true;
93 }
94 
ewsXmlIdReader(QXmlStreamReader & reader,QVariant & val)95 bool ewsXmlIdReader(QXmlStreamReader &reader, QVariant &val)
96 {
97     QString elmName = reader.name().toString();
98     EwsId id = EwsId(reader);
99     if (id.type() == EwsId::Unspecified) {
100         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(elmName);
101         reader.skipCurrentElement();
102         return false;
103     }
104     val = QVariant::fromValue(id);
105     reader.skipCurrentElement();
106     return true;
107 }
108 
ewsXmlIdWriter(QXmlStreamWriter & writer,const QVariant & val)109 bool ewsXmlIdWriter(QXmlStreamWriter &writer, const QVariant &val)
110 {
111     EwsId id = val.value<EwsId>();
112     if (id.type() == EwsId::Unspecified) {
113         return false;
114     }
115 
116     id.writeAttributes(writer);
117 
118     return true;
119 }
120 
ewsXmlTextReader(QXmlStreamReader & reader,QVariant & val)121 bool ewsXmlTextReader(QXmlStreamReader &reader, QVariant &val)
122 {
123     QString elmName = reader.name().toString();
124     val = reader.readElementText();
125     if (reader.error() != QXmlStreamReader::NoError) {
126         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(elmName);
127         reader.skipCurrentElement();
128         return false;
129     }
130     return true;
131 }
132 
ewsXmlTextWriter(QXmlStreamWriter & writer,const QVariant & val)133 bool ewsXmlTextWriter(QXmlStreamWriter &writer, const QVariant &val)
134 {
135     writer.writeCharacters(val.toString());
136 
137     return true;
138 }
139 
ewsXmlUIntReader(QXmlStreamReader & reader,QVariant & val)140 bool ewsXmlUIntReader(QXmlStreamReader &reader, QVariant &val)
141 {
142     QString elmName = reader.name().toString();
143     bool ok;
144     val = reader.readElementText().toUInt(&ok);
145     if (reader.error() != QXmlStreamReader::NoError || !ok) {
146         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(elmName);
147         return false;
148     }
149     return true;
150 }
151 
ewsXmlUIntWriter(QXmlStreamWriter & writer,const QVariant & val)152 bool ewsXmlUIntWriter(QXmlStreamWriter &writer, const QVariant &val)
153 {
154     writer.writeCharacters(QString::number(val.toUInt()));
155 
156     return true;
157 }
158 
ewsXmlDateTimeReader(QXmlStreamReader & reader,QVariant & val)159 bool ewsXmlDateTimeReader(QXmlStreamReader &reader, QVariant &val)
160 {
161     QString elmName = reader.name().toString();
162     QDateTime dt = QDateTime::fromString(reader.readElementText(), Qt::ISODate);
163     if (reader.error() != QXmlStreamReader::NoError || !dt.isValid()) {
164         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(elmName);
165         return false;
166     }
167     val = QVariant::fromValue<QDateTime>(dt);
168     return true;
169 }
170 
ewsXmlItemReader(QXmlStreamReader & reader,QVariant & val)171 bool ewsXmlItemReader(QXmlStreamReader &reader, QVariant &val)
172 {
173     QString elmName = reader.name().toString();
174     EwsItem item = EwsItem(reader);
175     if (!item.isValid()) {
176         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(elmName);
177         reader.skipCurrentElement();
178         return false;
179     }
180     val = QVariant::fromValue(item);
181     return true;
182 }
183 
ewsXmlFolderReader(QXmlStreamReader & reader,QVariant & val)184 bool ewsXmlFolderReader(QXmlStreamReader &reader, QVariant &val)
185 {
186     const QString elmName = reader.name().toString();
187     EwsFolder folder = EwsFolder(reader);
188     if (!folder.isValid()) {
189         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(elmName);
190         reader.skipCurrentElement();
191         return false;
192     }
193     val = QVariant::fromValue(folder);
194     return true;
195 }
196 
ewsXmlEnumReader(QXmlStreamReader & reader,QVariant & val,const QVector<QString> & items)197 bool ewsXmlEnumReader(QXmlStreamReader &reader, QVariant &val, const QVector<QString> &items)
198 {
199     const QString elmName = reader.name().toString();
200     QString text = reader.readElementText();
201     if (reader.error() != QXmlStreamReader::NoError) {
202         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(elmName);
203         reader.skipCurrentElement();
204         return false;
205     }
206     int i = 0;
207     QVector<QString>::const_iterator it;
208     for (it = items.cbegin(); it != items.cend(); ++it, i++) {
209         if (text == *it) {
210             val = i;
211             break;
212         }
213     }
214 
215     if (it == items.cend()) {
216         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - unknown value %2.").arg(elmName, text);
217         return false;
218     }
219     return true;
220 }
221 
ewsXmlSensitivityReader(QXmlStreamReader & reader,QVariant & val)222 bool ewsXmlSensitivityReader(QXmlStreamReader &reader, QVariant &val)
223 {
224     return ewsXmlEnumReader(reader, val, messageSensitivityNames);
225 }
226 
ewsXmlImportanceReader(QXmlStreamReader & reader,QVariant & val)227 bool ewsXmlImportanceReader(QXmlStreamReader &reader, QVariant &val)
228 {
229     return ewsXmlEnumReader(reader, val, messageImportanceNames);
230 }
231 
ewsXmlCalendarItemTypeReader(QXmlStreamReader & reader,QVariant & val)232 bool ewsXmlCalendarItemTypeReader(QXmlStreamReader &reader, QVariant &val)
233 {
234     return ewsXmlEnumReader(reader, val, calendarItemTypeNames);
235 }
236 
ewsXmlLegacyFreeBusyStatusReader(QXmlStreamReader & reader,QVariant & val)237 bool ewsXmlLegacyFreeBusyStatusReader(QXmlStreamReader &reader, QVariant &val)
238 {
239     return ewsXmlEnumReader(reader, val, legacyFreeBusyStatusNames);
240 }
241 
ewsXmlResponseTypeReader(QXmlStreamReader & reader,QVariant & val)242 bool ewsXmlResponseTypeReader(QXmlStreamReader &reader, QVariant &val)
243 {
244     return ewsXmlEnumReader(reader, val, responseTypeNames);
245 }
246 
readXmlElementValue(QXmlStreamReader & reader,bool & ok,const QString & parentElement)247 template<> QString readXmlElementValue(QXmlStreamReader &reader, bool &ok, const QString &parentElement)
248 {
249     ok = true;
250     QStringRef elmName = reader.name();
251     QString val = reader.readElementText();
252     if (reader.error() != QXmlStreamReader::NoError) {
253         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(parentElement, elmName.toString());
254         reader.skipCurrentElement();
255         val.clear();
256         ok = false;
257     }
258 
259     return val;
260 }
261 
readXmlElementValue(QXmlStreamReader & reader,bool & ok,const QString & parentElement)262 template<> int readXmlElementValue(QXmlStreamReader &reader, bool &ok, const QString &parentElement)
263 {
264     QStringRef elmName = reader.name();
265     QString valStr = readXmlElementValue<QString>(reader, ok, parentElement);
266     int val = 0;
267     if (ok) {
268         val = valStr.toInt(&ok);
269         if (!ok) {
270             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(parentElement, elmName.toString());
271         }
272     }
273 
274     return val;
275 }
276 
readXmlElementValue(QXmlStreamReader & reader,bool & ok,const QString & parentElement)277 template<> long readXmlElementValue(QXmlStreamReader &reader, bool &ok, const QString &parentElement)
278 {
279     QStringRef elmName = reader.name();
280     QString valStr = readXmlElementValue<QString>(reader, ok, parentElement);
281     long val = 0;
282     if (ok) {
283         val = valStr.toLong(&ok);
284         if (!ok) {
285             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(parentElement, elmName.toString());
286         }
287     }
288 
289     return val;
290 }
291 
readXmlElementValue(QXmlStreamReader & reader,bool & ok,const QString & parentElement)292 template<> QDateTime readXmlElementValue(QXmlStreamReader &reader, bool &ok, const QString &parentElement)
293 {
294     QStringRef elmName = reader.name();
295     QString valStr = readXmlElementValue<QString>(reader, ok, parentElement);
296     QDateTime val;
297     if (ok) {
298         val = QDateTime::fromString(valStr, Qt::ISODate);
299         if (!val.isValid()) {
300             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(parentElement, elmName.toString());
301             ok = false;
302         }
303     }
304 
305     return val;
306 }
307 
readXmlElementValue(QXmlStreamReader & reader,bool & ok,const QString & parentElement)308 template<> bool readXmlElementValue(QXmlStreamReader &reader, bool &ok, const QString &parentElement)
309 {
310     QStringRef elmName = reader.name();
311     QString valStr = readXmlElementValue<QString>(reader, ok, parentElement);
312     bool val = false;
313     if (ok) {
314         if (valStr == QLatin1String("true")) {
315             val = true;
316         } else if (valStr == QLatin1String("false")) {
317             val = false;
318         } else {
319             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(parentElement, elmName.toString());
320             ok = false;
321         }
322     }
323 
324     return val;
325 }
326 
readXmlElementValue(QXmlStreamReader & reader,bool & ok,const QString & parentElement)327 template<> QByteArray readXmlElementValue(QXmlStreamReader &reader, bool &ok, const QString &parentElement)
328 {
329     QString valStr = readXmlElementValue<QString>(reader, ok, parentElement);
330     QByteArray val;
331     if (ok) {
332         /* QByteArray::fromBase64() does not perform any input validity checks
333            and skips invalid input characters */
334         val = QByteArray::fromBase64(valStr.toLatin1());
335     }
336 
337     return val;
338 }
339