1 /*
2 SPDX-FileCopyrightText: 2017 Krzysztof Nowicki <krissn@op.pl>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "ewsattachment.h"
8
9 #include <QBitArray>
10
11 #include "ewsclient_debug.h"
12 #include "ewsxml.h"
13
14 class EwsAttachmentPrivate : public QSharedData
15 {
16 public:
17 EwsAttachmentPrivate();
18 ~EwsAttachmentPrivate();
19
20 enum Field {
21 Id = 0,
22 Name,
23 ContentType,
24 ContentId,
25 ContentLocation,
26 Size,
27 LastModifiedTime,
28 IsInline,
29 IsContactPhoto,
30 Content,
31 Item,
32 NumFields,
33 };
34
35 EwsAttachment::Type mType;
36 QString mId;
37 QString mName;
38 QString mContentType;
39 QString mContentId;
40 QString mContentLocation;
41 long mSize = 0;
42 QDateTime mLastModifiedTime;
43 bool mIsInline = false;
44 bool mIsContactPhoto = false;
45 QByteArray mContent;
46 EwsItem mItem;
47 bool mValid = false;
48 QBitArray mValidFields;
49 };
50
EwsAttachmentPrivate()51 EwsAttachmentPrivate::EwsAttachmentPrivate()
52 : mType(EwsAttachment::UnknownAttachment)
53 , mValidFields(NumFields)
54 {
55 }
56
~EwsAttachmentPrivate()57 EwsAttachmentPrivate::~EwsAttachmentPrivate()
58 {
59 }
60
EwsAttachment()61 EwsAttachment::EwsAttachment()
62 : d(new EwsAttachmentPrivate())
63 {
64 }
65
~EwsAttachment()66 EwsAttachment::~EwsAttachment()
67 {
68 }
69
EwsAttachment(QXmlStreamReader & reader)70 EwsAttachment::EwsAttachment(QXmlStreamReader &reader)
71 : d(new EwsAttachmentPrivate())
72 {
73 bool ok = true;
74
75 if (reader.namespaceUri() != ewsTypeNsUri) {
76 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in Attachment element:") << reader.namespaceUri();
77 reader.skipCurrentElement();
78 return;
79 }
80
81 const QStringRef readerName = reader.name();
82 if (readerName == QLatin1String("ItemAttachment")) {
83 d->mType = ItemAttachment;
84 } else if (readerName == QLatin1String("FileAttachment")) {
85 d->mType = FileAttachment;
86 } else if (readerName == QLatin1String("ReferenceAttachment")) {
87 d->mType = ReferenceAttachment;
88 } else {
89 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unknown attachment type %1").arg(readerName.toString());
90 ok = false;
91 }
92
93 // Skip this attachment type as it's not clearly documented.
94 if (d->mType == ReferenceAttachment) {
95 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Attachment type ReferenceAttachment not fully supported");
96 reader.skipCurrentElement();
97 d->mValid = true;
98 return;
99 }
100
101 while (ok && reader.readNextStartElement()) {
102 if (reader.namespaceUri() != ewsTypeNsUri) {
103 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Unexpected namespace in Attachment element:") << reader.namespaceUri();
104 reader.skipCurrentElement();
105 ok = false;
106 break;
107 }
108
109 const QString elmName = reader.name().toString();
110 if (elmName == QLatin1String("AttachmentId")) {
111 QXmlStreamAttributes attrs = reader.attributes();
112 if (!attrs.hasAttribute(QStringLiteral("Id"))) {
113 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - missing Id in AttachmentId element.").arg(QStringLiteral("Attachment"));
114 reader.skipCurrentElement();
115 ok = false;
116 } else {
117 d->mId = attrs.value(QStringLiteral("Id")).toString();
118 d->mValidFields.setBit(EwsAttachmentPrivate::Id);
119 }
120 reader.skipCurrentElement();
121 } else if (elmName == QLatin1String("Name")) {
122 d->mName = readXmlElementValue<QString>(reader, ok, QStringLiteral("Attachment"));
123 d->mValidFields.setBit(EwsAttachmentPrivate::Name, ok);
124 } else if (elmName == QLatin1String("ContentType")) {
125 d->mContentType = readXmlElementValue<QString>(reader, ok, QStringLiteral("Attachment"));
126 d->mValidFields.setBit(EwsAttachmentPrivate::ContentType, ok);
127 } else if (elmName == QLatin1String("ContentId")) {
128 d->mContentId = readXmlElementValue<QString>(reader, ok, QStringLiteral("Attachment"));
129 d->mValidFields.setBit(EwsAttachmentPrivate::ContentId, ok);
130 } else if (elmName == QLatin1String("ContentLocation")) {
131 d->mContentLocation = readXmlElementValue<QString>(reader, ok, QStringLiteral("Attachment"));
132 d->mValidFields.setBit(EwsAttachmentPrivate::ContentLocation, ok);
133 } else if (elmName == QLatin1String("AttachmentOriginalUrl")) {
134 // Ignore
135 reader.skipCurrentElement();
136 } else if (elmName == QLatin1String("Size")) {
137 d->mSize = readXmlElementValue<long>(reader, ok, QStringLiteral("Attachment"));
138 d->mValidFields.setBit(EwsAttachmentPrivate::Size, ok);
139 } else if (elmName == QLatin1String("LastModifiedTime")) {
140 d->mLastModifiedTime = readXmlElementValue<QDateTime>(reader, ok, QStringLiteral("Attachment"));
141 d->mValidFields.setBit(EwsAttachmentPrivate::LastModifiedTime, ok);
142 } else if (elmName == QLatin1String("IsInline")) {
143 d->mIsInline = readXmlElementValue<bool>(reader, ok, QStringLiteral("Attachment"));
144 d->mValidFields.setBit(EwsAttachmentPrivate::IsInline, ok);
145 } else if (d->mType == FileAttachment && elmName == QLatin1String("IsContactPhoto")) {
146 d->mIsContactPhoto = readXmlElementValue<bool>(reader, ok, QStringLiteral("Attachment"));
147 d->mValidFields.setBit(EwsAttachmentPrivate::IsContactPhoto, ok);
148 } else if (d->mType == FileAttachment && elmName == QLatin1String("Content")) {
149 d->mContent = readXmlElementValue<QByteArray>(reader, ok, QStringLiteral("Attachment"));
150 d->mValidFields.setBit(EwsAttachmentPrivate::Content, ok);
151 } else if (d->mType == ItemAttachment
152 && (elmName == QLatin1String("Item") || elmName == QLatin1String("Message") || elmName == QLatin1String("CalendarItem")
153 || elmName == QLatin1String("Contact") || elmName == QLatin1String("MeetingMessage") || elmName == QLatin1String("MeetingRequest")
154 || elmName == QLatin1String("MeetingResponse") || elmName == QLatin1String("MeetingCancellation") || elmName == QLatin1String("Task"))) {
155 d->mItem = EwsItem(reader);
156 if (!d->mItem.isValid()) {
157 qCWarningNC(EWSCLI_LOG)
158 << QStringLiteral("Failed to read %1 element - invalid %2 element.").arg(QStringLiteral("Attachment"), QStringLiteral("Item"));
159 reader.skipCurrentElement();
160 ok = false;
161 } else {
162 d->mValidFields.setBit(EwsAttachmentPrivate::Item);
163 }
164 } else {
165 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read %1 element - unknown %2 element.").arg(QStringLiteral("Attachment"), elmName);
166 reader.skipCurrentElement();
167 ok = false;
168 }
169 }
170
171 if (!ok) {
172 reader.skipCurrentElement();
173 }
174 d->mValid = ok;
175 }
176
EwsAttachment(const EwsAttachment & other)177 EwsAttachment::EwsAttachment(const EwsAttachment &other)
178 {
179 d = other.d;
180 }
181
EwsAttachment(EwsAttachment && other)182 EwsAttachment::EwsAttachment(EwsAttachment &&other)
183 {
184 d = std::move(other.d);
185 }
186
operator =(EwsAttachment && other)187 EwsAttachment &EwsAttachment::operator=(EwsAttachment &&other)
188 {
189 d = std::move(other.d);
190 return *this;
191 }
192
operator =(const EwsAttachment & other)193 EwsAttachment &EwsAttachment::operator=(const EwsAttachment &other)
194 {
195 d = other.d;
196 return *this;
197 }
198
write(QXmlStreamWriter & writer) const199 void EwsAttachment::write(QXmlStreamWriter &writer) const
200 {
201 QString elmName;
202 switch (d->mType) {
203 case ItemAttachment:
204 elmName = QStringLiteral("ItemAttachment");
205 break;
206 case FileAttachment:
207 elmName = QStringLiteral("FileAttachment");
208 break;
209 case ReferenceAttachment:
210 elmName = QStringLiteral("ReferenceAttachment");
211 break;
212 default:
213 qCWarning(EWSCLI_LOG) << QStringLiteral("Failed to write Attachment element - invalid attachment type.");
214 return;
215 }
216 writer.writeStartElement(ewsTypeNsUri, elmName);
217
218 if (d->mType == ReferenceAttachment) {
219 qCWarningNC(EWSCLI_LOG) << QStringLiteral("Attachment type ReferenceAttachment not fully supported");
220 writer.writeEndElement();
221 return;
222 }
223
224 if (d->mValidFields[EwsAttachmentPrivate::Id]) {
225 writer.writeStartElement(ewsTypeNsUri, QStringLiteral("AttachmentId"));
226 writer.writeAttribute(QStringLiteral("Id"), d->mId);
227 writer.writeEndElement();
228 }
229 if (d->mValidFields[EwsAttachmentPrivate::Name]) {
230 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("Name"), d->mName);
231 }
232 if (d->mValidFields[EwsAttachmentPrivate::ContentType]) {
233 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("ContentType"), d->mContentType);
234 }
235 if (d->mValidFields[EwsAttachmentPrivate::ContentId]) {
236 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("ContentId"), d->mContentId);
237 }
238 if (d->mValidFields[EwsAttachmentPrivate::ContentLocation]) {
239 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("ContentLocation"), d->mContentLocation);
240 }
241 if (d->mValidFields[EwsAttachmentPrivate::Size]) {
242 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("Size"), QString::number(d->mSize));
243 }
244 if (d->mValidFields[EwsAttachmentPrivate::LastModifiedTime]) {
245 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("LastModifiedTime"), d->mLastModifiedTime.toString(Qt::ISODate));
246 }
247 if (d->mValidFields[EwsAttachmentPrivate::IsInline]) {
248 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("IsInline"), d->mIsInline ? QStringLiteral("true") : QStringLiteral("false"));
249 }
250 if (d->mType == FileAttachment) {
251 if (d->mValidFields[EwsAttachmentPrivate::IsContactPhoto]) {
252 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("IsContactPhoto"), d->mIsContactPhoto ? QStringLiteral("true") : QStringLiteral("false"));
253 }
254 if (d->mValidFields[EwsAttachmentPrivate::Content]) {
255 writer.writeTextElement(ewsTypeNsUri, QStringLiteral("Content"), QString::fromLatin1(d->mContent.toBase64()));
256 }
257 } else if (d->mType == ItemAttachment) {
258 if (d->mValidFields[EwsAttachmentPrivate::Item]) {
259 d->mItem.write(writer);
260 }
261 }
262
263 writer.writeEndElement();
264 }
265
isValid() const266 bool EwsAttachment::isValid() const
267 {
268 return d->mValid;
269 }
270
type() const271 EwsAttachment::Type EwsAttachment::type() const
272 {
273 return d->mType;
274 }
275
setType(Type type)276 void EwsAttachment::setType(Type type)
277 {
278 d->mType = type;
279 }
280
id() const281 QString EwsAttachment::id() const
282 {
283 return d->mId;
284 }
285
setId(const QString & id)286 void EwsAttachment::setId(const QString &id)
287 {
288 d->mId = id;
289 d->mValidFields.setBit(EwsAttachmentPrivate::Id);
290 }
291
resetId()292 void EwsAttachment::resetId()
293 {
294 d->mValidFields.clearBit(EwsAttachmentPrivate::Id);
295 }
296
hasId() const297 bool EwsAttachment::hasId() const
298 {
299 return d->mValidFields[EwsAttachmentPrivate::Id];
300 }
301
name() const302 QString EwsAttachment::name() const
303 {
304 return d->mName;
305 }
306
setName(const QString & name)307 void EwsAttachment::setName(const QString &name)
308 {
309 d->mName = name;
310 d->mValidFields.setBit(EwsAttachmentPrivate::Name);
311 }
312
resetName()313 void EwsAttachment::resetName()
314 {
315 d->mValidFields.clearBit(EwsAttachmentPrivate::Name);
316 }
317
hasName() const318 bool EwsAttachment::hasName() const
319 {
320 return d->mValidFields[EwsAttachmentPrivate::Name];
321 }
322
contentType() const323 QString EwsAttachment::contentType() const
324 {
325 return d->mContentType;
326 }
327
setContentType(const QString & contentType)328 void EwsAttachment::setContentType(const QString &contentType)
329 {
330 d->mContentType = contentType;
331 d->mValidFields.setBit(EwsAttachmentPrivate::ContentType);
332 }
333
resetContentType()334 void EwsAttachment::resetContentType()
335 {
336 d->mValidFields.clearBit(EwsAttachmentPrivate::ContentType);
337 }
338
hasContentType() const339 bool EwsAttachment::hasContentType() const
340 {
341 return d->mValidFields[EwsAttachmentPrivate::ContentType];
342 }
343
contentId() const344 QString EwsAttachment::contentId() const
345 {
346 return d->mContentId;
347 }
348
setContentId(const QString & contentId)349 void EwsAttachment::setContentId(const QString &contentId)
350 {
351 d->mContentId = contentId;
352 d->mValidFields.setBit(EwsAttachmentPrivate::ContentId);
353 }
354
resetContentId()355 void EwsAttachment::resetContentId()
356 {
357 d->mValidFields.clearBit(EwsAttachmentPrivate::ContentId);
358 }
359
hasContentId() const360 bool EwsAttachment::hasContentId() const
361 {
362 return d->mValidFields[EwsAttachmentPrivate::ContentId];
363 }
364
contentLocation() const365 QString EwsAttachment::contentLocation() const
366 {
367 return d->mContentLocation;
368 }
369
setContentLocation(const QString & contentLocation)370 void EwsAttachment::setContentLocation(const QString &contentLocation)
371 {
372 d->mContentLocation = contentLocation;
373 d->mValidFields.setBit(EwsAttachmentPrivate::ContentLocation);
374 }
375
resetContentLocation()376 void EwsAttachment::resetContentLocation()
377 {
378 d->mValidFields.clearBit(EwsAttachmentPrivate::ContentLocation);
379 }
380
hasContentLocation() const381 bool EwsAttachment::hasContentLocation() const
382 {
383 return d->mValidFields[EwsAttachmentPrivate::ContentLocation];
384 }
385
size() const386 long EwsAttachment::size() const
387 {
388 return d->mSize;
389 }
390
setSize(long size)391 void EwsAttachment::setSize(long size)
392 {
393 d->mSize = size;
394 d->mValidFields.setBit(EwsAttachmentPrivate::Size);
395 }
396
resetSize()397 void EwsAttachment::resetSize()
398 {
399 d->mValidFields.clearBit(EwsAttachmentPrivate::Size);
400 }
401
hasSize() const402 bool EwsAttachment::hasSize() const
403 {
404 return d->mValidFields[EwsAttachmentPrivate::Size];
405 }
406
lastModifiedTime() const407 QDateTime EwsAttachment::lastModifiedTime() const
408 {
409 return d->mLastModifiedTime;
410 }
411
setLastModifiedTime(const QDateTime & time)412 void EwsAttachment::setLastModifiedTime(const QDateTime &time)
413 {
414 d->mLastModifiedTime = time;
415 d->mValidFields.setBit(EwsAttachmentPrivate::LastModifiedTime);
416 }
417
resetLastModifiedTime()418 void EwsAttachment::resetLastModifiedTime()
419 {
420 d->mValidFields.clearBit(EwsAttachmentPrivate::LastModifiedTime);
421 }
422
hasLastModifiedTime() const423 bool EwsAttachment::hasLastModifiedTime() const
424 {
425 return d->mValidFields[EwsAttachmentPrivate::LastModifiedTime];
426 }
427
isInline() const428 bool EwsAttachment::isInline() const
429 {
430 return d->mIsInline;
431 }
432
setIsInline(bool isInline)433 void EwsAttachment::setIsInline(bool isInline)
434 {
435 d->mIsInline = isInline;
436 d->mValidFields.setBit(EwsAttachmentPrivate::IsInline);
437 }
438
resetIsInline()439 void EwsAttachment::resetIsInline()
440 {
441 d->mValidFields.clearBit(EwsAttachmentPrivate::IsInline);
442 }
443
hasIsInline() const444 bool EwsAttachment::hasIsInline() const
445 {
446 return d->mValidFields[EwsAttachmentPrivate::IsInline];
447 }
448
isContactPhoto() const449 bool EwsAttachment::isContactPhoto() const
450 {
451 return d->mIsContactPhoto;
452 }
453
setIsContactPhoto(bool isContactPhoto)454 void EwsAttachment::setIsContactPhoto(bool isContactPhoto)
455 {
456 d->mIsContactPhoto = isContactPhoto;
457 d->mValidFields.setBit(EwsAttachmentPrivate::IsContactPhoto);
458 }
459
resetIsContactPhoto()460 void EwsAttachment::resetIsContactPhoto()
461 {
462 d->mValidFields.clearBit(EwsAttachmentPrivate::IsContactPhoto);
463 }
464
hasIsContactPhoto() const465 bool EwsAttachment::hasIsContactPhoto() const
466 {
467 return d->mValidFields[EwsAttachmentPrivate::IsContactPhoto];
468 }
469
content() const470 QByteArray EwsAttachment::content() const
471 {
472 return d->mContent;
473 }
474
setContent(const QByteArray & content)475 void EwsAttachment::setContent(const QByteArray &content)
476 {
477 d->mContent = content;
478 d->mValidFields.setBit(EwsAttachmentPrivate::Content);
479 }
480
resetContent()481 void EwsAttachment::resetContent()
482 {
483 d->mValidFields.clearBit(EwsAttachmentPrivate::Content);
484 }
485
hasContent() const486 bool EwsAttachment::hasContent() const
487 {
488 return d->mValidFields[EwsAttachmentPrivate::Content];
489 }
490
item() const491 const EwsItem &EwsAttachment::item() const
492 {
493 return d->mItem;
494 }
495
setItem(const EwsItem & item)496 void EwsAttachment::setItem(const EwsItem &item)
497 {
498 d->mItem = item;
499 d->mValidFields.setBit(EwsAttachmentPrivate::Item);
500 }
501
resetItem()502 void EwsAttachment::resetItem()
503 {
504 d->mValidFields.clearBit(EwsAttachmentPrivate::Item);
505 }
506
hasItem() const507 bool EwsAttachment::hasItem() const
508 {
509 return d->mValidFields[EwsAttachmentPrivate::Item];
510 }
511