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 "ewspropertyfield.h"
8 
9 #include <QString>
10 
11 #include "ewsclient_debug.h"
12 
13 static const QString distinguishedPropSetIdNames[] = {
14     QStringLiteral("Meeting"),
15     QStringLiteral("Appointment"),
16     QStringLiteral("Common"),
17     QStringLiteral("PublicStrings"),
18     QStringLiteral("Address"),
19     QStringLiteral("InternetHeaders"),
20     QStringLiteral("CalendarAssistant"),
21     QStringLiteral("UnifiedMessaging"),
22 };
23 
24 static const QString propertyTypeNames[] = {
25     QStringLiteral("ApplicationTime"),
26     QStringLiteral("ApplicationTimeArray"),
27     QStringLiteral("Binary"),
28     QStringLiteral("BinaryArray"),
29     QStringLiteral("Boolean"),
30     QStringLiteral("CLSID"),
31     QStringLiteral("CLSIDArray"),
32     QStringLiteral("Currency"),
33     QStringLiteral("CurrencyArray"),
34     QStringLiteral("Double"),
35     QStringLiteral("DoubleArray"),
36     QStringLiteral("Error"),
37     QStringLiteral("Float"),
38     QStringLiteral("FloatArray"),
39     QStringLiteral("Integer"),
40     QStringLiteral("IntegerArray"),
41     QStringLiteral("Long"),
42     QStringLiteral("LongArray"),
43     QStringLiteral("Null"),
44     QStringLiteral("Object"),
45     QStringLiteral("ObjectArray"),
46     QStringLiteral("Short"),
47     QStringLiteral("ShortArray"),
48     QStringLiteral("SystemTime"),
49     QStringLiteral("SystemTimeArray"),
50     QStringLiteral("String"),
51     QStringLiteral("StringArray"),
52 };
53 
54 class EwsPropertyFieldPrivate : public QSharedData
55 {
56 public:
EwsPropertyFieldPrivate()57     EwsPropertyFieldPrivate()
58         : mPropType(EwsPropertyField::UnknownField)
59         , mIndex(0)
60         , mPsIdType(DistinguishedPropSet)
61         , mPsDid(EwsPropSetMeeting)
62         , mIdType(PropName)
63         , mId(0)
64         , mHasTag(false)
65         , mTag(0)
66         , mType(EwsPropTypeNull)
67         , mHash(0)
68     {
69     }
70 
71     enum PropSetIdType {
72         DistinguishedPropSet,
73         RealPropSet,
74     };
75 
76     enum PropIdType {
77         PropName,
78         PropId,
79     };
80 
81     EwsPropertyField::Type mPropType;
82 
83     QString mUri;
84     unsigned mIndex;
85 
86     PropSetIdType mPsIdType;
87     EwsDistinguishedPropSetId mPsDid;
88     QString mPsId;
89 
90     PropIdType mIdType;
91     unsigned mId;
92     QString mName;
93 
94     bool mHasTag;
95     unsigned mTag;
96 
97     EwsPropertyType mType;
98 
99     uint mHash; // Precalculated hash for the qHash() function.
100 
101     void recalcHash();
102 };
103 
recalcHash()104 void EwsPropertyFieldPrivate::recalcHash()
105 {
106     mHash = 0;
107     switch (mPropType) {
108     case EwsPropertyField::Field:
109         mHash = 0x00000000 | (qHash(mUri) & 0x3FFFFFFF);
110         break;
111     case EwsPropertyField::IndexedField:
112         mHash = 0x80000000 | ((qHash(mUri) ^ mIndex) & 0x3FFFFFFF);
113         break;
114     case EwsPropertyField::ExtendedField:
115         if (mHasTag) {
116             mHash = 0x40000000 | mTag;
117         } else {
118             if (mPsIdType == DistinguishedPropSet) {
119                 mHash |= mPsDid << 16;
120             } else {
121                 mHash |= (qHash(mPsId) & 0x1FFF) << 16;
122             }
123 
124             if (mIdType == PropId) {
125                 mHash |= mId & 0xFFFF;
126             } else {
127                 mHash |= (qHash(mName) & 0xFFFF);
128             }
129             mHash |= 0xC0000000;
130         }
131         break;
132     default:
133         break;
134     }
135 }
136 
EwsPropertyField()137 EwsPropertyField::EwsPropertyField()
138     : d(new EwsPropertyFieldPrivate())
139 {
140 }
141 
EwsPropertyField(const QString & uri)142 EwsPropertyField::EwsPropertyField(const QString &uri)
143     : d(new EwsPropertyFieldPrivate())
144 {
145     d->mPropType = Field;
146     d->mUri = uri;
147     d->recalcHash();
148 }
149 
EwsPropertyField(const QString & uri,unsigned index)150 EwsPropertyField::EwsPropertyField(const QString &uri, unsigned index)
151     : d(new EwsPropertyFieldPrivate())
152 {
153     d->mPropType = IndexedField;
154     d->mUri = uri;
155     d->mIndex = index;
156     d->recalcHash();
157 }
158 
EwsPropertyField(EwsDistinguishedPropSetId psid,unsigned id,EwsPropertyType type)159 EwsPropertyField::EwsPropertyField(EwsDistinguishedPropSetId psid, unsigned id, EwsPropertyType type)
160     : d(new EwsPropertyFieldPrivate())
161 {
162     d->mPropType = ExtendedField;
163 
164     d->mPsIdType = EwsPropertyFieldPrivate::DistinguishedPropSet;
165     d->mPsDid = psid;
166 
167     d->mIdType = EwsPropertyFieldPrivate::PropId;
168     d->mId = id;
169 
170     d->mType = type;
171     d->recalcHash();
172 }
173 
EwsPropertyField(EwsDistinguishedPropSetId psid,const QString & name,EwsPropertyType type)174 EwsPropertyField::EwsPropertyField(EwsDistinguishedPropSetId psid, const QString &name, EwsPropertyType type)
175     : d(new EwsPropertyFieldPrivate())
176 {
177     d->mPropType = ExtendedField;
178 
179     d->mPsIdType = EwsPropertyFieldPrivate::DistinguishedPropSet;
180     d->mPsDid = psid;
181 
182     d->mIdType = EwsPropertyFieldPrivate::PropName;
183     d->mName = name;
184 
185     d->mType = type;
186     d->recalcHash();
187 }
188 
EwsPropertyField(const QString & psid,unsigned id,EwsPropertyType type)189 EwsPropertyField::EwsPropertyField(const QString &psid, unsigned id, EwsPropertyType type)
190     : d(new EwsPropertyFieldPrivate())
191 {
192     d->mPropType = ExtendedField;
193 
194     d->mPsIdType = EwsPropertyFieldPrivate::RealPropSet;
195     d->mPsId = psid;
196 
197     d->mIdType = EwsPropertyFieldPrivate::PropId;
198     d->mId = id;
199 
200     d->mType = type;
201     d->recalcHash();
202 }
203 
EwsPropertyField(const QString & psid,const QString & name,EwsPropertyType type)204 EwsPropertyField::EwsPropertyField(const QString &psid, const QString &name, EwsPropertyType type)
205     : d(new EwsPropertyFieldPrivate())
206 {
207     d->mPropType = ExtendedField;
208 
209     d->mPsIdType = EwsPropertyFieldPrivate::RealPropSet;
210     d->mPsId = psid;
211 
212     d->mIdType = EwsPropertyFieldPrivate::PropName;
213     d->mName = name;
214 
215     d->mType = type;
216     d->recalcHash();
217 }
218 
EwsPropertyField(unsigned tag,EwsPropertyType type)219 EwsPropertyField::EwsPropertyField(unsigned tag, EwsPropertyType type)
220     : d(new EwsPropertyFieldPrivate())
221 {
222     d->mPropType = ExtendedField;
223 
224     d->mHasTag = true;
225     d->mTag = tag;
226 
227     d->mType = type;
228     d->recalcHash();
229 }
230 
EwsPropertyField(const EwsPropertyField & other)231 EwsPropertyField::EwsPropertyField(const EwsPropertyField &other)
232     : d(other.d)
233 {
234 }
235 
EwsPropertyField(EwsPropertyField && other)236 EwsPropertyField::EwsPropertyField(EwsPropertyField &&other)
237     : d(other.d)
238 {
239 }
240 
operator =(EwsPropertyField && other)241 EwsPropertyField &EwsPropertyField::operator=(EwsPropertyField &&other)
242 {
243     d = other.d;
244     return *this;
245 }
246 
~EwsPropertyField()247 EwsPropertyField::~EwsPropertyField()
248 {
249 }
250 
operator =(const EwsPropertyField & other)251 EwsPropertyField &EwsPropertyField::operator=(const EwsPropertyField &other)
252 {
253     d = other.d;
254     return *this;
255 }
256 
operator ==(const EwsPropertyField & other) const257 bool EwsPropertyField::operator==(const EwsPropertyField &other) const
258 {
259     if (d == other.d) {
260         return true;
261     }
262 
263     const EwsPropertyFieldPrivate *od = other.d;
264 
265     if (d->mPropType != od->mPropType) {
266         return false;
267     }
268 
269     switch (d->mPropType) {
270     case UnknownField:
271         return true;
272     case Field:
273         return d->mUri == od->mUri;
274     case IndexedField:
275         return (d->mUri == od->mUri) && (d->mIndex == od->mIndex);
276     case ExtendedField:
277         if (d->mType != od->mType) {
278             return false;
279         }
280 
281         if (d->mHasTag != od->mHasTag) {
282             return false;
283         } else if (d->mHasTag) {
284             return d->mTag == od->mTag;
285         }
286 
287         if (d->mPsIdType != od->mPsIdType) {
288             return false;
289         } else if ((d->mPsIdType == EwsPropertyFieldPrivate::DistinguishedPropSet) && (d->mPsDid != od->mPsDid)) {
290             return false;
291         } else if ((d->mPsIdType == EwsPropertyFieldPrivate::RealPropSet) && (d->mPsId != od->mPsId)) {
292             return false;
293         }
294 
295         if (d->mIdType != od->mIdType) {
296             return false;
297         } else if ((d->mIdType == EwsPropertyFieldPrivate::PropId) && (d->mId != od->mId)) {
298             return false;
299         } else if ((d->mIdType == EwsPropertyFieldPrivate::PropName) && (d->mName != od->mName)) {
300             return false;
301         }
302         return true;
303     default:
304         return false;
305     }
306 
307     // Shouldn't get here.
308     return false;
309 }
310 
write(QXmlStreamWriter & writer) const311 void EwsPropertyField::write(QXmlStreamWriter &writer) const
312 {
313     switch (d->mPropType) {
314     case Field:
315         writer.writeStartElement(ewsTypeNsUri, QStringLiteral("FieldURI"));
316         writer.writeAttribute(QStringLiteral("FieldURI"), d->mUri);
317         writer.writeEndElement();
318         break;
319     case IndexedField: {
320         writer.writeStartElement(ewsTypeNsUri, QStringLiteral("IndexedFieldURI"));
321         writer.writeAttribute(QStringLiteral("FieldURI"), d->mUri);
322         QStringList tokens = d->mUri.split(QLatin1Char(':'));
323         writer.writeAttribute(QStringLiteral("FieldIndex"), tokens[1] + QString::number(d->mIndex));
324         writer.writeEndElement();
325         break;
326     }
327     case ExtendedField:
328         writer.writeStartElement(ewsTypeNsUri, QStringLiteral("ExtendedFieldURI"));
329         if (d->mHasTag) {
330             writer.writeAttribute(QStringLiteral("PropertyTag"), QStringLiteral("0x") + QString::number(d->mTag, 16));
331         } else {
332             if (d->mPsIdType == EwsPropertyFieldPrivate::DistinguishedPropSet) {
333                 writer.writeAttribute(QStringLiteral("DistinguishedPropertySetId"), distinguishedPropSetIdNames[d->mPsDid]);
334             } else {
335                 writer.writeAttribute(QStringLiteral("PropertySetId"), d->mPsId);
336             }
337 
338             if (d->mIdType == EwsPropertyFieldPrivate::PropId) {
339                 writer.writeAttribute(QStringLiteral("PropertyId"), QString::number(d->mId));
340             } else {
341                 writer.writeAttribute(QStringLiteral("PropertyName"), d->mName);
342             }
343         }
344         writer.writeAttribute(QStringLiteral("PropertyType"), propertyTypeNames[d->mType]);
345         writer.writeEndElement();
346         break;
347     case UnknownField:
348         break;
349     }
350 }
351 
read(QXmlStreamReader & reader)352 bool EwsPropertyField::read(QXmlStreamReader &reader)
353 {
354     if (reader.namespaceUri() != ewsTypeNsUri) {
355         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - invalid namespace.");
356         return false;
357     }
358 
359     QXmlStreamAttributes attrs = reader.attributes();
360     bool ok;
361 
362     // First check the property type
363     if (reader.name() == QLatin1String("FieldURI")) {
364         if (!attrs.hasAttribute(QStringLiteral("FieldURI"))) {
365             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - missing %1 attribute.").arg(QStringLiteral("FieldURI"));
366             return false;
367         }
368         d->mPropType = Field;
369         d->mUri = attrs.value(QStringLiteral("FieldURI")).toString();
370     } else if (reader.name() == QLatin1String("IndexedFieldURI")) {
371         if (!attrs.hasAttribute(QStringLiteral("FieldURI"))) {
372             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - missing %1 attribute.").arg(QStringLiteral("FieldURI"));
373             return false;
374         }
375         if (!attrs.hasAttribute(QStringLiteral("FieldIndex"))) {
376             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - missing %1 attribute.").arg(QStringLiteral("FieldIndex"));
377             return false;
378         }
379         QString uri = attrs.value(QStringLiteral("FieldURI")).toString();
380         QStringList tokens = uri.split(QLatin1Char(':'));
381         QString indexStr = attrs.value(QStringLiteral("FieldIndex")).toString();
382         if (!indexStr.startsWith(tokens[1])) {
383             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - malformed %1 attribute.").arg(QStringLiteral("FieldIndex"));
384             return false;
385         }
386         unsigned index = indexStr.midRef(tokens[1].size()).toUInt(&ok, 0);
387         if (!ok) {
388             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.").arg(QStringLiteral("FieldIndex"));
389             return false;
390         }
391         d->mPropType = IndexedField;
392         d->mUri = uri;
393         d->mIndex = index;
394     } else if (reader.name() == QLatin1String("ExtendedFieldURI")) {
395         if (!attrs.hasAttribute(QStringLiteral("PropertyType"))) {
396             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - missing %1 attribute.").arg(QStringLiteral("PropertyType"));
397             return false;
398         }
399         QStringRef propTypeText = attrs.value(QStringLiteral("PropertyType"));
400         unsigned i;
401         EwsPropertyType propType;
402         for (i = 0; i < sizeof(propertyTypeNames) / sizeof(propertyTypeNames[0]); ++i) {
403             if (propTypeText == propertyTypeNames[i]) {
404                 propType = static_cast<EwsPropertyType>(i);
405                 break;
406             }
407         }
408         if (i == sizeof(propertyTypeNames) / sizeof(propertyTypeNames[0])) {
409             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.").arg(QStringLiteral("PropertyType"));
410             return false;
411         }
412 
413         if (attrs.hasAttribute(QStringLiteral("PropertyTag"))) {
414             unsigned tag = attrs.value(QStringLiteral("PropertyTag")).toUInt(&ok, 0);
415             if (!ok) {
416                 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.").arg(QStringLiteral("PropertyTag"));
417                 return false;
418             }
419             d->mHasTag = true;
420             d->mTag = tag;
421         } else {
422             EwsPropertyFieldPrivate::PropSetIdType psIdType = EwsPropertyFieldPrivate::DistinguishedPropSet;
423             EwsDistinguishedPropSetId psDid = EwsPropSetMeeting;
424             QString psId;
425 
426             EwsPropertyFieldPrivate::PropIdType idType = EwsPropertyFieldPrivate::PropName;
427             unsigned id = 0;
428             QString name;
429             if (attrs.hasAttribute(QStringLiteral("PropertyId"))) {
430                 id = attrs.value(QStringLiteral("PropertyId")).toUInt(&ok, 0);
431                 if (!ok) {
432                     qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.").arg(QStringLiteral("PropertyId"));
433                     return false;
434                 }
435                 idType = EwsPropertyFieldPrivate::PropId;
436             } else if (attrs.hasAttribute(QStringLiteral("PropertyName"))) {
437                 name = attrs.value(QStringLiteral("PropertyName")).toString();
438                 idType = EwsPropertyFieldPrivate::PropName;
439             } else {
440                 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - missing one of %1 or %2 attributes.")
441                                                .arg(QStringLiteral("PropertyId").arg(QStringLiteral("PropertyName")));
442                 return false;
443             }
444 
445             if (attrs.hasAttribute(QStringLiteral("DistinguishedPropertySetId"))) {
446                 QStringRef didText = attrs.value(QStringLiteral("DistinguishedPropertySetId"));
447                 unsigned i;
448                 for (i = 0; i < sizeof(distinguishedPropSetIdNames) / sizeof(distinguishedPropSetIdNames[0]); ++i) {
449                     if (didText == distinguishedPropSetIdNames[i]) {
450                         psDid = static_cast<EwsDistinguishedPropSetId>(i);
451                         break;
452                     }
453                 }
454                 if (i == sizeof(distinguishedPropSetIdNames) / sizeof(distinguishedPropSetIdNames[0])) {
455                     qCWarningNC(EWSCLI_LOG)
456                         << QStringLiteral("Error reading property field - error reading %1 attribute.").arg(QStringLiteral("DistinguishedPropertySetId"));
457                     return false;
458                 }
459                 psIdType = EwsPropertyFieldPrivate::DistinguishedPropSet;
460             } else if (attrs.hasAttribute(QStringLiteral("PropertySetId"))) {
461                 psId = attrs.value(QStringLiteral("PropertySetId")).toString();
462                 psIdType = EwsPropertyFieldPrivate::RealPropSet;
463             } else {
464                 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading property field - missing one of %1 or %2 attributes.")
465                                                .arg(QStringLiteral("DistinguishedPropertySetId").arg(QStringLiteral("PropertySetId")));
466                 return false;
467             }
468             d->mPsIdType = psIdType;
469             d->mPsDid = psDid;
470             d->mPsId = psId;
471             d->mIdType = idType;
472             d->mId = id;
473             d->mName = name;
474         }
475 
476         d->mType = propType;
477         d->mPropType = ExtendedField;
478     }
479     d->recalcHash();
480     return true;
481 }
482 
qHash(const EwsPropertyField & prop,uint seed)483 uint qHash(const EwsPropertyField &prop, uint seed)
484 {
485     return prop.d->mHasTag ^ seed;
486 }
487 
operator <<(QDebug debug,const EwsPropertyField & prop)488 QDebug operator<<(QDebug debug, const EwsPropertyField &prop)
489 {
490     QDebugStateSaver saver(debug);
491     QDebug d = debug.nospace().noquote();
492     d << QStringLiteral("EwsPropertyField(");
493 
494     switch (prop.d->mPropType) {
495     case EwsPropertyField::Field:
496         d << QStringLiteral("FieldUri: ") << prop.d->mUri;
497         break;
498     case EwsPropertyField::IndexedField:
499         d << QStringLiteral("IndexedFieldUri: ") << prop.d->mUri << '@' << prop.d->mIndex;
500         break;
501     case EwsPropertyField::ExtendedField:
502         d << QStringLiteral("ExtendedFieldUri: ");
503         if (prop.d->mHasTag) {
504             d << QStringLiteral("tag: 0x") << QString::number(prop.d->mTag, 16);
505         } else {
506             if (prop.d->mPsIdType == EwsPropertyFieldPrivate::DistinguishedPropSet) {
507                 d << QStringLiteral("psdid: ") << distinguishedPropSetIdNames[prop.d->mPsDid];
508             } else {
509                 d << QStringLiteral("psid: ") << prop.d->mPsId;
510             }
511             d << QStringLiteral(", ");
512 
513             if (prop.d->mIdType == EwsPropertyFieldPrivate::PropId) {
514                 d << QStringLiteral("id: 0x") << QString::number(prop.d->mId, 16);
515             } else {
516                 d << QStringLiteral("name: ") << prop.d->mName;
517             }
518         }
519         d << QStringLiteral(", type: ") << propertyTypeNames[prop.d->mType];
520         break;
521     case EwsPropertyField::UnknownField:
522         d << QStringLiteral("Unknown");
523         break;
524     }
525     d << ')';
526     return debug;
527 }
528 
writeWithValue(QXmlStreamWriter & writer,const QVariant & value) const529 bool EwsPropertyField::writeWithValue(QXmlStreamWriter &writer, const QVariant &value) const
530 {
531     switch (d->mPropType) {
532     case Field: {
533         QStringList tokens = d->mUri.split(QLatin1Char(':'));
534         if (tokens.size() != 2) {
535             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Invalid field URI: %1").arg(d->mUri);
536             return false;
537         }
538         writer.writeStartElement(ewsTypeNsUri, tokens[1]);
539         writeValue(writer, value);
540         writer.writeEndElement();
541         break;
542     }
543     case IndexedField: {
544         QStringList tokens = d->mUri.split(QLatin1Char(':'));
545         if (tokens.size() != 2) {
546             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Invalid field URI: %1").arg(d->mUri);
547             return false;
548         }
549         writer.writeStartElement(ewsTypeNsUri, tokens[1] + QStringLiteral("es"));
550         writer.writeStartElement(ewsTypeNsUri, QStringLiteral("Entry"));
551         writer.writeAttribute(QStringLiteral("Key"), tokens[1] + QString::number(d->mIndex));
552         writeValue(writer, value);
553         writer.writeEndElement();
554         writer.writeEndElement();
555         break;
556     }
557     case ExtendedField:
558         writer.writeStartElement(ewsTypeNsUri, QStringLiteral("ExtendedProperty"));
559         write(writer);
560         writeExtendedValue(writer, value);
561         writer.writeEndElement();
562         break;
563     default:
564         return false;
565     }
566 
567     return true;
568 }
569 
writeValue(QXmlStreamWriter & writer,const QVariant & value) const570 void EwsPropertyField::writeValue(QXmlStreamWriter &writer, const QVariant &value) const
571 {
572     switch (value.type()) {
573     case QVariant::StringList: {
574         const QStringList list = value.toStringList();
575         for (const QString &str : list) {
576             writer.writeTextElement(ewsTypeNsUri, QStringLiteral("String"), str);
577         }
578         break;
579     }
580     case QVariant::String:
581         writer.writeCharacters(value.toString());
582         break;
583     default:
584         qCWarning(EWSCLI_LOG) << QStringLiteral("Unknown variant type to write: %1").arg(QString::fromLatin1(value.typeName()));
585     }
586 }
587 
writeExtendedValue(QXmlStreamWriter & writer,const QVariant & value) const588 void EwsPropertyField::writeExtendedValue(QXmlStreamWriter &writer, const QVariant &value) const
589 {
590     switch (value.type()) {
591     case QVariant::StringList: {
592         const QStringList list = value.toStringList();
593         writer.writeStartElement(ewsTypeNsUri, QStringLiteral("Values"));
594         for (const QString &str : list) {
595             writer.writeTextElement(ewsTypeNsUri, QStringLiteral("Value"), str);
596         }
597         writer.writeEndElement();
598         break;
599     }
600     case QVariant::String:
601         writer.writeStartElement(ewsTypeNsUri, QStringLiteral("Value"));
602         writer.writeCharacters(value.toString());
603         writer.writeEndElement();
604         break;
605     default:
606         qCWarning(EWSCLI_LOG) << QStringLiteral("Unknown variant type to write: %1").arg(QString::fromLatin1(value.typeName()));
607     }
608 }
609 
type() const610 EwsPropertyField::Type EwsPropertyField::type() const
611 {
612     return d->mPropType;
613 }
614 
uri() const615 QString EwsPropertyField::uri() const
616 {
617     if (d->mPropType == Field || d->mPropType == IndexedField) {
618         return d->mUri;
619     } else {
620         return QString();
621     }
622 }
623