1 /*
2 This file is part of Akonadi.
3 SPDX-FileCopyrightText: 2003 Andreas Gungl <a.gungl@gmx.de>
4 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 SPDX-FileCopyrightText: 2010 Leo Franchi <lfranchi@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9
10 #include "messagestatus.h"
11
12 #include "messageflags.h"
13
14 #include <QString>
15
16 /** The message status format. These can be or'd together.
17 Note, that the StatusIgnored implies the
18 status to be Read.
19 This is done in isRead() and related getters.
20 So we can preserve the state when switching a
21 thread to Ignored and back. */
22 enum Status {
23 StatusUnknown = 0x00000000,
24 StatusUnread = 0x00000002, // deprecated
25 StatusRead = 0x00000004,
26 StatusDeleted = 0x00000010,
27 StatusReplied = 0x00000020,
28 StatusForwarded = 0x00000040,
29 StatusQueued = 0x00000080,
30 StatusSent = 0x00000100,
31 StatusFlag = 0x00000200, // flag means important
32 StatusWatched = 0x00000400,
33 StatusIgnored = 0x00000800, // forces isRead()
34 StatusToAct = 0x00001000,
35 StatusSpam = 0x00002000,
36 StatusHam = 0x00004000,
37 StatusHasAttachment = 0x00008000,
38 StatusHasInvitation = 0x00010000,
39 StatusSigned = 0x00020000,
40 StatusEncrypted = 0x00040000,
41 StatusHasError = 0x00080000
42 };
43
MessageStatus()44 Akonadi::MessageStatus::MessageStatus()
45 {
46 mStatus = StatusUnknown;
47 }
48
operator ==(Akonadi::MessageStatus other) const49 bool Akonadi::MessageStatus::operator==(Akonadi::MessageStatus other) const
50 {
51 return mStatus == other.mStatus;
52 }
53
operator !=(Akonadi::MessageStatus other) const54 bool Akonadi::MessageStatus::operator!=(Akonadi::MessageStatus other) const
55 {
56 return mStatus != other.mStatus;
57 }
58
operator &(Akonadi::MessageStatus other) const59 bool Akonadi::MessageStatus::operator&(Akonadi::MessageStatus other) const
60 {
61 if (mStatus == StatusUnread) {
62 return !(other.mStatus & StatusRead);
63 }
64
65 if (other.mStatus == StatusUnread) {
66 return !(mStatus & StatusRead);
67 }
68
69 return mStatus & other.mStatus;
70 }
71
clear()72 void Akonadi::MessageStatus::clear()
73 {
74 mStatus = StatusUnknown;
75 }
76
set(Akonadi::MessageStatus other)77 void Akonadi::MessageStatus::set(Akonadi::MessageStatus other)
78 {
79 Q_ASSERT(!(other.mStatus & StatusUnread));
80
81 // Those stati are exclusive, but we have to lock at the
82 // internal representation because Ignored can manipulate
83 // the result of the getter methods.
84 if (other.mStatus & StatusRead) {
85 setRead();
86 }
87 if (other.isDeleted()) {
88 setDeleted();
89 }
90 if (other.isReplied()) {
91 setReplied();
92 }
93 if (other.isForwarded()) {
94 setForwarded();
95 }
96 if (other.isQueued()) {
97 setQueued();
98 }
99 if (other.isSent()) {
100 setSent();
101 }
102 if (other.isImportant()) {
103 setImportant();
104 }
105
106 if (other.isWatched()) {
107 setWatched();
108 }
109 if (other.isIgnored()) {
110 setIgnored();
111 }
112 if (other.isToAct()) {
113 setToAct();
114 }
115 if (other.isSpam()) {
116 setSpam();
117 }
118 if (other.isHam()) {
119 setHam();
120 }
121 if (other.hasAttachment()) {
122 setHasAttachment();
123 }
124 if (other.hasInvitation()) {
125 setHasInvitation();
126 }
127 if (other.isSigned()) {
128 setSigned();
129 }
130 if (other.isEncrypted()) {
131 setEncrypted();
132 }
133 if (other.hasError()) {
134 setHasError();
135 }
136 }
137
toggle(Akonadi::MessageStatus other)138 void Akonadi::MessageStatus::toggle(Akonadi::MessageStatus other)
139 {
140 Q_ASSERT(!(other.mStatus & StatusUnread));
141
142 if (other.isDeleted()) {
143 setDeleted(!(mStatus & StatusDeleted));
144 }
145 if (other.isReplied()) {
146 setReplied(!(mStatus & StatusReplied));
147 }
148 if (other.isForwarded()) {
149 setForwarded(!(mStatus & StatusForwarded));
150 }
151 if (other.isQueued()) {
152 setQueued(!(mStatus & StatusQueued));
153 }
154 if (other.isSent()) {
155 setSent(!(mStatus & StatusSent));
156 }
157 if (other.isImportant()) {
158 setImportant(!(mStatus & StatusFlag));
159 }
160
161 if (other.isWatched()) {
162 setWatched(!(mStatus & StatusWatched));
163 }
164 if (other.isIgnored()) {
165 setIgnored(!(mStatus & StatusIgnored));
166 }
167 if (other.isToAct()) {
168 setToAct(!(mStatus & StatusToAct));
169 }
170 if (other.isSpam()) {
171 setSpam(!(mStatus & StatusSpam));
172 }
173 if (other.isHam()) {
174 setHam(!(mStatus & StatusHam));
175 }
176 if (other.hasAttachment()) {
177 setHasAttachment(!(mStatus & StatusHasAttachment));
178 }
179 if (other.hasInvitation()) {
180 setHasInvitation(!(mStatus & StatusHasInvitation));
181 }
182 if (other.isSigned()) {
183 setSigned(!(mStatus & StatusSigned));
184 }
185 if (other.isEncrypted()) {
186 setEncrypted(!(mStatus & StatusEncrypted));
187 }
188 if (other.hasError()) {
189 setHasError(!(mStatus & StatusHasError));
190 }
191 }
192
isOfUnknownStatus() const193 bool Akonadi::MessageStatus::isOfUnknownStatus() const
194 {
195 return mStatus == StatusUnknown;
196 }
197
isRead() const198 bool Akonadi::MessageStatus::isRead() const
199 {
200 return (mStatus & StatusRead) || (mStatus & StatusIgnored);
201 }
202
isDeleted() const203 bool Akonadi::MessageStatus::isDeleted() const
204 {
205 return mStatus & StatusDeleted;
206 }
207
isReplied() const208 bool Akonadi::MessageStatus::isReplied() const
209 {
210 return mStatus & StatusReplied;
211 }
212
isForwarded() const213 bool Akonadi::MessageStatus::isForwarded() const
214 {
215 return mStatus & StatusForwarded;
216 }
217
isQueued() const218 bool Akonadi::MessageStatus::isQueued() const
219 {
220 return mStatus & StatusQueued;
221 }
222
isSent() const223 bool Akonadi::MessageStatus::isSent() const
224 {
225 return mStatus & StatusSent;
226 }
227
isImportant() const228 bool Akonadi::MessageStatus::isImportant() const
229 {
230 return mStatus & StatusFlag;
231 }
232
isWatched() const233 bool Akonadi::MessageStatus::isWatched() const
234 {
235 return mStatus & StatusWatched;
236 }
237
isIgnored() const238 bool Akonadi::MessageStatus::isIgnored() const
239 {
240 return mStatus & StatusIgnored;
241 }
242
isToAct() const243 bool Akonadi::MessageStatus::isToAct() const
244 {
245 return mStatus & StatusToAct;
246 }
247
isSpam() const248 bool Akonadi::MessageStatus::isSpam() const
249 {
250 return mStatus & StatusSpam;
251 }
252
isHam() const253 bool Akonadi::MessageStatus::isHam() const
254 {
255 return mStatus & StatusHam;
256 }
257
hasAttachment() const258 bool Akonadi::MessageStatus::hasAttachment() const
259 {
260 return mStatus & StatusHasAttachment;
261 }
262
hasInvitation() const263 bool Akonadi::MessageStatus::hasInvitation() const
264 {
265 return mStatus & StatusHasInvitation;
266 }
267
isSigned() const268 bool Akonadi::MessageStatus::isSigned() const
269 {
270 return mStatus & StatusSigned;
271 }
272
isEncrypted() const273 bool Akonadi::MessageStatus::isEncrypted() const
274 {
275 return mStatus & StatusEncrypted;
276 }
277
hasError() const278 bool Akonadi::MessageStatus::hasError() const
279 {
280 return mStatus & StatusHasError;
281 }
282
setRead(bool read)283 void Akonadi::MessageStatus::setRead(bool read)
284 {
285 if (read) {
286 mStatus |= StatusRead;
287 } else {
288 mStatus &= ~StatusRead;
289 }
290 }
291
setDeleted(bool deleted)292 void Akonadi::MessageStatus::setDeleted(bool deleted)
293 {
294 if (deleted) {
295 mStatus |= StatusDeleted;
296 } else {
297 mStatus &= ~StatusDeleted;
298 }
299 }
300
setReplied(bool replied)301 void Akonadi::MessageStatus::setReplied(bool replied)
302 {
303 if (replied) {
304 mStatus |= StatusReplied;
305 } else {
306 mStatus &= ~StatusReplied;
307 }
308 }
309
setForwarded(bool forwarded)310 void Akonadi::MessageStatus::setForwarded(bool forwarded)
311 {
312 if (forwarded) {
313 mStatus |= StatusForwarded;
314 } else {
315 mStatus &= ~StatusForwarded;
316 }
317 }
318
setQueued(bool queued)319 void Akonadi::MessageStatus::setQueued(bool queued)
320 {
321 if (queued) {
322 mStatus |= StatusQueued;
323 } else {
324 mStatus &= ~StatusQueued;
325 }
326 }
327
setSent(bool sent)328 void Akonadi::MessageStatus::setSent(bool sent)
329 {
330 if (sent) {
331 mStatus &= ~StatusQueued;
332 mStatus |= StatusSent;
333 } else {
334 mStatus &= ~StatusSent;
335 }
336 }
337
setImportant(bool important)338 void Akonadi::MessageStatus::setImportant(bool important)
339 {
340 if (important) {
341 mStatus |= StatusFlag;
342 } else {
343 mStatus &= ~StatusFlag;
344 }
345 }
346
347 // Watched and ignored are mutually exclusive
setWatched(bool watched)348 void Akonadi::MessageStatus::setWatched(bool watched)
349 {
350 if (watched) {
351 mStatus &= ~StatusIgnored;
352 mStatus |= StatusWatched;
353 } else {
354 mStatus &= ~StatusWatched;
355 }
356 }
357
setIgnored(bool ignored)358 void Akonadi::MessageStatus::setIgnored(bool ignored)
359 {
360 if (ignored) {
361 mStatus &= ~StatusWatched;
362 mStatus |= StatusIgnored;
363 } else {
364 mStatus &= ~StatusIgnored;
365 }
366 }
367
setToAct(bool toAct)368 void Akonadi::MessageStatus::setToAct(bool toAct)
369 {
370 if (toAct) {
371 mStatus |= StatusToAct;
372 } else {
373 mStatus &= ~StatusToAct;
374 }
375 }
376
377 // Ham and Spam are mutually exclusive
setSpam(bool spam)378 void Akonadi::MessageStatus::setSpam(bool spam)
379 {
380 if (spam) {
381 mStatus &= ~StatusHam;
382 mStatus |= StatusSpam;
383 } else {
384 mStatus &= ~StatusSpam;
385 }
386 }
387
setHam(bool ham)388 void Akonadi::MessageStatus::setHam(bool ham)
389 {
390 if (ham) {
391 mStatus &= ~StatusSpam;
392 mStatus |= StatusHam;
393 } else {
394 mStatus &= ~StatusHam;
395 }
396 }
397
setHasAttachment(bool withAttachment)398 void Akonadi::MessageStatus::setHasAttachment(bool withAttachment)
399 {
400 if (withAttachment) {
401 mStatus |= StatusHasAttachment;
402 } else {
403 mStatus &= ~StatusHasAttachment;
404 }
405 }
406
setHasInvitation(bool withInvitation)407 void Akonadi::MessageStatus::setHasInvitation(bool withInvitation)
408 {
409 if (withInvitation) {
410 mStatus |= StatusHasInvitation;
411 } else {
412 mStatus &= ~StatusHasInvitation;
413 }
414 }
415
setSigned(bool value)416 void Akonadi::MessageStatus::setSigned(bool value)
417 {
418 if (value) {
419 mStatus |= StatusSigned;
420 } else {
421 mStatus &= ~StatusSigned;
422 }
423 }
424
setEncrypted(bool value)425 void Akonadi::MessageStatus::setEncrypted(bool value)
426 {
427 if (value) {
428 mStatus |= StatusEncrypted;
429 } else {
430 mStatus &= ~StatusEncrypted;
431 }
432 }
433
setHasError(bool hasError)434 void Akonadi::MessageStatus::setHasError(bool hasError)
435 {
436 if (hasError) {
437 mStatus |= StatusHasError;
438 } else {
439 mStatus &= ~StatusHasError;
440 }
441 }
442
toQInt32() const443 qint32 Akonadi::MessageStatus::toQInt32() const
444 {
445 return mStatus;
446 }
447
fromQInt32(qint32 status)448 void Akonadi::MessageStatus::fromQInt32(qint32 status)
449 {
450 mStatus = status;
451 }
452
statusStr() const453 QString Akonadi::MessageStatus::statusStr() const
454 {
455 QByteArray sstr;
456 if (mStatus & StatusRead) {
457 sstr += 'R';
458 } else {
459 sstr += 'U';
460 }
461 if (mStatus & StatusDeleted) {
462 sstr += 'D';
463 }
464 if (mStatus & StatusReplied) {
465 sstr += 'A';
466 }
467 if (mStatus & StatusForwarded) {
468 sstr += 'F';
469 }
470 if (mStatus & StatusQueued) {
471 sstr += 'Q';
472 }
473 if (mStatus & StatusToAct) {
474 sstr += 'K';
475 }
476 if (mStatus & StatusSent) {
477 sstr += 'S';
478 }
479 if (mStatus & StatusFlag) {
480 sstr += 'G';
481 }
482 if (mStatus & StatusWatched) {
483 sstr += 'W';
484 }
485 if (mStatus & StatusIgnored) {
486 sstr += 'I';
487 }
488 if (mStatus & StatusSpam) {
489 sstr += 'P';
490 }
491 if (mStatus & StatusHam) {
492 sstr += 'H';
493 }
494 if (mStatus & StatusHasAttachment) {
495 sstr += 'T';
496 }
497
498 return QLatin1String(sstr);
499 }
500
setStatusFromStr(const QString & aStr)501 void Akonadi::MessageStatus::setStatusFromStr(const QString &aStr)
502 {
503 mStatus = StatusUnknown;
504
505 if (aStr.contains(QLatin1Char('U'))) {
506 setRead(false);
507 }
508 if (aStr.contains(QLatin1Char('R'))) {
509 setRead();
510 }
511 if (aStr.contains(QLatin1Char('D'))) {
512 setDeleted();
513 }
514 if (aStr.contains(QLatin1Char('A'))) {
515 setReplied();
516 }
517 if (aStr.contains(QLatin1Char('F'))) {
518 setForwarded();
519 }
520 if (aStr.contains(QLatin1Char('Q'))) {
521 setQueued();
522 }
523 if (aStr.contains(QLatin1Char('K'))) {
524 setToAct();
525 }
526 if (aStr.contains(QLatin1Char('S'))) {
527 setSent();
528 }
529 if (aStr.contains(QLatin1Char('G'))) {
530 setImportant();
531 }
532 if (aStr.contains(QLatin1Char('W'))) {
533 setWatched();
534 }
535 if (aStr.contains(QLatin1Char('I'))) {
536 setIgnored();
537 }
538 if (aStr.contains(QLatin1Char('P'))) {
539 setSpam();
540 }
541 if (aStr.contains(QLatin1Char('H'))) {
542 setHam();
543 }
544 if (aStr.contains(QLatin1Char('T'))) {
545 setHasAttachment();
546 }
547 if (aStr.contains(QLatin1Char('C'))) {
548 setHasAttachment(false);
549 }
550 }
551
statusFlags() const552 QSet<QByteArray> Akonadi::MessageStatus::statusFlags() const
553 {
554 QSet<QByteArray> flags;
555
556 if (mStatus & StatusDeleted) {
557 flags += Akonadi::MessageFlags::Deleted;
558 } else {
559 if (mStatus & StatusRead) {
560 flags += Akonadi::MessageFlags::Seen;
561 }
562 if (mStatus & StatusReplied) {
563 flags += Akonadi::MessageFlags::Answered;
564 }
565 if (mStatus & StatusFlag) {
566 flags += Akonadi::MessageFlags::Flagged;
567 }
568
569 // non standard flags
570 if (mStatus & StatusSent) {
571 flags += Akonadi::MessageFlags::Sent;
572 }
573 if (mStatus & StatusQueued) {
574 flags += Akonadi::MessageFlags::Queued;
575 }
576 if (mStatus & StatusReplied) {
577 flags += Akonadi::MessageFlags::Replied;
578 }
579 if (mStatus & StatusForwarded) {
580 flags += Akonadi::MessageFlags::Forwarded;
581 }
582 if (mStatus & StatusToAct) {
583 flags += Akonadi::MessageFlags::ToAct;
584 }
585 if (mStatus & StatusWatched) {
586 flags += Akonadi::MessageFlags::Watched;
587 }
588 if (mStatus & StatusIgnored) {
589 flags += Akonadi::MessageFlags::Ignored;
590 }
591 if (mStatus & StatusHasAttachment) {
592 flags += Akonadi::MessageFlags::HasAttachment;
593 }
594 if (mStatus & StatusHasInvitation) {
595 flags += Akonadi::MessageFlags::HasInvitation;
596 }
597 if (mStatus & StatusSigned) {
598 flags += Akonadi::MessageFlags::Signed;
599 }
600 if (mStatus & StatusEncrypted) {
601 flags += Akonadi::MessageFlags::Encrypted;
602 }
603 if (mStatus & StatusSpam) {
604 flags += Akonadi::MessageFlags::Spam;
605 }
606 if (mStatus & StatusHam) {
607 flags += Akonadi::MessageFlags::Ham;
608 }
609 if (mStatus & StatusHasError) {
610 flags += Akonadi::MessageFlags::HasError;
611 }
612 }
613
614 return flags;
615 }
616
setStatusFromFlags(const QSet<QByteArray> & flags)617 void Akonadi::MessageStatus::setStatusFromFlags(const QSet<QByteArray> &flags)
618 {
619 mStatus = StatusUnknown;
620
621 for (const QByteArray &flag : flags) {
622 const QByteArray &upperedFlag = flag.toUpper();
623 if (upperedFlag == Akonadi::MessageFlags::Deleted) {
624 setDeleted();
625 } else if (upperedFlag == Akonadi::MessageFlags::Seen) {
626 setRead();
627 } else if (upperedFlag == Akonadi::MessageFlags::Answered) {
628 setReplied();
629 } else if (upperedFlag == Akonadi::MessageFlags::Flagged) {
630 setImportant();
631
632 // non standard flags
633 } else if (upperedFlag == Akonadi::MessageFlags::Sent) {
634 setSent();
635 } else if (upperedFlag == Akonadi::MessageFlags::Queued) {
636 setQueued();
637 } else if (upperedFlag == Akonadi::MessageFlags::Replied) {
638 setReplied();
639 } else if (upperedFlag == Akonadi::MessageFlags::Forwarded) {
640 setForwarded();
641 } else if (upperedFlag == Akonadi::MessageFlags::ToAct) {
642 setToAct();
643 } else if (upperedFlag == Akonadi::MessageFlags::Watched) {
644 setWatched();
645 } else if (upperedFlag == Akonadi::MessageFlags::Ignored) {
646 setIgnored();
647 } else if (upperedFlag == Akonadi::MessageFlags::HasAttachment) {
648 setHasAttachment();
649 } else if (upperedFlag == Akonadi::MessageFlags::HasInvitation) {
650 setHasInvitation();
651 } else if (upperedFlag == Akonadi::MessageFlags::Signed) {
652 setSigned();
653 } else if (upperedFlag == Akonadi::MessageFlags::Encrypted) {
654 setEncrypted();
655 } else if (upperedFlag == Akonadi::MessageFlags::Spam) {
656 setSpam();
657 } else if (upperedFlag == Akonadi::MessageFlags::Ham) {
658 setHam();
659 } else if (upperedFlag == Akonadi::MessageFlags::HasError) {
660 setHasError();
661 }
662 }
663 }
664
statusUnread()665 const Akonadi::MessageStatus Akonadi::MessageStatus::statusUnread()
666 {
667 Akonadi::MessageStatus st;
668 st.mStatus = StatusUnread;
669 return st;
670 }
671
statusRead()672 const Akonadi::MessageStatus Akonadi::MessageStatus::statusRead()
673 {
674 Akonadi::MessageStatus st;
675 st.setRead();
676 return st;
677 }
678
statusDeleted()679 const Akonadi::MessageStatus Akonadi::MessageStatus::statusDeleted()
680 {
681 Akonadi::MessageStatus st;
682 st.setDeleted();
683 return st;
684 }
685
statusReplied()686 const Akonadi::MessageStatus Akonadi::MessageStatus::statusReplied()
687 {
688 Akonadi::MessageStatus st;
689 st.setReplied();
690 return st;
691 }
692
statusForwarded()693 const Akonadi::MessageStatus Akonadi::MessageStatus::statusForwarded()
694 {
695 Akonadi::MessageStatus st;
696 st.setForwarded();
697 return st;
698 }
699
statusQueued()700 const Akonadi::MessageStatus Akonadi::MessageStatus::statusQueued()
701 {
702 Akonadi::MessageStatus st;
703 st.setQueued();
704 return st;
705 }
706
statusSent()707 const Akonadi::MessageStatus Akonadi::MessageStatus::statusSent()
708 {
709 Akonadi::MessageStatus st;
710 st.setSent();
711 return st;
712 }
713
statusImportant()714 const Akonadi::MessageStatus Akonadi::MessageStatus::statusImportant()
715 {
716 Akonadi::MessageStatus st;
717 st.setImportant();
718 return st;
719 }
720
statusWatched()721 const Akonadi::MessageStatus Akonadi::MessageStatus::statusWatched()
722 {
723 Akonadi::MessageStatus st;
724 st.setWatched();
725 return st;
726 }
727
statusIgnored()728 const Akonadi::MessageStatus Akonadi::MessageStatus::statusIgnored()
729 {
730 Akonadi::MessageStatus st;
731 st.setIgnored();
732 return st;
733 }
734
statusToAct()735 const Akonadi::MessageStatus Akonadi::MessageStatus::statusToAct()
736 {
737 Akonadi::MessageStatus st;
738 st.setToAct();
739 return st;
740 }
741
statusSpam()742 const Akonadi::MessageStatus Akonadi::MessageStatus::statusSpam()
743 {
744 Akonadi::MessageStatus st;
745 st.setSpam();
746 return st;
747 }
748
statusHam()749 const Akonadi::MessageStatus Akonadi::MessageStatus::statusHam()
750 {
751 Akonadi::MessageStatus st;
752 st.setHam();
753 return st;
754 }
755
statusHasAttachment()756 const Akonadi::MessageStatus Akonadi::MessageStatus::statusHasAttachment()
757 {
758 Akonadi::MessageStatus st;
759 st.setHasAttachment();
760 return st;
761 }
762
statusHasInvitation()763 const Akonadi::MessageStatus Akonadi::MessageStatus::statusHasInvitation()
764 {
765 MessageStatus st;
766 st.setHasInvitation();
767 return st;
768 }
769
statusSigned()770 const Akonadi::MessageStatus Akonadi::MessageStatus::statusSigned()
771 {
772 MessageStatus st;
773 st.setSigned();
774 return st;
775 }
776
statusEncrypted()777 const Akonadi::MessageStatus Akonadi::MessageStatus::statusEncrypted()
778 {
779 MessageStatus st;
780 st.setEncrypted();
781 return st;
782 }
783
statusHasError()784 const Akonadi::MessageStatus Akonadi::MessageStatus::statusHasError()
785 {
786 MessageStatus st;
787 st.setHasError();
788 return st;
789 }
790
operator <<(QDebug d,const Akonadi::MessageStatus & t)791 QDebug operator<<(QDebug d, const Akonadi::MessageStatus &t)
792 {
793 d << "status " << t.statusStr();
794 return d;
795 }
796