1 // 2 3 #pragma once 4 5 #include "kmail_private_export.h" 6 7 #include <MailCommon/SearchPattern> 8 #include <MessageComposer/MessageFactoryNG> 9 #include <MessageList/View> 10 #include <MessageViewer/Viewer> 11 12 #include <Akonadi/KMime/MessageStatus> 13 #include <KIO/Job> 14 #include <KMime/KMimeMessage> 15 16 #include <Akonadi/Collection> 17 #include <Akonadi/Item> 18 #include <Akonadi/ItemFetchScope> 19 #include <QList> 20 #include <QPointer> 21 #include <QUrl> 22 namespace Akonadi 23 { 24 class Tag; 25 } 26 27 namespace KPIM 28 { 29 class ProgressItem; 30 } 31 32 using Akonadi::MessageStatus; 33 34 class QProgressDialog; 35 class KMMainWidget; 36 class KMReaderMainWin; 37 38 template<typename T> class QSharedPointer; 39 40 namespace MessageViewer 41 { 42 class HeaderStyle; 43 class AttachmentStrategy; 44 } 45 46 namespace KIO 47 { 48 class Job; 49 } 50 namespace KMail 51 { 52 class Composer; 53 } 54 using PartNodeMessageMap = QMap<KMime::Content *, Akonadi::Item>; 55 /// Small helper structure which encapsulates the KMMessage created when creating a reply, and 56 57 class KMAILTESTS_TESTS_EXPORT KMCommand : public QObject 58 { 59 Q_OBJECT 60 61 public: 62 enum Result { 63 Undefined, 64 OK, 65 Canceled, 66 Failed, 67 }; 68 69 // Trivial constructor, don't retrieve any messages 70 explicit KMCommand(QWidget *parent = nullptr); 71 KMCommand(QWidget *parent, const Akonadi::Item &); 72 // Retrieve all messages in msgList when start is called. 73 KMCommand(QWidget *parent, const Akonadi::Item::List &msgList); 74 // Retrieve the single message msgBase when start is called. 75 ~KMCommand() override; 76 77 /** Returns the result of the command. Only call this method from the slot 78 connected to completed(). 79 */ 80 Q_REQUIRED_RESULT Result result() const; 81 82 public Q_SLOTS: 83 // Retrieve messages then calls execute 84 void start(); 85 86 Q_SIGNALS: 87 88 /// @param result The status of the command. 89 void messagesTransfered(KMCommand::Result result); 90 91 /// Emitted when the command has completed. 92 void completed(KMCommand *command); 93 94 protected: 95 virtual Akonadi::ItemFetchJob *createFetchJob(const Akonadi::Item::List &items); 96 97 /** Allows to configure how much data should be retrieved of the messages. */ fetchScope()98 Q_REQUIRED_RESULT Akonadi::ItemFetchScope &fetchScope() 99 { 100 return mFetchScope; 101 } 102 103 // Returns list of messages retrieved 104 Q_REQUIRED_RESULT const Akonadi::Item::List retrievedMsgs() const; 105 // Returns the single message retrieved 106 Q_REQUIRED_RESULT Akonadi::Item retrievedMessage() const; 107 // Returns the parent widget 108 QWidget *parentWidget() const; 109 110 Q_REQUIRED_RESULT bool deletesItself() const; 111 /** Specify whether the subclass takes care of the deletion of the object. 112 By default the base class will delete the object. 113 @param deletesItself true if the subclass takes care of deletion, false 114 if the base class should take care of deletion 115 */ 116 void setDeletesItself(bool deletesItself); 117 118 Q_REQUIRED_RESULT bool emitsCompletedItself() const; 119 /** Specify whether the subclass takes care of emitting the completed() 120 signal. By default the base class will Q_EMIT this signal. 121 @param emitsCompletedItself true if the subclass emits the completed 122 signal, false if the base class should Q_EMIT 123 the signal 124 */ 125 void setEmitsCompletedItself(bool emitsCompletedItself); 126 127 /** Use this to set the result of the command. 128 @param result The result of the command. 129 */ 130 void setResult(Result result); 131 132 private: 133 Q_DISABLE_COPY(KMCommand) 134 // execute should be implemented by derived classes 135 virtual Result execute() = 0; 136 137 /** transfers the list of (imap)-messages 138 * this is a necessary preparation for e.g. forwarding */ 139 void transferSelectedMsgs(); 140 141 private Q_SLOTS: 142 void slotPostTransfer(KMCommand::Result result); 143 /** the msg has been transferred */ 144 void slotMsgTransfered(const Akonadi::Item::List &msgs); 145 /** the KMImapJob is finished */ 146 void slotJobFinished(); 147 /** the transfer was canceled */ 148 void slotTransferCancelled(); 149 150 protected: 151 Akonadi::Item::List mRetrievedMsgs; 152 153 private: 154 // ProgressDialog for transferring messages 155 QPointer<QProgressDialog> mProgressDialog; 156 // Currently only one async command allowed at a time 157 static int mCountJobs; 158 int mCountMsgs = 0; 159 Result mResult = Undefined; 160 bool mDeletesItself : 1; 161 bool mEmitsCompletedItself : 1; 162 163 QWidget *const mParent; 164 Akonadi::Item::List mMsgList; 165 Akonadi::ItemFetchScope mFetchScope; 166 }; 167 168 class KMAILTESTS_TESTS_EXPORT KMMailtoComposeCommand : public KMCommand 169 { 170 Q_OBJECT 171 172 public: 173 explicit KMMailtoComposeCommand(const QUrl &url, const Akonadi::Item &msg = Akonadi::Item()); 174 175 private: 176 Q_REQUIRED_RESULT Result execute() override; 177 178 QUrl mUrl; 179 Akonadi::Item mMessage; 180 }; 181 182 class KMAILTESTS_TESTS_EXPORT KMMailtoReplyCommand : public KMCommand 183 { 184 Q_OBJECT 185 186 public: 187 KMMailtoReplyCommand(QWidget *parent, const QUrl &url, const Akonadi::Item &msg, const QString &selection); 188 189 Q_REQUIRED_RESULT bool replyAsHtml() const; 190 void setReplyAsHtml(bool replyAsHtml); 191 192 private: 193 Q_REQUIRED_RESULT Result execute() override; 194 195 QUrl mUrl; 196 QString mSelection; 197 bool mReplyAsHtml = false; 198 }; 199 200 class KMAILTESTS_TESTS_EXPORT KMMailtoForwardCommand : public KMCommand 201 { 202 Q_OBJECT 203 204 public: 205 KMMailtoForwardCommand(QWidget *parent, const QUrl &url, const Akonadi::Item &msg); 206 207 private: 208 Q_REQUIRED_RESULT Result execute() override; 209 QUrl mUrl; 210 }; 211 212 class KMAILTESTS_TESTS_EXPORT KMAddBookmarksCommand : public KMCommand 213 { 214 Q_OBJECT 215 216 public: 217 KMAddBookmarksCommand(const QUrl &url, QWidget *parent); 218 219 private: 220 Q_REQUIRED_RESULT Result execute() override; 221 222 QUrl mUrl; 223 }; 224 225 class KMAILTESTS_TESTS_EXPORT KMUrlSaveCommand : public KMCommand 226 { 227 Q_OBJECT 228 229 public: 230 KMUrlSaveCommand(const QUrl &url, QWidget *parent); 231 232 private Q_SLOTS: 233 void slotUrlSaveResult(KJob *job); 234 235 private: 236 Q_REQUIRED_RESULT Result execute() override; 237 238 QUrl mUrl; 239 }; 240 241 class KMAILTESTS_TESTS_EXPORT KMEditItemCommand : public KMCommand 242 { 243 Q_OBJECT 244 245 public: 246 explicit KMEditItemCommand(QWidget *parent, const Akonadi::Item &msg, bool deleteFromSource = true); 247 ~KMEditItemCommand() override; 248 private Q_SLOTS: 249 void slotDeleteItem(KJob *job); 250 251 private: 252 Q_REQUIRED_RESULT Result execute() override; 253 bool mDeleteFromSource = false; 254 }; 255 256 class KMAILTESTS_TESTS_EXPORT KMEditMessageCommand : public KMCommand 257 { 258 Q_OBJECT 259 260 public: 261 explicit KMEditMessageCommand(QWidget *parent, const KMime::Message::Ptr &msg); 262 263 private: 264 Q_REQUIRED_RESULT Result execute() override; 265 KMime::Message::Ptr mMessage; 266 }; 267 268 class KMAILTESTS_TESTS_EXPORT KMUseTemplateCommand : public KMCommand 269 { 270 Q_OBJECT 271 272 public: 273 KMUseTemplateCommand(QWidget *parent, const Akonadi::Item &msg); 274 275 private: 276 Q_REQUIRED_RESULT Result execute() override; 277 }; 278 279 class KMAILTESTS_TESTS_EXPORT KMSaveMsgCommand : public KMCommand 280 { 281 Q_OBJECT 282 283 public: 284 KMSaveMsgCommand(QWidget *parent, const Akonadi::Item::List &msgList); 285 286 private: 287 Q_REQUIRED_RESULT Result execute() override; 288 }; 289 290 class KMAILTESTS_TESTS_EXPORT KMOpenMsgCommand : public KMCommand 291 { 292 Q_OBJECT 293 294 public: 295 explicit KMOpenMsgCommand(QWidget *parent, const QUrl &url = QUrl(), const QString &encoding = QString(), KMMainWidget *main = nullptr); 296 297 private: 298 Q_REQUIRED_RESULT Result execute() override; 299 300 private Q_SLOTS: 301 void slotDataArrived(KIO::Job *job, const QByteArray &data); 302 void slotResult(KJob *job); 303 304 private: 305 void doesNotContainMessage(); 306 static const int MAX_CHUNK_SIZE = 64 * 1024; 307 QUrl mUrl; 308 QString mMsgString; 309 KIO::TransferJob *mJob = nullptr; 310 const QString mEncoding; 311 KMMainWidget *mMainWidget = nullptr; 312 }; 313 314 class KMAILTESTS_TESTS_EXPORT KMSaveAttachmentsCommand : public KMCommand 315 { 316 Q_OBJECT 317 public: 318 /** Use this to save all attachments of the given message. 319 @param parent The parent widget of the command used for message boxes. 320 @param msg The message of which the attachments should be saved. 321 @param viewer The message viewer. 322 */ 323 KMSaveAttachmentsCommand(QWidget *parent, const Akonadi::Item &msg, MessageViewer::Viewer *viewer); 324 /** Use this to save all attachments of the given messages. 325 @param parent The parent widget of the command used for message boxes. 326 @param msgs The messages of which the attachments should be saved. 327 */ 328 KMSaveAttachmentsCommand(QWidget *parent, const Akonadi::Item::List &msgs, MessageViewer::Viewer *viewer); 329 330 private: 331 Q_REQUIRED_RESULT Result execute() override; 332 MessageViewer::Viewer *mViewer = nullptr; 333 }; 334 335 class KMAILTESTS_TESTS_EXPORT KMReplyCommand : public KMCommand 336 { 337 Q_OBJECT 338 public: 339 KMReplyCommand(QWidget *parent, 340 const Akonadi::Item &msg, 341 MessageComposer::ReplyStrategy replyStrategy, 342 const QString &selection = QString(), 343 bool noquote = false, 344 const QString &templateName = QString()); 345 Q_REQUIRED_RESULT bool replyAsHtml() const; 346 void setReplyAsHtml(bool replyAsHtml); 347 348 private: 349 Q_REQUIRED_RESULT Result execute() override; 350 351 private: 352 QString mSelection; 353 QString mTemplate; 354 MessageComposer::ReplyStrategy m_replyStrategy; 355 bool mNoQuote = false; 356 bool mReplyAsHtml = false; 357 }; 358 359 class KMAILTESTS_TESTS_EXPORT KMForwardCommand : public KMCommand 360 { 361 Q_OBJECT 362 363 public: 364 KMForwardCommand(QWidget *parent, 365 const Akonadi::Item::List &msgList, 366 uint identity = 0, 367 const QString &templateName = QString(), 368 const QString &selection = QString()); 369 KMForwardCommand(QWidget *parent, 370 const Akonadi::Item &msg, 371 uint identity = 0, 372 const QString &templateName = QString(), 373 const QString &selection = QString()); 374 375 private: 376 Q_REQUIRED_RESULT KMCommand::Result createComposer(const Akonadi::Item &item); 377 Result execute() override; 378 379 private: 380 uint mIdentity; 381 QString mTemplate; 382 QString mSelection; 383 }; 384 385 class KMAILTESTS_TESTS_EXPORT KMForwardAttachedCommand : public KMCommand 386 { 387 Q_OBJECT 388 389 public: 390 KMForwardAttachedCommand(QWidget *parent, const Akonadi::Item::List &msgList, uint identity = 0, KMail::Composer *win = nullptr); 391 KMForwardAttachedCommand(QWidget *parent, const Akonadi::Item &msg, uint identity = 0, KMail::Composer *win = nullptr); 392 393 private: 394 Result execute() override; 395 396 uint mIdentity; 397 QPointer<KMail::Composer> mWin; 398 }; 399 400 class KMAILTESTS_TESTS_EXPORT KMRedirectCommand : public KMCommand 401 { 402 Q_OBJECT 403 404 public: 405 KMRedirectCommand(QWidget *parent, const Akonadi::Item &msg); 406 KMRedirectCommand(QWidget *parent, const Akonadi::Item::List &msgList); 407 408 private: 409 Q_REQUIRED_RESULT Result execute() override; 410 }; 411 412 struct KMAILTESTS_TESTS_EXPORT KMPrintCommandInfo { 413 Akonadi::Item mMsg; 414 QFont mOverrideFont; 415 QString mEncoding; 416 MessageViewer::Viewer::DisplayFormatMessage mFormat = MessageViewer::Viewer::UseGlobalSetting; 417 const MessageViewer::AttachmentStrategy *mAttachmentStrategy = nullptr; 418 MessageViewer::HeaderStylePlugin *mHeaderStylePlugin = nullptr; 419 bool mHtmlLoadExtOverride = false; 420 bool mUseFixedFont = false; 421 bool mPrintPreview = false; 422 bool mShowSignatureDetails = false; 423 bool mShowEncryptionDetails = false; 424 }; 425 426 QDebug operator<<(QDebug d, const KMPrintCommandInfo &t); 427 428 class KMAILTESTS_TESTS_EXPORT KMPrintCommand : public KMCommand 429 { 430 Q_OBJECT 431 432 public: 433 KMPrintCommand(QWidget *parent, const KMPrintCommandInfo &commandInfo); 434 435 private: 436 Q_REQUIRED_RESULT Result execute() override; 437 438 KMPrintCommandInfo mPrintCommandInfo; 439 }; 440 441 class KMAILTESTS_TESTS_EXPORT KMSetStatusCommand : public KMCommand 442 { 443 Q_OBJECT 444 445 public: 446 // Serial numbers 447 KMSetStatusCommand(const MessageStatus &status, const Akonadi::Item::List &items, bool invert = false); 448 449 protected Q_SLOTS: 450 void slotModifyItemDone(KJob *job); 451 452 private: 453 Q_REQUIRED_RESULT Result execute() override; 454 MessageStatus mStatus; 455 bool mInvertMark = false; 456 }; 457 458 /** This command is used to set or toggle a tag for a list of messages. If toggle is 459 true then the tag is deleted if it is already applied. 460 */ 461 class KMAILTESTS_TESTS_EXPORT KMSetTagCommand : public KMCommand 462 { 463 Q_OBJECT 464 465 public: 466 enum SetTagMode { 467 AddIfNotExisting, 468 Toggle, 469 CleanExistingAndAddNew, 470 }; 471 472 KMSetTagCommand(const Akonadi::Tag::List &tags, const Akonadi::Item::List &item, SetTagMode mode = AddIfNotExisting); 473 474 protected Q_SLOTS: 475 void slotModifyItemDone(KJob *job); 476 477 private: 478 Q_REQUIRED_RESULT Result execute() override; 479 void setTags(); 480 481 Akonadi::Tag::List mTags; 482 Akonadi::Tag::List mCreatedTags; 483 Akonadi::Item::List mItem; 484 SetTagMode mMode; 485 }; 486 487 /* This command is used to apply a single filter (AKA ad-hoc filter) 488 to a set of messages */ 489 class KMAILTESTS_TESTS_EXPORT KMFilterActionCommand : public KMCommand 490 { 491 Q_OBJECT 492 493 public: 494 KMFilterActionCommand(QWidget *parent, const QVector<qlonglong> &msgListId, const QString &filterId); 495 496 private: 497 Q_REQUIRED_RESULT Result execute() override; 498 QVector<qlonglong> mMsgListId; 499 QString mFilterId; 500 }; 501 502 class KMAILTESTS_TESTS_EXPORT KMMetaFilterActionCommand : public QObject 503 { 504 Q_OBJECT 505 506 public: 507 KMMetaFilterActionCommand(const QString &filterId, KMMainWidget *main); 508 509 public Q_SLOTS: 510 void start(); 511 512 private: 513 QString mFilterId; 514 KMMainWidget *mMainWidget = nullptr; 515 }; 516 517 class KMAILTESTS_TESTS_EXPORT KMMailingListFilterCommand : public KMCommand 518 { 519 Q_OBJECT 520 521 public: 522 KMMailingListFilterCommand(QWidget *parent, const Akonadi::Item &msg); 523 524 private: 525 Q_REQUIRED_RESULT Result execute() override; 526 }; 527 528 class KMAILTESTS_TESTS_EXPORT KMCopyCommand : public KMCommand 529 { 530 Q_OBJECT 531 532 public: 533 KMCopyCommand(const Akonadi::Collection &destFolder, const Akonadi::Item::List &msgList); 534 KMCopyCommand(const Akonadi::Collection &destFolder, const Akonadi::Item &msg); 535 536 protected Q_SLOTS: 537 void slotCopyResult(KJob *job); 538 539 private: 540 Q_REQUIRED_RESULT Result execute() override; 541 542 Akonadi::Collection mDestFolder; 543 }; 544 545 class KMAILTESTS_TESTS_EXPORT KMCopyDecryptedCommand : public KMCommand 546 { 547 Q_OBJECT 548 public: 549 KMCopyDecryptedCommand(const Akonadi::Collection &destFolder, const Akonadi::Item::List &msgList); 550 KMCopyDecryptedCommand(const Akonadi::Collection &destFolder, const Akonadi::Item &msg); 551 552 protected Q_SLOTS: 553 void slotAppendResult(KJob *job); 554 555 private: 556 Q_REQUIRED_RESULT Result execute() override; 557 558 Akonadi::Collection mDestFolder; 559 QList<KJob *> mPendingJobs; 560 }; 561 562 class KMAILTESTS_TESTS_EXPORT KMMoveCommand : public KMCommand 563 { 564 Q_OBJECT 565 566 public: 567 KMMoveCommand(const Akonadi::Collection &destFolder, const Akonadi::Item::List &msgList, MessageList::Core::MessageItemSetReference ref); 568 KMMoveCommand(const Akonadi::Collection &destFolder, 569 const Akonadi::Item &msg, 570 MessageList::Core::MessageItemSetReference ref = MessageList::Core::MessageItemSetReference()); destFolder()571 Q_REQUIRED_RESULT Akonadi::Collection destFolder() const 572 { 573 return mDestFolder; 574 } 575 refSet()576 Q_REQUIRED_RESULT MessageList::Core::MessageItemSetReference refSet() const 577 { 578 return mRef; 579 } 580 581 public Q_SLOTS: 582 void slotMoveCanceled(); 583 void slotMoveResult(KJob *job); 584 585 protected: setDestFolder(const Akonadi::Collection & folder)586 void setDestFolder(const Akonadi::Collection &folder) 587 { 588 mDestFolder = folder; 589 } 590 591 Q_SIGNALS: 592 void moveDone(KMMoveCommand *); 593 594 private: 595 Q_REQUIRED_RESULT Result execute() override; 596 void completeMove(Result result); 597 598 Akonadi::Collection mDestFolder; 599 KPIM::ProgressItem *mProgressItem = nullptr; 600 MessageList::Core::MessageItemSetReference mRef; 601 }; 602 603 class KMAILTESTS_TESTS_EXPORT KMTrashMsgCommand final : public KMCommand 604 { 605 Q_OBJECT 606 607 public: 608 enum TrashOperation { 609 Unknown, 610 MoveToTrash, 611 Delete, 612 Both, 613 }; 614 615 KMTrashMsgCommand(const Akonadi::Collection &srcFolder, const Akonadi::Item::List &msgList, MessageList::Core::MessageItemSetReference ref); 616 KMTrashMsgCommand(const Akonadi::Collection &srcFolder, const Akonadi::Item &msg, MessageList::Core::MessageItemSetReference ref); refSet()617 Q_REQUIRED_RESULT MessageList::Core::MessageItemSetReference refSet() const 618 { 619 return mRef; 620 } 621 622 TrashOperation operation() const; 623 624 public Q_SLOTS: 625 void slotMoveCanceled(); 626 627 private Q_SLOTS: 628 void slotMoveResult(KJob *job); 629 void slotDeleteResult(KJob *job); 630 Q_SIGNALS: 631 void moveDone(KMTrashMsgCommand *); 632 633 private: 634 Q_REQUIRED_RESULT Result execute() override; 635 void completeMove(Result result); 636 637 Q_REQUIRED_RESULT static Akonadi::Collection findTrashFolder(const Akonadi::Collection &srcFolder); 638 639 QMap<Akonadi::Collection, Akonadi::Item::List> mTrashFolders; 640 KPIM::ProgressItem *mMoveProgress = nullptr; 641 KPIM::ProgressItem *mDeleteProgress = nullptr; 642 MessageList::Core::MessageItemSetReference mRef; 643 QList<KJob *> mPendingMoves; 644 QList<KJob *> mPendingDeletes; 645 }; 646 647 class KMAILTESTS_TESTS_EXPORT KMResendMessageCommand : public KMCommand 648 { 649 Q_OBJECT 650 651 public: 652 explicit KMResendMessageCommand(QWidget *parent, const Akonadi::Item &msg = Akonadi::Item()); 653 654 private: 655 Q_REQUIRED_RESULT Result execute() override; 656 }; 657 658 class KMAILTESTS_TESTS_EXPORT KMShareImageCommand : public KMCommand 659 { 660 Q_OBJECT 661 662 public: 663 explicit KMShareImageCommand(const QUrl &url, QWidget *parent); 664 665 private: 666 Q_REQUIRED_RESULT Result execute() override; 667 QUrl mUrl; 668 }; 669 670 class KMAILTESTS_TESTS_EXPORT KMFetchMessageCommand : public KMCommand 671 { 672 Q_OBJECT 673 public: 674 explicit KMFetchMessageCommand(QWidget *parent, const Akonadi::Item &item, MessageViewer::Viewer *viewer, KMReaderMainWin *win = nullptr); 675 676 Q_REQUIRED_RESULT Akonadi::Item item() const; 677 678 KMReaderMainWin *readerMainWin() const; 679 680 private: 681 Akonadi::ItemFetchJob *createFetchJob(const Akonadi::Item::List &items) override; 682 Q_REQUIRED_RESULT Result execute() override; 683 684 Akonadi::Item mItem; 685 MessageViewer::Viewer *mViewer = nullptr; 686 KMReaderMainWin *mReaderMainWin = nullptr; 687 }; 688 689