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

0001 /*
0002     SPDX-FileCopyrightText: 2017 Krzysztof Nowicki <krissn@op.pl>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "ewsattachment.h"
0008 
0009 #include <QBitArray>
0010 
0011 #include "ewsclient_debug.h"
0012 #include "ewsxml.h"
0013 
0014 class EwsAttachmentPrivate : public QSharedData
0015 {
0016 public:
0017     EwsAttachmentPrivate();
0018     ~EwsAttachmentPrivate();
0019 
0020     enum Field {
0021         Id = 0,
0022         Name,
0023         ContentType,
0024         ContentId,
0025         ContentLocation,
0026         Size,
0027         LastModifiedTime,
0028         IsInline,
0029         IsContactPhoto,
0030         Content,
0031         Item,
0032         NumFields,
0033     };
0034 
0035     EwsAttachment::Type mType;
0036     QString mId;
0037     QString mName;
0038     QString mContentType;
0039     QString mContentId;
0040     QString mContentLocation;
0041     long mSize = 0;
0042     QDateTime mLastModifiedTime;
0043     bool mIsInline = false;
0044     bool mIsContactPhoto = false;
0045     QByteArray mContent;
0046     EwsItem mItem;
0047     bool mValid = false;
0048     QBitArray mValidFields;
0049 };
0050 
0051 EwsAttachmentPrivate::EwsAttachmentPrivate()
0052     : mType(EwsAttachment::UnknownAttachment)
0053     , mValidFields(NumFields)
0054 {
0055 }
0056 
0057 EwsAttachmentPrivate::~EwsAttachmentPrivate()
0058 {
0059 }
0060 
0061 EwsAttachment::EwsAttachment()
0062     : d(new EwsAttachmentPrivate())
0063 {
0064 }
0065 
0066 EwsAttachment::~EwsAttachment()
0067 {
0068 }
0069 
0070 EwsAttachment::EwsAttachment(QXmlStreamReader &reader)
0071     : d(new EwsAttachmentPrivate())
0072 {
0073     bool ok = true;
0074 
0075     if (reader.namespaceUri() != ewsTypeNsUri) {
0076         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in Attachment element:") << reader.namespaceUri();
0077         reader.skipCurrentElement();
0078         return;
0079     }
0080     const QStringView readerName = reader.name();
0081     if (readerName == QLatin1StringView("ItemAttachment")) {
0082         d->mType = ItemAttachment;
0083     } else if (readerName == QLatin1StringView("FileAttachment")) {
0084         d->mType = FileAttachment;
0085     } else if (readerName == QLatin1StringView("ReferenceAttachment")) {
0086         d->mType = ReferenceAttachment;
0087     } else {
0088         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unknown attachment type %1").arg(readerName.toString());
0089         ok = false;
0090     }
0091 
0092     // Skip this attachment type as it's not clearly documented.
0093     if (d->mType == ReferenceAttachment) {
0094         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Attachment type ReferenceAttachment not fully supported");
0095         reader.skipCurrentElement();
0096         d->mValid = true;
0097         return;
0098     }
0099 
0100     while (ok && reader.readNextStartElement()) {
0101         if (reader.namespaceUri() != ewsTypeNsUri) {
0102             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in Attachment element:") << reader.namespaceUri();
0103             reader.skipCurrentElement();
0104             ok = false;
0105             break;
0106         }
0107 
0108         const QString elmName = reader.name().toString();
0109         if (elmName == QLatin1StringView("AttachmentId")) {
0110             QXmlStreamAttributes attrs = reader.attributes();
0111             if (!attrs.hasAttribute(QStringLiteral("Id"))) {
0112                 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - missing Id in AttachmentId element.").arg(QStringLiteral("Attachment"));
0113                 reader.skipCurrentElement();
0114                 ok = false;
0115             } else {
0116                 d->mId = attrs.value(QStringLiteral("Id")).toString();
0117                 d->mValidFields.setBit(EwsAttachmentPrivate::Id);
0118             }
0119             reader.skipCurrentElement();
0120         } else if (elmName == QLatin1StringView("Name")) {
0121             d->mName = readXmlElementValue<QString>(reader, ok, QStringLiteral("Attachment"));
0122             d->mValidFields.setBit(EwsAttachmentPrivate::Name, ok);
0123         } else if (elmName == QLatin1StringView("ContentType")) {
0124             d->mContentType = readXmlElementValue<QString>(reader, ok, QStringLiteral("Attachment"));
0125             d->mValidFields.setBit(EwsAttachmentPrivate::ContentType, ok);
0126         } else if (elmName == QLatin1StringView("ContentId")) {
0127             d->mContentId = readXmlElementValue<QString>(reader, ok, QStringLiteral("Attachment"));
0128             d->mValidFields.setBit(EwsAttachmentPrivate::ContentId, ok);
0129         } else if (elmName == QLatin1StringView("ContentLocation")) {
0130             d->mContentLocation = readXmlElementValue<QString>(reader, ok, QStringLiteral("Attachment"));
0131             d->mValidFields.setBit(EwsAttachmentPrivate::ContentLocation, ok);
0132         } else if (elmName == QLatin1StringView("AttachmentOriginalUrl")) {
0133             // Ignore
0134             reader.skipCurrentElement();
0135         } else if (elmName == QLatin1StringView("Size")) {
0136             d->mSize = readXmlElementValue<long>(reader, ok, QStringLiteral("Attachment"));
0137             d->mValidFields.setBit(EwsAttachmentPrivate::Size, ok);
0138         } else if (elmName == QLatin1StringView("LastModifiedTime")) {
0139             d->mLastModifiedTime = readXmlElementValue<QDateTime>(reader, ok, QStringLiteral("Attachment"));
0140             d->mValidFields.setBit(EwsAttachmentPrivate::LastModifiedTime, ok);
0141         } else if (elmName == QLatin1StringView("IsInline")) {
0142             d->mIsInline = readXmlElementValue<bool>(reader, ok, QStringLiteral("Attachment"));
0143             d->mValidFields.setBit(EwsAttachmentPrivate::IsInline, ok);
0144         } else if (d->mType == FileAttachment && elmName == QLatin1StringView("IsContactPhoto")) {
0145             d->mIsContactPhoto = readXmlElementValue<bool>(reader, ok, QStringLiteral("Attachment"));
0146             d->mValidFields.setBit(EwsAttachmentPrivate::IsContactPhoto, ok);
0147         } else if (d->mType == FileAttachment && elmName == QLatin1StringView("Content")) {
0148             d->mContent = readXmlElementValue<QByteArray>(reader, ok, QStringLiteral("Attachment"));
0149             d->mValidFields.setBit(EwsAttachmentPrivate::Content, ok);
0150         } else if (d->mType == ItemAttachment
0151                    && (elmName == QLatin1StringView("Item") || elmName == QLatin1StringView("Message") || elmName == QLatin1StringView("CalendarItem")
0152                        || elmName == QLatin1StringView("Contact") || elmName == QLatin1StringView("MeetingMessage")
0153                        || elmName == QLatin1StringView("MeetingRequest") || elmName == QLatin1StringView("MeetingResponse")
0154                        || elmName == QLatin1StringView("MeetingCancellation") || elmName == QLatin1StringView("Task"))) {
0155             d->mItem = EwsItem(reader);
0156             if (!d->mItem.isValid()) {
0157                 qCWarningNC(EWSCLI_LOG)
0158                     << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(QStringLiteral("Attachment"), QStringLiteral("Item"));
0159                 reader.skipCurrentElement();
0160                 ok = false;
0161             } else {
0162                 d->mValidFields.setBit(EwsAttachmentPrivate::Item);
0163             }
0164         } else {
0165             qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - unknown %2 element.").arg(QStringLiteral("Attachment"), elmName);
0166             reader.skipCurrentElement();
0167             ok = false;
0168         }
0169     }
0170 
0171     if (!ok) {
0172         reader.skipCurrentElement();
0173     }
0174     d->mValid = ok;
0175 }
0176 
0177 EwsAttachment::EwsAttachment(const EwsAttachment &other)
0178     : d(other.d)
0179 {
0180 }
0181 
0182 EwsAttachment::EwsAttachment(EwsAttachment &&other)
0183     : d(std::move(other.d))
0184 {
0185 }
0186 
0187 EwsAttachment &EwsAttachment::operator=(EwsAttachment &&other)
0188 {
0189     d = std::move(other.d);
0190     return *this;
0191 }
0192 
0193 EwsAttachment &EwsAttachment::operator=(const EwsAttachment &other)
0194 {
0195     d = other.d;
0196     return *this;
0197 }
0198 
0199 void EwsAttachment::write(QXmlStreamWriter &writer) const
0200 {
0201     QString elmName;
0202     switch (d->mType) {
0203     case ItemAttachment:
0204         elmName = QStringLiteral("ItemAttachment");
0205         break;
0206     case FileAttachment:
0207         elmName = QStringLiteral("FileAttachment");
0208         break;
0209     case ReferenceAttachment:
0210         elmName = QStringLiteral("ReferenceAttachment");
0211         break;
0212     default:
0213         qCWarning(EWSCLI_LOG) << QStringLiteral("Failed to write Attachment element - invalid attachment type.");
0214         return;
0215     }
0216     writer.writeStartElement(ewsTypeNsUri, elmName);
0217 
0218     if (d->mType == ReferenceAttachment) {
0219         qCWarningNC(EWSCLI_LOG) << QStringLiteral("Attachment type ReferenceAttachment not fully supported");
0220         writer.writeEndElement();
0221         return;
0222     }
0223 
0224     if (d->mValidFields[EwsAttachmentPrivate::Id]) {
0225         writer.writeStartElement(ewsTypeNsUri, QStringLiteral("AttachmentId"));
0226         writer.writeAttribute(QStringLiteral("Id"), d->mId);
0227         writer.writeEndElement();
0228     }
0229     if (d->mValidFields[EwsAttachmentPrivate::Name]) {
0230         writer.writeTextElement(ewsTypeNsUri, QStringLiteral("Name"), d->mName);
0231     }
0232     if (d->mValidFields[EwsAttachmentPrivate::ContentType]) {
0233         writer.writeTextElement(ewsTypeNsUri, QStringLiteral("ContentType"), d->mContentType);
0234     }
0235     if (d->mValidFields[EwsAttachmentPrivate::ContentId]) {
0236         writer.writeTextElement(ewsTypeNsUri, QStringLiteral("ContentId"), d->mContentId);
0237     }
0238     if (d->mValidFields[EwsAttachmentPrivate::ContentLocation]) {
0239         writer.writeTextElement(ewsTypeNsUri, QStringLiteral("ContentLocation"), d->mContentLocation);
0240     }
0241     if (d->mValidFields[EwsAttachmentPrivate::Size]) {
0242         writer.writeTextElement(ewsTypeNsUri, QStringLiteral("Size"), QString::number(d->mSize));
0243     }
0244     if (d->mValidFields[EwsAttachmentPrivate::LastModifiedTime]) {
0245         writer.writeTextElement(ewsTypeNsUri, QStringLiteral("LastModifiedTime"), d->mLastModifiedTime.toString(Qt::ISODate));
0246     }
0247     if (d->mValidFields[EwsAttachmentPrivate::IsInline]) {
0248         writer.writeTextElement(ewsTypeNsUri, QStringLiteral("IsInline"), d->mIsInline ? QStringLiteral("true") : QStringLiteral("false"));
0249     }
0250     if (d->mType == FileAttachment) {
0251         if (d->mValidFields[EwsAttachmentPrivate::IsContactPhoto]) {
0252             writer.writeTextElement(ewsTypeNsUri, QStringLiteral("IsContactPhoto"), d->mIsContactPhoto ? QStringLiteral("true") : QStringLiteral("false"));
0253         }
0254         if (d->mValidFields[EwsAttachmentPrivate::Content]) {
0255             writer.writeTextElement(ewsTypeNsUri, QStringLiteral("Content"), QString::fromLatin1(d->mContent.toBase64()));
0256         }
0257     } else if (d->mType == ItemAttachment) {
0258         if (d->mValidFields[EwsAttachmentPrivate::Item]) {
0259             d->mItem.write(writer);
0260         }
0261     }
0262 
0263     writer.writeEndElement();
0264 }
0265 
0266 bool EwsAttachment::isValid() const
0267 {
0268     return d->mValid;
0269 }
0270 
0271 EwsAttachment::Type EwsAttachment::type() const
0272 {
0273     return d->mType;
0274 }
0275 
0276 void EwsAttachment::setType(Type type)
0277 {
0278     d->mType = type;
0279 }
0280 
0281 QString EwsAttachment::id() const
0282 {
0283     return d->mId;
0284 }
0285 
0286 void EwsAttachment::setId(const QString &id)
0287 {
0288     d->mId = id;
0289     d->mValidFields.setBit(EwsAttachmentPrivate::Id);
0290 }
0291 
0292 void EwsAttachment::resetId()
0293 {
0294     d->mValidFields.clearBit(EwsAttachmentPrivate::Id);
0295 }
0296 
0297 bool EwsAttachment::hasId() const
0298 {
0299     return d->mValidFields[EwsAttachmentPrivate::Id];
0300 }
0301 
0302 QString EwsAttachment::name() const
0303 {
0304     return d->mName;
0305 }
0306 
0307 void EwsAttachment::setName(const QString &name)
0308 {
0309     d->mName = name;
0310     d->mValidFields.setBit(EwsAttachmentPrivate::Name);
0311 }
0312 
0313 void EwsAttachment::resetName()
0314 {
0315     d->mValidFields.clearBit(EwsAttachmentPrivate::Name);
0316 }
0317 
0318 bool EwsAttachment::hasName() const
0319 {
0320     return d->mValidFields[EwsAttachmentPrivate::Name];
0321 }
0322 
0323 QString EwsAttachment::contentType() const
0324 {
0325     return d->mContentType;
0326 }
0327 
0328 void EwsAttachment::setContentType(const QString &contentType)
0329 {
0330     d->mContentType = contentType;
0331     d->mValidFields.setBit(EwsAttachmentPrivate::ContentType);
0332 }
0333 
0334 void EwsAttachment::resetContentType()
0335 {
0336     d->mValidFields.clearBit(EwsAttachmentPrivate::ContentType);
0337 }
0338 
0339 bool EwsAttachment::hasContentType() const
0340 {
0341     return d->mValidFields[EwsAttachmentPrivate::ContentType];
0342 }
0343 
0344 QString EwsAttachment::contentId() const
0345 {
0346     return d->mContentId;
0347 }
0348 
0349 void EwsAttachment::setContentId(const QString &contentId)
0350 {
0351     d->mContentId = contentId;
0352     d->mValidFields.setBit(EwsAttachmentPrivate::ContentId);
0353 }
0354 
0355 void EwsAttachment::resetContentId()
0356 {
0357     d->mValidFields.clearBit(EwsAttachmentPrivate::ContentId);
0358 }
0359 
0360 bool EwsAttachment::hasContentId() const
0361 {
0362     return d->mValidFields[EwsAttachmentPrivate::ContentId];
0363 }
0364 
0365 QString EwsAttachment::contentLocation() const
0366 {
0367     return d->mContentLocation;
0368 }
0369 
0370 void EwsAttachment::setContentLocation(const QString &contentLocation)
0371 {
0372     d->mContentLocation = contentLocation;
0373     d->mValidFields.setBit(EwsAttachmentPrivate::ContentLocation);
0374 }
0375 
0376 void EwsAttachment::resetContentLocation()
0377 {
0378     d->mValidFields.clearBit(EwsAttachmentPrivate::ContentLocation);
0379 }
0380 
0381 bool EwsAttachment::hasContentLocation() const
0382 {
0383     return d->mValidFields[EwsAttachmentPrivate::ContentLocation];
0384 }
0385 
0386 long EwsAttachment::size() const
0387 {
0388     return d->mSize;
0389 }
0390 
0391 void EwsAttachment::setSize(long size)
0392 {
0393     d->mSize = size;
0394     d->mValidFields.setBit(EwsAttachmentPrivate::Size);
0395 }
0396 
0397 void EwsAttachment::resetSize()
0398 {
0399     d->mValidFields.clearBit(EwsAttachmentPrivate::Size);
0400 }
0401 
0402 bool EwsAttachment::hasSize() const
0403 {
0404     return d->mValidFields[EwsAttachmentPrivate::Size];
0405 }
0406 
0407 QDateTime EwsAttachment::lastModifiedTime() const
0408 {
0409     return d->mLastModifiedTime;
0410 }
0411 
0412 void EwsAttachment::setLastModifiedTime(const QDateTime &time)
0413 {
0414     d->mLastModifiedTime = time;
0415     d->mValidFields.setBit(EwsAttachmentPrivate::LastModifiedTime);
0416 }
0417 
0418 void EwsAttachment::resetLastModifiedTime()
0419 {
0420     d->mValidFields.clearBit(EwsAttachmentPrivate::LastModifiedTime);
0421 }
0422 
0423 bool EwsAttachment::hasLastModifiedTime() const
0424 {
0425     return d->mValidFields[EwsAttachmentPrivate::LastModifiedTime];
0426 }
0427 
0428 bool EwsAttachment::isInline() const
0429 {
0430     return d->mIsInline;
0431 }
0432 
0433 void EwsAttachment::setIsInline(bool isInline)
0434 {
0435     d->mIsInline = isInline;
0436     d->mValidFields.setBit(EwsAttachmentPrivate::IsInline);
0437 }
0438 
0439 void EwsAttachment::resetIsInline()
0440 {
0441     d->mValidFields.clearBit(EwsAttachmentPrivate::IsInline);
0442 }
0443 
0444 bool EwsAttachment::hasIsInline() const
0445 {
0446     return d->mValidFields[EwsAttachmentPrivate::IsInline];
0447 }
0448 
0449 bool EwsAttachment::isContactPhoto() const
0450 {
0451     return d->mIsContactPhoto;
0452 }
0453 
0454 void EwsAttachment::setIsContactPhoto(bool isContactPhoto)
0455 {
0456     d->mIsContactPhoto = isContactPhoto;
0457     d->mValidFields.setBit(EwsAttachmentPrivate::IsContactPhoto);
0458 }
0459 
0460 void EwsAttachment::resetIsContactPhoto()
0461 {
0462     d->mValidFields.clearBit(EwsAttachmentPrivate::IsContactPhoto);
0463 }
0464 
0465 bool EwsAttachment::hasIsContactPhoto() const
0466 {
0467     return d->mValidFields[EwsAttachmentPrivate::IsContactPhoto];
0468 }
0469 
0470 QByteArray EwsAttachment::content() const
0471 {
0472     return d->mContent;
0473 }
0474 
0475 void EwsAttachment::setContent(const QByteArray &content)
0476 {
0477     d->mContent = content;
0478     d->mValidFields.setBit(EwsAttachmentPrivate::Content);
0479 }
0480 
0481 void EwsAttachment::resetContent()
0482 {
0483     d->mValidFields.clearBit(EwsAttachmentPrivate::Content);
0484 }
0485 
0486 bool EwsAttachment::hasContent() const
0487 {
0488     return d->mValidFields[EwsAttachmentPrivate::Content];
0489 }
0490 
0491 const EwsItem &EwsAttachment::item() const
0492 {
0493     return d->mItem;
0494 }
0495 
0496 void EwsAttachment::setItem(const EwsItem &item)
0497 {
0498     d->mItem = item;
0499     d->mValidFields.setBit(EwsAttachmentPrivate::Item);
0500 }
0501 
0502 void EwsAttachment::resetItem()
0503 {
0504     d->mValidFields.clearBit(EwsAttachmentPrivate::Item);
0505 }
0506 
0507 bool EwsAttachment::hasItem() const
0508 {
0509     return d->mValidFields[EwsAttachmentPrivate::Item];
0510 }