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

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 "ewsitem.h"
0008 
0009 #include <QXmlStreamReader>
0010 #include <QXmlStreamWriter>
0011 
0012 #include "ewsattachment.h"
0013 #include "ewsattendee.h"
0014 #include "ewsclient_debug.h"
0015 #include "ewsitembase_p.h"
0016 #include "ewsmailbox.h"
0017 #include "ewsoccurrence.h"
0018 #include "ewsrecurrence.h"
0019 #include "ewsxml.h"
0020 
0021 #define D_PTR EwsItemPrivate *d = reinterpret_cast<EwsItemPrivate *>(this->d.data());
0022 #define D_CPTR const EwsItemPrivate *d = reinterpret_cast<const EwsItemPrivate *>(this->d.data());
0023 
0024 class EwsItemPrivate : public EwsItemBasePrivate
0025 {
0026 public:
0027     typedef EwsXml<EwsItemFields> Reader;
0028 
0029     EwsItemPrivate();
0030     EwsItemPrivate(const EwsItemBasePrivate &other);
0031     EwsItemBasePrivate *clone() const override
0032     {
0033         return new EwsItemPrivate(*this);
0034     }
0035 
0036     static bool bodyReader(QXmlStreamReader &reader, QVariant &val);
0037     static bool messageHeadersReader(QXmlStreamReader &reader, QVariant &val);
0038     static bool mailboxReader(QXmlStreamReader &reader, QVariant &val);
0039     static bool recipientsReader(QXmlStreamReader &reader, QVariant &val);
0040     static bool timezoneReader(QXmlStreamReader &reader, QVariant &val);
0041     static bool attendeesReader(QXmlStreamReader &reader, QVariant &val);
0042     static bool occurrenceReader(QXmlStreamReader &reader, QVariant &val);
0043     static bool occurrencesReader(QXmlStreamReader &reader, QVariant &val);
0044     static bool recurrenceReader(QXmlStreamReader &reader, QVariant &val);
0045     static bool categoriesReader(QXmlStreamReader &reader, QVariant &val);
0046     static bool categoriesWriter(QXmlStreamWriter &writer, const QVariant &val);
0047     static bool attachmentsReader(QXmlStreamReader &reader, QVariant &val);
0048 
0049     bool operator==(const EwsItemPrivate &other) const;
0050 
0051     EwsItemType mType;
0052     static const Reader mStaticEwsXml;
0053     Reader mEwsXml;
0054 };
0055 
0056 static const QList<EwsItemPrivate::Reader::Item> ewsItemItems = {
0057     // Item fields
0058     {EwsItemFieldMimeContent, QStringLiteral("MimeContent"), &ewsXmlBase64Reader, &ewsXmlBase64Writer},
0059     {EwsItemFieldItemId, QStringLiteral("ItemId"), &ewsXmlIdReader, &ewsXmlIdWriter},
0060     {EwsItemFieldParentFolderId, QStringLiteral("ParentFolderId"), &ewsXmlIdReader, &ewsXmlIdWriter},
0061     {EwsItemFieldItemClass, QStringLiteral("ItemClass"), &ewsXmlTextReader, &ewsXmlTextWriter},
0062     {EwsItemFieldSubject, QStringLiteral("Subject"), &ewsXmlTextReader, &ewsXmlTextWriter},
0063     {EwsItemFieldSensitivity, QStringLiteral("Sensitivity"), &ewsXmlSensitivityReader},
0064     {EwsItemFieldBody, QStringLiteral("Body"), &EwsItemPrivate::bodyReader},
0065     {EwsItemFieldAttachments, QStringLiteral("Attachments"), &EwsItemPrivate::attachmentsReader},
0066     {EwsItemFieldDateTimeReceived, QStringLiteral("DateTimeReceived"), &ewsXmlDateTimeReader},
0067     {EwsItemFieldSize, QStringLiteral("Size"), &ewsXmlUIntReader},
0068     {EwsItemFieldCategories, QStringLiteral("Categories"), &EwsItemPrivate::categoriesReader, &EwsItemPrivate::categoriesWriter},
0069     {EwsItemFieldImportance, QStringLiteral("Importance"), &ewsXmlImportanceReader},
0070     {EwsItemFieldInReplyTo, QStringLiteral("InReplyTo"), &ewsXmlTextReader},
0071     {EwsItemFieldIsDraft, QStringLiteral("IsDraft"), &ewsXmlBoolReader, &ewsXmlBoolWriter},
0072     {EwsItemFieldIsFromMe, QStringLiteral("IsFromMe"), &ewsXmlBoolReader},
0073     {EwsItemFieldInternetMessageHeaders, QStringLiteral("InternetMessageHeaders"), &EwsItemPrivate::messageHeadersReader},
0074     {EwsItemFieldExtendedProperties,
0075      QStringLiteral("ExtendedProperty"),
0076      &EwsItemBasePrivate::extendedPropertyReader,
0077      &EwsItemBasePrivate::extendedPropertyWriter},
0078     {EwsItemFieldHasAttachments, QStringLiteral("HasAttachments"), &ewsXmlBoolReader},
0079     // Message fields
0080     {EwsItemFieldToRecipients, QStringLiteral("ToRecipients"), &EwsItemPrivate::recipientsReader},
0081     {EwsItemFieldCcRecipients, QStringLiteral("CcRecipients"), &EwsItemPrivate::recipientsReader},
0082     {EwsItemFieldBccRecipients, QStringLiteral("BccRecipients"), &EwsItemPrivate::recipientsReader},
0083     {EwsItemFieldFrom, QStringLiteral("From"), &EwsItemPrivate::mailboxReader},
0084     {EwsItemFieldInternetMessageId, QStringLiteral("InternetMessageId"), &ewsXmlTextReader},
0085     {EwsItemFieldIsRead, QStringLiteral("IsRead"), &ewsXmlBoolReader, &ewsXmlBoolWriter},
0086     {EwsItemFieldReferences, QStringLiteral("References"), &ewsXmlTextReader},
0087     {EwsItemFieldReplyTo, QStringLiteral("ReplyTo"), &EwsItemPrivate::mailboxReader},
0088     // CalendarItem fields
0089     {EwsItemFieldCalendarItemType, QStringLiteral("CalendarItemType"), &ewsXmlCalendarItemTypeReader},
0090     {EwsItemFieldUID, QStringLiteral("UID"), &ewsXmlTextReader},
0091     {EwsItemFieldCulture, QStringLiteral("Culture"), &ewsXmlTextReader},
0092     {EwsItemFieldStartTimeZone, QStringLiteral("StartTimeZone"), &EwsItemPrivate::timezoneReader},
0093     {EwsItemFieldOrganizer, QStringLiteral("Organizer"), &EwsItemPrivate::mailboxReader},
0094     {EwsItemFieldRequiredAttendees, QStringLiteral("RequiredAttendees"), &EwsItemPrivate::attendeesReader},
0095     {EwsItemFieldOptionalAttendees, QStringLiteral("OptionalAttendees"), &EwsItemPrivate::attendeesReader},
0096     {EwsItemFieldResources, QStringLiteral("Resources"), &EwsItemPrivate::attendeesReader},
0097     {EwsItemFieldStart, QStringLiteral("Start"), &ewsXmlDateTimeReader},
0098     {EwsItemFieldEnd, QStringLiteral("End"), &ewsXmlDateTimeReader},
0099     {EwsItemFieldRecurrenceId, QStringLiteral("RecurrenceId"), &ewsXmlDateTimeReader},
0100     {EwsItemFieldIsAllDayEvent, QStringLiteral("IsAllDayEvent"), &ewsXmlBoolReader},
0101     {EwsItemFieldLegacyFreeBusyStatus, QStringLiteral("LegacyFreeBusyStatus"), &ewsXmlLegacyFreeBusyStatusReader},
0102     {EwsItemFieldMyResponseType, QStringLiteral("MyResponseType"), &ewsXmlResponseTypeReader},
0103     {EwsItemFieldAppointmentSequenceNumber, QStringLiteral("AppointmentSequenceNumber"), &ewsXmlUIntReader},
0104     {EwsItemFieldRecurrence, QStringLiteral("Recurrence"), &EwsItemPrivate::recurrenceReader},
0105     {EwsItemFieldFirstOccurrence, QStringLiteral("FirstOccurrence"), &EwsItemPrivate::occurrenceReader},
0106     {EwsItemFieldLastOccurrence, QStringLiteral("LastOccurrence"), &EwsItemPrivate::occurrenceReader},
0107     {EwsItemFieldModifiedOccurrences, QStringLiteral("ModifiedOccurrences"), &EwsItemPrivate::occurrencesReader},
0108     {EwsItemFieldDeletedOccurrences, QStringLiteral("DeletedOccurrences"), &EwsItemPrivate::occurrencesReader},
0109     {EwsItemFieldTimeZone, QStringLiteral("TimeZone"), &ewsXmlTextReader},
0110     {EwsItemFieldExchangePersonIdGuid, QStringLiteral("ExchangePersonIdGuid"), &ewsXmlTextReader},
0111     {EwsItemFieldDoNotForwardMeeting, QStringLiteral("DoNotForwardMeeting"), &ewsXmlBoolReader},
0112 };
0113 
0114 const EwsItemPrivate::Reader EwsItemPrivate::mStaticEwsXml(ewsItemItems);
0115 
0116 EwsItemPrivate::EwsItemPrivate()
0117     : EwsItemBasePrivate()
0118     , mType(EwsItemTypeUnknown)
0119     , mEwsXml(mStaticEwsXml)
0120 {
0121 }
0122 
0123 bool EwsItemPrivate::bodyReader(QXmlStreamReader &reader, QVariant &val)
0124 {
0125     QVariantList vl;
0126     auto bodyType = reader.attributes().value(QStringLiteral("BodyType"));
0127     if (bodyType.isNull()) {
0128         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - missing %2 attribute").arg(QStringLiteral("Body"), QStringLiteral("BodyType"));
0129         return false;
0130     }
0131     bool isHtml;
0132     if (bodyType == QLatin1StringView("HTML")) {
0133         isHtml = true;
0134     } else if (bodyType == QLatin1StringView("Text")) {
0135         isHtml = false;
0136     } else {
0137         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read Body element- unknown body type");
0138         return false;
0139     }
0140     vl.append(reader.readElementText());
0141     if (reader.error() != QXmlStreamReader::NoError) {
0142         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - invalid content.").arg(QStringLiteral("Body"));
0143         return false;
0144     }
0145     vl.append(isHtml);
0146     val = vl;
0147     return true;
0148 }
0149 
0150 bool EwsItemPrivate::messageHeadersReader(QXmlStreamReader &reader, QVariant &val)
0151 {
0152     EwsItem::HeaderMap map = val.value<EwsItem::HeaderMap>();
0153 
0154     while (reader.readNextStartElement()) {
0155         if (reader.namespaceUri() != ewsTypeNsUri) {
0156             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in InternetMessageHeaders element:") << reader.namespaceUri();
0157             return false;
0158         }
0159 
0160         if (reader.name() == QLatin1StringView("InternetMessageHeader")) {
0161             auto nameRef = reader.attributes().value(QStringLiteral("HeaderName"));
0162             if (nameRef.isNull()) {
0163                 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Missing HeaderName attribute in InternetMessageHeader element.");
0164                 return false;
0165             }
0166             QString name = nameRef.toString();
0167             QString value = reader.readElementText();
0168             map.insert(name, value);
0169             if (reader.error() != QXmlStreamReader::NoError) {
0170                 qCWarning(EWSCLI_LOG) << QStringLiteral("Failed to read EWS request - invalid %1 element.").arg(QStringLiteral("InternetMessageHeader"));
0171                 return false;
0172             }
0173         }
0174     }
0175 
0176     val = QVariant::fromValue<EwsItem::HeaderMap>(map);
0177 
0178     return true;
0179 }
0180 
0181 bool EwsItemPrivate::recipientsReader(QXmlStreamReader &reader, QVariant &val)
0182 {
0183     EwsMailbox::List mboxList;
0184 
0185     while (reader.readNextStartElement()) {
0186         if (reader.namespaceUri() != ewsTypeNsUri) {
0187             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in %1 element:").arg(reader.name().toString()) << reader.namespaceUri();
0188             return false;
0189         }
0190         EwsMailbox mbox(reader);
0191         if (!mbox.isValid()) {
0192             return false;
0193         }
0194         mboxList.append(mbox);
0195     }
0196 
0197     val = QVariant::fromValue<EwsMailbox::List>(mboxList);
0198 
0199     return true;
0200 }
0201 
0202 bool EwsItemPrivate::mailboxReader(QXmlStreamReader &reader, QVariant &val)
0203 {
0204     if (!reader.readNextStartElement()) {
0205         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Expected mailbox in %1 element:").arg(reader.name().toString());
0206         return false;
0207     }
0208 
0209     if (reader.namespaceUri() != ewsTypeNsUri) {
0210         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in %1 element:").arg(reader.name().toString()) << reader.namespaceUri();
0211         reader.skipCurrentElement();
0212         return false;
0213     }
0214 
0215     EwsMailbox mbox(reader);
0216     if (!mbox.isValid()) {
0217         reader.skipCurrentElement();
0218         return false;
0219     }
0220 
0221     val = QVariant::fromValue<EwsMailbox>(mbox);
0222 
0223     // Leave the element
0224     reader.skipCurrentElement();
0225 
0226     return true;
0227 }
0228 
0229 bool EwsItemPrivate::timezoneReader(QXmlStreamReader &reader, QVariant &val)
0230 {
0231     // TODO: This only reads the timezone identifier.
0232     auto idRef = reader.attributes().value(QStringLiteral("Id"));
0233     if (idRef.isNull()) {
0234         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Error reading %1 element - missing %2 attribute").arg(reader.name().toString(), QStringLiteral("Id"));
0235         reader.skipCurrentElement();
0236         return false;
0237     } else {
0238         reader.skipCurrentElement();
0239         val = idRef.toString();
0240         return true;
0241     }
0242 }
0243 
0244 bool EwsItemPrivate::attendeesReader(QXmlStreamReader &reader, QVariant &val)
0245 {
0246     EwsAttendee::List attList;
0247 
0248     while (reader.readNextStartElement()) {
0249         if (reader.namespaceUri() != ewsTypeNsUri) {
0250             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in %1 element:").arg(reader.name().toString()) << reader.namespaceUri();
0251             return false;
0252         }
0253         EwsAttendee att(reader);
0254         if (!att.isValid()) {
0255             return false;
0256         }
0257         attList.append(att);
0258     }
0259 
0260     val = QVariant::fromValue<EwsAttendee::List>(attList);
0261 
0262     return true;
0263 }
0264 
0265 bool EwsItemPrivate::occurrenceReader(QXmlStreamReader &reader, QVariant &val)
0266 {
0267     EwsOccurrence occ(reader);
0268     if (!occ.isValid()) {
0269         return false;
0270     }
0271     val = QVariant::fromValue<EwsOccurrence>(occ);
0272     return true;
0273 }
0274 
0275 bool EwsItemPrivate::occurrencesReader(QXmlStreamReader &reader, QVariant &val)
0276 {
0277     EwsOccurrence::List occList;
0278 
0279     while (reader.readNextStartElement()) {
0280         if (reader.namespaceUri() != ewsTypeNsUri) {
0281             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in %1 element:").arg(reader.name().toString()) << reader.namespaceUri();
0282             return false;
0283         }
0284         EwsOccurrence occ(reader);
0285         if (!occ.isValid()) {
0286             return false;
0287         }
0288         occList.append(occ);
0289     }
0290 
0291     val = QVariant::fromValue<EwsOccurrence::List>(occList);
0292 
0293     return true;
0294 }
0295 
0296 bool EwsItemPrivate::categoriesReader(QXmlStreamReader &reader, QVariant &val)
0297 {
0298     QStringList categories;
0299 
0300     while (reader.readNextStartElement()) {
0301         if (reader.namespaceUri() != ewsTypeNsUri) {
0302             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in %1 element:").arg(reader.name().toString()) << reader.namespaceUri();
0303             return false;
0304         }
0305 
0306         if (reader.name() == QLatin1StringView("String")) {
0307             categories.append(reader.readElementText());
0308             if (reader.error() != QXmlStreamReader::NoError) {
0309                 qCWarning(EWSCLI_LOG) << QStringLiteral("Failed to read EWS request - invalid %1 element.").arg(QStringLiteral("Categories/Value"));
0310                 return false;
0311             }
0312         }
0313     }
0314 
0315     val = categories;
0316 
0317     return true;
0318 }
0319 
0320 bool EwsItemPrivate::categoriesWriter(QXmlStreamWriter &writer, const QVariant &val)
0321 {
0322     const QStringList categories = val.toStringList();
0323 
0324     for (const QString &cat : categories) {
0325         writer.writeTextElement(ewsTypeNsUri, QStringLiteral("String"), cat);
0326     }
0327 
0328     return true;
0329 }
0330 
0331 bool EwsItemPrivate::recurrenceReader(QXmlStreamReader &reader, QVariant &val)
0332 {
0333     EwsRecurrence recurrence(reader);
0334     val = QVariant::fromValue<EwsRecurrence>(recurrence);
0335     return true;
0336 }
0337 
0338 bool EwsItemPrivate::attachmentsReader(QXmlStreamReader &reader, QVariant &val)
0339 {
0340     EwsAttachment::List attList;
0341 
0342     while (reader.readNextStartElement()) {
0343         if (reader.namespaceUri() != ewsTypeNsUri) {
0344             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in %1 element:").arg(reader.name().toString()) << reader.namespaceUri();
0345             return false;
0346         }
0347         EwsAttachment att(reader);
0348         if (!att.isValid()) {
0349             return false;
0350         }
0351         attList.append(att);
0352     }
0353 
0354     val = QVariant::fromValue<EwsAttachment::List>(attList);
0355 
0356     return true;
0357 }
0358 
0359 bool EwsItemPrivate::operator==(const EwsItemPrivate &other) const
0360 {
0361     if (!EwsItemBasePrivate::operator==(other)) {
0362         return false;
0363     }
0364     return mType == other.mType;
0365 }
0366 
0367 EwsItem::EwsItem()
0368     : EwsItemBase(QSharedDataPointer<EwsItemBasePrivate>(new EwsItemPrivate()))
0369 {
0370 }
0371 
0372 EwsItem::EwsItem(QXmlStreamReader &reader)
0373     : EwsItemBase(QSharedDataPointer<EwsItemBasePrivate>(new EwsItemPrivate()))
0374 {
0375     qRegisterMetaType<EwsItem::HeaderMap>();
0376     qRegisterMetaType<EwsMailbox>();
0377     qRegisterMetaType<EwsMailbox::List>();
0378     qRegisterMetaType<EwsAttendee>();
0379     qRegisterMetaType<EwsAttendee::List>();
0380     qRegisterMetaType<EwsRecurrence>();
0381     qRegisterMetaType<EwsOccurrence>();
0382     qRegisterMetaType<EwsOccurrence::List>();
0383 
0384     auto d = reinterpret_cast<EwsItemPrivate *>(this->d.data());
0385 
0386     // Check what item type are we
0387     const auto elmName = reader.name();
0388     if (elmName == QLatin1StringView("Item")) {
0389         d->mType = EwsItemTypeItem;
0390         const auto subtype = reader.attributes().value(QStringLiteral("xsi:type"));
0391         if (!subtype.isEmpty()) {
0392             auto tokens = subtype.split(QLatin1Char(':'));
0393             const auto type = tokens.size() == 1 ? tokens[0] : tokens[1];
0394             if (type == QLatin1StringView("AbchPersonItemType")) {
0395                 d->mType = EwsItemTypeAbchPerson;
0396             }
0397         }
0398     } else if (elmName == QLatin1StringView("Message")) {
0399         d->mType = EwsItemTypeMessage;
0400     } else if (elmName == QLatin1StringView("CalendarItem")) {
0401         d->mType = EwsItemTypeCalendarItem;
0402     } else if (elmName == QLatin1StringView("Contact")) {
0403         d->mType = EwsItemTypeContact;
0404     } else if (elmName == QLatin1StringView("DistributionList")) {
0405         d->mType = EwsItemTypeDistributionList;
0406     } else if (elmName == QLatin1StringView("MeetingMessage")) {
0407         d->mType = EwsItemTypeMeetingMessage;
0408     } else if (elmName == QLatin1StringView("MeetingRequest")) {
0409         d->mType = EwsItemTypeMeetingRequest;
0410     } else if (elmName == QLatin1StringView("MeetingResponse")) {
0411         d->mType = EwsItemTypeMeetingResponse;
0412     } else if (elmName == QLatin1StringView("MeetingCancellation")) {
0413         d->mType = EwsItemTypeMeetingCancellation;
0414     } else if (elmName == QLatin1StringView("PostItem")) {
0415         d->mType = EwsItemTypePostItem;
0416     } else if (elmName == QLatin1StringView("Task")) {
0417         d->mType = EwsItemTypeTask;
0418     } else {
0419         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unknown item type: %1").arg(elmName);
0420     }
0421 
0422     while (reader.readNextStartElement()) {
0423         if (reader.namespaceUri() != ewsTypeNsUri) {
0424             qCWarningNC(EWSCLI_LOG) << "Unexpected namespace in Item element:" << reader.namespaceUri();
0425             return;
0426         }
0427 
0428         if (!readBaseItemElement(reader)) {
0429             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Invalid Item child: %1").arg(reader.qualifiedName().toString());
0430             return;
0431         }
0432     }
0433     d->mValid = true;
0434 }
0435 
0436 EwsItem::EwsItem(const EwsItem &other)
0437     : EwsItemBase(other.d)
0438 {
0439 }
0440 
0441 EwsItem::EwsItem(EwsItem &&other)
0442     : EwsItemBase(other.d)
0443 {
0444 }
0445 
0446 EwsItem::~EwsItem()
0447 {
0448 }
0449 
0450 EwsItem &EwsItem::operator=(const EwsItem &other)
0451 {
0452     d = other.d;
0453     return *this;
0454 }
0455 
0456 EwsItem &EwsItem::operator=(EwsItem &&other)
0457 {
0458     d = std::move(other.d);
0459     return *this;
0460 }
0461 
0462 EwsItemType EwsItem::type() const
0463 {
0464     const auto d = reinterpret_cast<const EwsItemPrivate *>(this->d.data());
0465     return d->mType;
0466 }
0467 
0468 void EwsItem::setType(EwsItemType type)
0469 {
0470     D_PTR
0471     d->mType = type;
0472     d->mValid = true;
0473 }
0474 
0475 EwsItemType EwsItem::internalType() const
0476 {
0477     D_CPTR
0478 
0479     EwsItemType type = d->mType;
0480     switch (type) {
0481     case EwsItemTypeMeetingMessage:
0482     case EwsItemTypeMeetingRequest:
0483     case EwsItemTypeMeetingResponse:
0484     case EwsItemTypeMeetingCancellation:
0485         type = EwsItemTypeMessage;
0486         break;
0487     case EwsItemTypeDistributionList:
0488         type = EwsItemTypeContact;
0489         break;
0490     default:
0491         break;
0492     }
0493     return type;
0494 }
0495 
0496 bool EwsItem::readBaseItemElement(QXmlStreamReader &reader)
0497 {
0498     D_PTR
0499 
0500     if (!d->mEwsXml.readItem(reader, QStringLiteral("Item"), ewsTypeNsUri)) {
0501         return false;
0502     }
0503 
0504     d->mFields = d->mEwsXml.values();
0505 
0506     // The body item is special as it hold two values in one. Need to separate them into their
0507     // proper places.
0508     if (d->mFields.contains(EwsItemFieldBody)) {
0509         QVariantList vl = d->mFields[EwsItemFieldBody].value<QVariantList>();
0510         QVariantList::const_iterator it = vl.cbegin();
0511         d->mFields[EwsItemFieldBody] = *it++;
0512         d->mFields[EwsItemFieldBodyIsHtml] = *it;
0513     }
0514     return true;
0515 }
0516 
0517 bool EwsItem::write(QXmlStreamWriter &writer) const
0518 {
0519     D_CPTR
0520 
0521     writer.writeStartElement(ewsTypeNsUri, ewsItemTypeNames[d->mType]);
0522 
0523     bool status = d->mEwsXml.writeItems(writer, ewsItemTypeNames[d->mType], ewsTypeNsUri, d->mFields);
0524 
0525     writer.writeEndElement();
0526 
0527     return status;
0528 }
0529 
0530 bool EwsItem::operator==(const EwsItem &other) const
0531 {
0532     return *d == *other.d;
0533 }