File indexing completed on 2024-05-12 05:20:45
0001 /* 0002 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "messageactions.h" 0008 0009 #include "kmcommands.h" 0010 #include "kmkernel.h" 0011 #include "kmreaderwin.h" 0012 #include "settings/kmailsettings.h" 0013 #include "util.h" 0014 #include <MailCommon/MailKernel> 0015 #include <TemplateParser/CustomTemplatesMenu> 0016 0017 #include <MessageCore/MailingList> 0018 #include <MessageCore/MessageCoreSettings> 0019 #include <MessageCore/StringUtil> 0020 #include <MessageViewer/HeaderStylePlugin> 0021 #include <MessageViewer/MessageViewerSettings> 0022 #include <PimCommonAkonadi/AnnotationDialog> 0023 0024 #include <Akonadi/ChangeRecorder> 0025 #include <Akonadi/ItemFetchJob> 0026 #include <Akonadi/MessageParts> 0027 #include <Debug/akonadisearchdebugdialog.h> 0028 #include <KIO/KUriFilterSearchProviderActions> 0029 #include <QAction> 0030 0031 #include "job/createfollowupreminderonexistingmessagejob.h" 0032 #include <MessageComposer/FollowUpReminderSelectDateDialog> 0033 0034 #include "kmail_debug.h" 0035 #include <Akonadi/ItemFetchJob> 0036 #include <KActionCollection> 0037 #include <KActionMenu> 0038 #include <KIO/JobUiDelegateFactory> 0039 #include <KIO/OpenUrlJob> 0040 #include <KLocalizedString> 0041 #include <KStringHandler> 0042 #include <KUriFilter> 0043 #include <KXMLGUIClient> 0044 #include <QFileDialog> 0045 #include <QIcon> 0046 #include <QMenu> 0047 0048 #include "folderarchive/folderarchivemanager.h" 0049 #include <Akonadi/Collection> 0050 #include <Akonadi/EntityAnnotationsAttribute> 0051 #include <Akonadi/StandardMailActionManager> 0052 #include <MailCommon/MailUtil> 0053 #include <MessageViewer/MessageViewerUtil> 0054 #include <QVariant> 0055 #include <QWidget> 0056 0057 using namespace KMail; 0058 0059 MessageActions::MessageActions(KActionCollection *ac, QWidget *parent) 0060 : QObject(parent) 0061 , mParent(parent) 0062 , mReplyActionMenu(new KActionMenu(QIcon::fromTheme(QStringLiteral("mail-reply-sender")), i18nc("Message->", "&Reply"), this)) 0063 , mReplyAction(new QAction(QIcon::fromTheme(QStringLiteral("mail-reply-sender")), i18n("&Reply..."), this)) 0064 , mReplyAllAction(new QAction(QIcon::fromTheme(QStringLiteral("mail-reply-all")), i18n("Reply to &All..."), this)) 0065 , mReplyAuthorAction(new QAction(QIcon::fromTheme(QStringLiteral("mail-reply-sender")), i18n("Reply to A&uthor..."), this)) 0066 , mReplyListAction(new QAction(QIcon::fromTheme(QStringLiteral("mail-reply-list")), i18n("Reply to Mailing-&List..."), this)) 0067 , mNoQuoteReplyAction(new QAction(i18n("Reply Without &Quote..."), this)) 0068 , mForwardInlineAction(new QAction(QIcon::fromTheme(QStringLiteral("mail-forward")), i18nc("@action:inmenu Message->Forward->", "&Inline..."), this)) 0069 , mForwardAttachedAction( 0070 new QAction(QIcon::fromTheme(QStringLiteral("mail-forward")), i18nc("@action:inmenu Message->Forward->", "As &Attachment..."), this)) 0071 , mRedirectAction(new QAction(i18nc("Message->Forward->", "&Redirect..."), this)) 0072 , mNewToRecipientsAction(new QAction(i18n("New Message to Recipients..."), this)) 0073 , mStatusMenu(new KActionMenu(i18n("Mar&k Message"), this)) 0074 , mForwardActionMenu(new KActionMenu(QIcon::fromTheme(QStringLiteral("mail-forward")), i18nc("Message->", "&Forward"), this)) 0075 , mMailingListActionMenu(new KActionMenu(QIcon::fromTheme(QStringLiteral("mail-message-new-list")), i18nc("Message->", "Mailing-&List"), this)) 0076 , mAnnotateAction(new QAction(QIcon::fromTheme(QStringLiteral("view-pim-notes")), i18n("Add Note..."), this)) 0077 , mEditAsNewAction(new QAction(QIcon::fromTheme(QStringLiteral("document-edit")), i18n("&Edit As New"), this)) 0078 , mListFilterAction(new QAction(i18n("Filter on Mailing-&List..."), this)) 0079 , mAddFollowupReminderAction(new QAction(i18n("Add Followup Reminder..."), this)) 0080 , mDebugAkonadiSearchAction(new QAction(QStringLiteral("Debug Akonadi Search..."), this)) /* dont translate it*/ 0081 , mSendAgainAction(new QAction(i18n("Send A&gain..."), this)) 0082 , mNewMessageFromTemplateAction(new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("New Message From &Template"), this)) 0083 , mWebShortcutMenuManager(new KIO::KUriFilterSearchProviderActions(this)) 0084 , mExportToPdfAction(new QAction(QIcon::fromTheme(QStringLiteral("application-pdf")), i18n("Export to PDF..."), this)) 0085 , mArchiveMessageAction(new QAction(i18nc("@action:inmenu", "Archive Message"), this)) 0086 0087 { 0088 ac->addAction(QStringLiteral("message_reply_menu"), mReplyActionMenu); 0089 connect(mReplyActionMenu, &KActionMenu::triggered, this, &MessageActions::slotReplyToMsg); 0090 0091 ac->addAction(QStringLiteral("reply"), mReplyAction); 0092 ac->setDefaultShortcut(mReplyAction, Qt::Key_R); 0093 connect(mReplyAction, &QAction::triggered, this, &MessageActions::slotReplyToMsg); 0094 mReplyActionMenu->addAction(mReplyAction); 0095 0096 ac->addAction(QStringLiteral("reply_author"), mReplyAuthorAction); 0097 ac->setDefaultShortcut(mReplyAuthorAction, Qt::SHIFT | Qt::Key_A); 0098 connect(mReplyAuthorAction, &QAction::triggered, this, &MessageActions::slotReplyAuthorToMsg); 0099 mReplyActionMenu->addAction(mReplyAuthorAction); 0100 0101 ac->addAction(QStringLiteral("reply_all"), mReplyAllAction); 0102 ac->setDefaultShortcut(mReplyAllAction, Qt::Key_A); 0103 connect(mReplyAllAction, &QAction::triggered, this, &MessageActions::slotReplyAllToMsg); 0104 mReplyActionMenu->addAction(mReplyAllAction); 0105 0106 ac->addAction(QStringLiteral("reply_list"), mReplyListAction); 0107 0108 ac->setDefaultShortcut(mReplyListAction, Qt::Key_L); 0109 connect(mReplyListAction, &QAction::triggered, this, &MessageActions::slotReplyListToMsg); 0110 mReplyActionMenu->addAction(mReplyListAction); 0111 0112 ac->addAction(QStringLiteral("noquotereply"), mNoQuoteReplyAction); 0113 ac->setDefaultShortcut(mNoQuoteReplyAction, Qt::SHIFT | Qt::Key_R); 0114 connect(mNoQuoteReplyAction, &QAction::triggered, this, &MessageActions::slotNoQuoteReplyToMsg); 0115 0116 ac->addAction(QStringLiteral("mlist_filter"), mListFilterAction); 0117 connect(mListFilterAction, &QAction::triggered, this, &MessageActions::slotMailingListFilter); 0118 0119 ac->addAction(QStringLiteral("set_status"), mStatusMenu); 0120 0121 ac->addAction(QStringLiteral("annotate"), mAnnotateAction); 0122 connect(mAnnotateAction, &QAction::triggered, this, &MessageActions::annotateMessage); 0123 0124 ac->addAction(QStringLiteral("editasnew"), mEditAsNewAction); 0125 connect(mEditAsNewAction, &QAction::triggered, this, &MessageActions::editCurrentMessage); 0126 ac->setDefaultShortcut(mEditAsNewAction, Qt::Key_T); 0127 0128 mPrintAction = KStandardAction::print(this, &MessageActions::slotPrintMessage, ac); 0129 mPrintPreviewAction = KStandardAction::printPreview(this, &MessageActions::slotPrintPreviewMsg, ac); 0130 0131 ac->addAction(QStringLiteral("message_forward"), mForwardActionMenu); 0132 0133 connect(mForwardAttachedAction, SIGNAL(triggered(bool)), parent, SLOT(slotForwardAttachedMessage())); 0134 0135 ac->addAction(QStringLiteral("message_forward_as_attachment"), mForwardAttachedAction); 0136 0137 connect(mForwardInlineAction, SIGNAL(triggered(bool)), parent, SLOT(slotForwardInlineMsg())); 0138 0139 ac->addAction(QStringLiteral("message_forward_inline"), mForwardInlineAction); 0140 0141 setupForwardActions(ac); 0142 0143 ac->addAction(QStringLiteral("new_to_recipients"), mNewToRecipientsAction); 0144 connect(mNewToRecipientsAction, SIGNAL(triggered(bool)), parent, SLOT(slotNewMessageToRecipients())); 0145 0146 ac->addAction(QStringLiteral("message_forward_redirect"), mRedirectAction); 0147 connect(mRedirectAction, SIGNAL(triggered(bool)), parent, SLOT(slotRedirectMessage())); 0148 0149 ac->setDefaultShortcut(mRedirectAction, QKeySequence(Qt::Key_E)); 0150 mForwardActionMenu->addAction(mRedirectAction); 0151 0152 connect(mMailingListActionMenu->menu(), &QMenu::triggered, this, &MessageActions::slotRunUrl); 0153 ac->addAction(QStringLiteral("mailing_list"), mMailingListActionMenu); 0154 mMailingListActionMenu->setEnabled(false); 0155 0156 connect(kmkernel->folderCollectionMonitor(), &Akonadi::Monitor::itemChanged, this, &MessageActions::slotItemModified); 0157 connect(kmkernel->folderCollectionMonitor(), &Akonadi::Monitor::itemRemoved, this, &MessageActions::slotItemRemoved); 0158 0159 mCustomTemplatesMenu = new TemplateParser::CustomTemplatesMenu(parent, ac); 0160 0161 connect(mCustomTemplatesMenu, SIGNAL(replyTemplateSelected(QString)), parent, SLOT(slotCustomReplyToMsg(QString))); 0162 connect(mCustomTemplatesMenu, SIGNAL(replyAllTemplateSelected(QString)), parent, SLOT(slotCustomReplyAllToMsg(QString))); 0163 connect(mCustomTemplatesMenu, SIGNAL(forwardTemplateSelected(QString)), parent, SLOT(slotCustomForwardMsg(QString))); 0164 connect(KMKernel::self(), &KMKernel::customTemplatesChanged, mCustomTemplatesMenu, &TemplateParser::CustomTemplatesMenu::update); 0165 0166 forwardMenu()->addSeparator(); 0167 forwardMenu()->addAction(mCustomTemplatesMenu->forwardActionMenu()); 0168 replyMenu()->addSeparator(); 0169 replyMenu()->addAction(mCustomTemplatesMenu->replyActionMenu()); 0170 replyMenu()->addAction(mCustomTemplatesMenu->replyAllActionMenu()); 0171 0172 // Don't translate it. Shown only when we set env variable AKONADI_SEARCH_DEBUG 0173 connect(mDebugAkonadiSearchAction, &QAction::triggered, this, &MessageActions::slotDebugAkonadiSearch); 0174 0175 ac->addAction(QStringLiteral("message_followup_reminder"), mAddFollowupReminderAction); 0176 connect(mAddFollowupReminderAction, &QAction::triggered, this, &MessageActions::slotAddFollowupReminder); 0177 0178 ac->addAction(QStringLiteral("send_again"), mSendAgainAction); 0179 connect(mSendAgainAction, &QAction::triggered, this, &MessageActions::slotResendMessage); 0180 0181 ac->addAction(QStringLiteral("use_template"), mNewMessageFromTemplateAction); 0182 connect(mNewMessageFromTemplateAction, &QAction::triggered, this, &MessageActions::slotUseTemplate); 0183 ac->setDefaultShortcut(mNewMessageFromTemplateAction, QKeySequence(Qt::SHIFT | Qt::Key_N)); 0184 0185 ac->addAction(QStringLiteral("file_export_pdf"), mExportToPdfAction); 0186 connect(mExportToPdfAction, &QAction::triggered, this, &MessageActions::slotExportToPdf); 0187 0188 ac->addAction(QStringLiteral("archive_message"), mArchiveMessageAction); 0189 connect(mArchiveMessageAction, &QAction::triggered, this, &MessageActions::slotArchiveMessage); 0190 0191 updateActions(); 0192 } 0193 0194 MessageActions::~MessageActions() 0195 { 0196 delete mCustomTemplatesMenu; 0197 } 0198 0199 void MessageActions::fillAkonadiStandardAction(Akonadi::StandardMailActionManager *akonadiStandardActionManager) 0200 { 0201 QAction *action = akonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MarkMailAsRead); 0202 mStatusMenu->addAction(action); 0203 0204 action = akonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MarkMailAsUnread); 0205 mStatusMenu->addAction(action); 0206 0207 mStatusMenu->addSeparator(); 0208 action = akonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MarkMailAsImportant); 0209 mStatusMenu->addAction(action); 0210 0211 action = akonadiStandardActionManager->action(Akonadi::StandardMailActionManager::MarkMailAsActionItem); 0212 mStatusMenu->addAction(action); 0213 } 0214 0215 TemplateParser::CustomTemplatesMenu *MessageActions::customTemplatesMenu() const 0216 { 0217 return mCustomTemplatesMenu; 0218 } 0219 0220 void MessageActions::slotUseTemplate() 0221 { 0222 if (!mCurrentItem.isValid()) { 0223 return; 0224 } 0225 KMCommand *command = new KMUseTemplateCommand(mParent, mCurrentItem); 0226 command->start(); 0227 } 0228 0229 QAction *MessageActions::editAsNewAction() const 0230 { 0231 return mEditAsNewAction; 0232 } 0233 0234 void MessageActions::setCurrentMessage(const Akonadi::Item &msg, const Akonadi::Item::List &items) 0235 { 0236 mCurrentItem = msg; 0237 0238 if (!items.isEmpty()) { 0239 if (msg.isValid()) { 0240 mVisibleItems = items; 0241 } else { 0242 mVisibleItems.clear(); 0243 } 0244 } 0245 0246 if (!msg.isValid()) { 0247 mVisibleItems.clear(); 0248 clearMailingListActions(); 0249 } 0250 0251 updateActions(); 0252 } 0253 0254 KActionMenu *MessageActions::replyMenu() const 0255 { 0256 return mReplyActionMenu; 0257 } 0258 0259 QAction *MessageActions::replyListAction() const 0260 { 0261 return mReplyListAction; 0262 } 0263 0264 QAction *MessageActions::forwardInlineAction() const 0265 { 0266 return mForwardInlineAction; 0267 } 0268 0269 QAction *MessageActions::forwardAttachedAction() const 0270 { 0271 return mForwardAttachedAction; 0272 } 0273 0274 QAction *MessageActions::redirectAction() const 0275 { 0276 return mRedirectAction; 0277 } 0278 0279 QAction *MessageActions::newToRecipientsAction() const 0280 { 0281 return mNewToRecipientsAction; 0282 } 0283 0284 KActionMenu *MessageActions::messageStatusMenu() const 0285 { 0286 return mStatusMenu; 0287 } 0288 0289 KActionMenu *MessageActions::forwardMenu() const 0290 { 0291 return mForwardActionMenu; 0292 } 0293 0294 QAction *MessageActions::annotateAction() const 0295 { 0296 return mAnnotateAction; 0297 } 0298 0299 QAction *MessageActions::printAction() const 0300 { 0301 return mPrintAction; 0302 } 0303 0304 QAction *MessageActions::printPreviewAction() const 0305 { 0306 return mPrintPreviewAction; 0307 } 0308 0309 QAction *MessageActions::listFilterAction() const 0310 { 0311 return mListFilterAction; 0312 } 0313 0314 KActionMenu *MessageActions::mailingListActionMenu() const 0315 { 0316 return mMailingListActionMenu; 0317 } 0318 0319 void MessageActions::slotItemRemoved(const Akonadi::Item &item) 0320 { 0321 if (item == mCurrentItem) { 0322 mCurrentItem = Akonadi::Item(); 0323 updateActions(); 0324 } 0325 } 0326 0327 void MessageActions::slotItemModified(const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers) 0328 { 0329 Q_UNUSED(partIdentifiers) 0330 if (item == mCurrentItem) { 0331 mCurrentItem = item; 0332 const int numberOfVisibleItems = mVisibleItems.count(); 0333 for (int i = 0; i < numberOfVisibleItems; ++i) { 0334 Akonadi::Item it = mVisibleItems.at(i); 0335 if (item == it) { 0336 mVisibleItems[i] = item; 0337 } 0338 } 0339 updateActions(); 0340 } 0341 } 0342 0343 void MessageActions::updateActions() 0344 { 0345 const bool hasPayload = mCurrentItem.hasPayload<KMime::Message::Ptr>(); 0346 bool itemValid = mCurrentItem.isValid(); 0347 Akonadi::Collection parent; 0348 if (itemValid) { //=> valid 0349 parent = mCurrentItem.parentCollection(); 0350 } 0351 if (parent.isValid()) { 0352 if (CommonKernel->folderIsTemplates(parent)) { 0353 itemValid = false; 0354 } 0355 } 0356 0357 const bool multiVisible = !mVisibleItems.isEmpty() || mCurrentItem.isValid(); 0358 const bool uniqItem = (itemValid || hasPayload) && (mVisibleItems.count() <= 1); 0359 mReplyActionMenu->setEnabled(hasPayload); 0360 mReplyAction->setEnabled(hasPayload); 0361 mNoQuoteReplyAction->setEnabled(hasPayload); 0362 mReplyAuthorAction->setEnabled(hasPayload); 0363 mReplyAllAction->setEnabled(hasPayload); 0364 mReplyListAction->setEnabled(hasPayload); 0365 mNoQuoteReplyAction->setEnabled(hasPayload); 0366 mSendAgainAction->setEnabled(hasPayload); 0367 0368 mAnnotateAction->setEnabled(uniqItem); 0369 mAddFollowupReminderAction->setEnabled(uniqItem); 0370 if (!mCurrentItem.hasAttribute<Akonadi::EntityAnnotationsAttribute>()) { 0371 mAnnotateAction->setText(i18n("Add Note...")); 0372 } else { 0373 mAnnotateAction->setText(i18n("Edit Note...")); 0374 } 0375 0376 mStatusMenu->setEnabled(multiVisible); 0377 0378 mPrintAction->setEnabled(mMessageView != nullptr); 0379 mPrintPreviewAction->setEnabled(mMessageView != nullptr); 0380 mExportToPdfAction->setEnabled(uniqItem); 0381 if (mCurrentItem.hasPayload<KMime::Message::Ptr>()) { 0382 if (mCurrentItem.loadedPayloadParts().contains("RFC822")) { 0383 updateMailingListActions(mCurrentItem); 0384 } else { 0385 auto job = new Akonadi::ItemFetchJob(mCurrentItem); 0386 job->fetchScope().fetchAllAttributes(); 0387 job->fetchScope().fetchFullPayload(true); 0388 job->fetchScope().fetchPayloadPart(Akonadi::MessagePart::Header); 0389 job->fetchScope().fetchAttribute<Akonadi::EntityAnnotationsAttribute>(); 0390 connect(job, &Akonadi::ItemFetchJob::result, this, &MessageActions::slotUpdateActionsFetchDone); 0391 } 0392 } 0393 mEditAsNewAction->setEnabled(uniqItem); 0394 mArchiveMessageAction->setEnabled(hasPayload); 0395 } 0396 0397 void MessageActions::slotUpdateActionsFetchDone(KJob *job) 0398 { 0399 if (job->error()) { 0400 return; 0401 } 0402 0403 auto fetchJob = static_cast<Akonadi::ItemFetchJob *>(job); 0404 if (fetchJob->items().isEmpty()) { 0405 return; 0406 } 0407 const Akonadi::Item messageItem = fetchJob->items().constFirst(); 0408 if (messageItem == mCurrentItem) { 0409 mCurrentItem = messageItem; 0410 updateMailingListActions(messageItem); 0411 } 0412 } 0413 0414 void MessageActions::clearMailingListActions() 0415 { 0416 mMailingListActionMenu->setEnabled(false); 0417 mListFilterAction->setEnabled(false); 0418 mListFilterAction->setText(i18n("Filter on Mailing-List...")); 0419 } 0420 0421 void MessageActions::updateMailingListActions(const Akonadi::Item &messageItem) 0422 { 0423 if (!messageItem.hasPayload<KMime::Message::Ptr>()) { 0424 return; 0425 } 0426 auto message = messageItem.payload<KMime::Message::Ptr>(); 0427 const MessageCore::MailingList mailList = MessageCore::MailingList::detect(message); 0428 0429 if (mailList.features() == MessageCore::MailingList::None) { 0430 clearMailingListActions(); 0431 } else { 0432 // A mailing list menu with only a title is pretty boring 0433 // so make sure theres at least some content 0434 QString listId; 0435 if (mailList.features() & MessageCore::MailingList::Id) { 0436 // From a list-id in the form, "Birds of France <bof.yahoo.com>", 0437 // take "Birds of France" if it exists otherwise "bof.yahoo.com". 0438 listId = mailList.id(); 0439 const int start = listId.indexOf(QLatin1Char('<')); 0440 if (start > 0) { 0441 listId.truncate(start - 1); 0442 } else if (start == 0) { 0443 const int end = listId.lastIndexOf(QLatin1Char('>')); 0444 if (end < 1) { // shouldn't happen but account for it anyway 0445 listId.remove(0, 1); 0446 } else { 0447 listId = listId.mid(1, end - 1); 0448 } 0449 } 0450 } 0451 mMailingListActionMenu->menu()->clear(); 0452 qDeleteAll(mMailListActionList); 0453 mMailListActionList.clear(); 0454 mMailingListActionMenu->menu()->setTitle(KStringHandler::rsqueeze(i18n("Mailing List Name: %1", (listId.isEmpty() ? i18n("<unknown>") : listId)), 40)); 0455 if (mailList.features() & MessageCore::MailingList::ArchivedAt) { 0456 // IDEA: this may be something you want to copy - "Copy in submenu"? 0457 addMailingListActions(i18n("Open Message in List Archive"), mailList.archivedAtUrls()); 0458 } 0459 if (mailList.features() & MessageCore::MailingList::Post) { 0460 addMailingListActions(i18n("Post New Message"), mailList.postUrls()); 0461 } 0462 if (mailList.features() & MessageCore::MailingList::Archive) { 0463 addMailingListActions(i18n("Go to Archive"), mailList.archiveUrls()); 0464 } 0465 if (mailList.features() & MessageCore::MailingList::Help) { 0466 addMailingListActions(i18n("Request Help"), mailList.helpUrls()); 0467 } 0468 if (mailList.features() & MessageCore::MailingList::Owner) { 0469 addMailingListActions(i18nc("Contact the owner of the mailing list", "Contact Owner"), mailList.ownerUrls()); 0470 } 0471 if (mailList.features() & MessageCore::MailingList::Subscribe) { 0472 addMailingListActions(i18n("Subscribe to List"), mailList.subscribeUrls()); 0473 } 0474 if (mailList.features() & MessageCore::MailingList::Unsubscribe) { 0475 addMailingListActions(i18n("Unsubscribe from List"), mailList.unsubscribeUrls()); 0476 } 0477 mMailingListActionMenu->setEnabled(true); 0478 0479 QByteArray name; 0480 QString value; 0481 const QString lname = MailingList::name(message, name, value); 0482 if (!lname.isEmpty()) { 0483 mListFilterAction->setEnabled(true); 0484 mListFilterAction->setText(i18n("Filter on Mailing-List %1...", lname)); 0485 } 0486 } 0487 } 0488 0489 void MessageActions::replyCommand(MessageComposer::ReplyStrategy strategy) 0490 { 0491 if (!mCurrentItem.hasPayload<KMime::Message::Ptr>()) { 0492 return; 0493 } 0494 0495 const QString text = mMessageView ? mMessageView->copyText() : QString(); 0496 auto command = new KMReplyCommand(mParent, mCurrentItem, strategy, text); 0497 command->setReplyAsHtml(mMessageView ? mMessageView->viewer()->htmlMail() : false); 0498 connect(command, &KMCommand::completed, this, &MessageActions::replyActionFinished); 0499 command->start(); 0500 } 0501 0502 void MessageActions::setMessageView(KMReaderWin *msgView) 0503 { 0504 mMessageView = msgView; 0505 } 0506 0507 void MessageActions::setupForwardActions(KActionCollection *ac) 0508 { 0509 disconnect(mForwardActionMenu, SIGNAL(triggered(bool)), nullptr, nullptr); 0510 mForwardActionMenu->removeAction(mForwardInlineAction); 0511 mForwardActionMenu->removeAction(mForwardAttachedAction); 0512 0513 if (KMailSettings::self()->forwardingInlineByDefault()) { 0514 mForwardActionMenu->insertAction(mRedirectAction, mForwardInlineAction); 0515 mForwardActionMenu->insertAction(mRedirectAction, mForwardAttachedAction); 0516 ac->setDefaultShortcut(mForwardInlineAction, QKeySequence(Qt::Key_F)); 0517 ac->setDefaultShortcut(mForwardAttachedAction, QKeySequence(Qt::SHIFT | Qt::Key_F)); 0518 QObject::connect(mForwardActionMenu, SIGNAL(triggered(bool)), mParent, SLOT(slotForwardInlineMsg())); 0519 } else { 0520 mForwardActionMenu->insertAction(mRedirectAction, mForwardAttachedAction); 0521 mForwardActionMenu->insertAction(mRedirectAction, mForwardInlineAction); 0522 ac->setDefaultShortcut(mForwardInlineAction, QKeySequence(Qt::Key_F)); 0523 ac->setDefaultShortcut(mForwardAttachedAction, QKeySequence(Qt::SHIFT | Qt::Key_F)); 0524 QObject::connect(mForwardActionMenu, SIGNAL(triggered(bool)), mParent, SLOT(slotForwardAttachedMessage())); 0525 } 0526 } 0527 0528 void MessageActions::setupForwardingActionsList(KXMLGUIClient *guiClient) 0529 { 0530 QList<QAction *> forwardActionList; 0531 guiClient->unplugActionList(QStringLiteral("forward_action_list")); 0532 if (KMailSettings::self()->forwardingInlineByDefault()) { 0533 forwardActionList.append(mForwardInlineAction); 0534 forwardActionList.append(mForwardAttachedAction); 0535 } else { 0536 forwardActionList.append(mForwardAttachedAction); 0537 forwardActionList.append(mForwardInlineAction); 0538 } 0539 forwardActionList.append(mRedirectAction); 0540 guiClient->plugActionList(QStringLiteral("forward_action_list"), forwardActionList); 0541 } 0542 0543 void MessageActions::slotReplyToMsg() 0544 { 0545 replyCommand(MessageComposer::ReplySmart); 0546 } 0547 0548 void MessageActions::slotReplyAuthorToMsg() 0549 { 0550 replyCommand(MessageComposer::ReplyAuthor); 0551 } 0552 0553 void MessageActions::slotReplyListToMsg() 0554 { 0555 replyCommand(MessageComposer::ReplyList); 0556 } 0557 0558 void MessageActions::slotReplyAllToMsg() 0559 { 0560 replyCommand(MessageComposer::ReplyAll); 0561 } 0562 0563 void MessageActions::slotNoQuoteReplyToMsg() 0564 { 0565 if (!mCurrentItem.hasPayload<KMime::Message::Ptr>()) { 0566 return; 0567 } 0568 auto command = new KMReplyCommand(mParent, mCurrentItem, MessageComposer::ReplySmart, QString(), true); 0569 command->setReplyAsHtml(mMessageView ? mMessageView->viewer()->htmlMail() : false); 0570 0571 command->start(); 0572 } 0573 0574 void MessageActions::slotRunUrl(QAction *urlAction) 0575 { 0576 const QVariant q = urlAction->data(); 0577 if (q.userType() == QMetaType::QUrl) { 0578 auto job = new KIO::OpenUrlJob(q.toUrl()); 0579 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, mParent)); 0580 job->start(); 0581 } 0582 } 0583 0584 void MessageActions::slotMailingListFilter() 0585 { 0586 if (!mCurrentItem.hasPayload<KMime::Message::Ptr>()) { 0587 return; 0588 } 0589 0590 KMCommand *command = new KMMailingListFilterCommand(mParent, mCurrentItem); 0591 command->start(); 0592 } 0593 0594 void MessageActions::printMessage(bool preview) 0595 { 0596 if (mMessageView) { 0597 bool result = false; 0598 if (MessageViewer::MessageViewerSettings::self()->printSelectedText()) { 0599 result = mMessageView->printSelectedText(preview); 0600 } 0601 if (!result) { 0602 const bool useFixedFont = MessageViewer::MessageViewerSettings::self()->useFixedFont(); 0603 const QString overrideEncoding = MessageCore::MessageCoreSettings::self()->overrideCharacterEncoding(); 0604 0605 const Akonadi::Item message = mCurrentItem; 0606 KMPrintCommandInfo commandInfo; 0607 commandInfo.mMsg = message; 0608 commandInfo.mHeaderStylePlugin = mMessageView->viewer()->headerStylePlugin(); 0609 commandInfo.mFormat = mMessageView->viewer()->displayFormatMessageOverwrite(); 0610 commandInfo.mHtmlLoadExtOverride = mMessageView->viewer()->htmlLoadExternal(); 0611 commandInfo.mPrintPreview = preview; 0612 commandInfo.mUseFixedFont = useFixedFont; 0613 commandInfo.mOverrideFont = overrideEncoding; 0614 commandInfo.mShowSignatureDetails = 0615 mMessageView->viewer()->showSignatureDetails() || MessageViewer::MessageViewerSettings::self()->alwaysShowEncryptionSignatureDetails(); 0616 commandInfo.mShowEncryptionDetails = 0617 mMessageView->viewer()->showEncryptionDetails() || MessageViewer::MessageViewerSettings::self()->alwaysShowEncryptionSignatureDetails(); 0618 0619 auto command = new KMPrintCommand(mParent, commandInfo); 0620 command->start(); 0621 } 0622 } else { 0623 qCWarning(KMAIL_LOG) << "MessageActions::printMessage impossible to do it if we don't have a viewer"; 0624 } 0625 } 0626 0627 void MessageActions::slotPrintPreviewMsg() 0628 { 0629 printMessage(true); 0630 } 0631 0632 void MessageActions::slotPrintMessage() 0633 { 0634 printMessage(false); 0635 } 0636 0637 /** 0638 * This adds a list of actions to mMailingListActionMenu mapping the identifier item to 0639 * the url. 0640 * 0641 * e.g.: item = "Contact Owner" 0642 * "Contact Owner (email)" -> KRun( "mailto:bob@arthouseflowers.example.com" ) 0643 * "Contact Owner (web)" -> KRun( "http://arthouseflowers.example.com/contact-owner.php" ) 0644 */ 0645 void MessageActions::addMailingListActions(const QString &item, const QList<QUrl> &list) 0646 { 0647 for (const QUrl &url : list) { 0648 addMailingListAction(item, url); 0649 } 0650 } 0651 0652 /** 0653 * This adds a action to mMailingListActionMenu mapping the identifier item to 0654 * the url. See addMailingListActions above. 0655 */ 0656 void MessageActions::addMailingListAction(const QString &item, const QUrl &url) 0657 { 0658 QString protocol = url.scheme().toLower(); 0659 QString prettyUrl = url.toDisplayString(); 0660 if (protocol == QLatin1StringView("mailto")) { 0661 protocol = i18n("email"); 0662 prettyUrl.remove(0, 7); // length( "mailto:" ) 0663 } else if (protocol.startsWith(QLatin1StringView("http"))) { 0664 protocol = i18n("web"); 0665 } 0666 // item is a mailing list url description passed from the updateActions method above. 0667 auto act = 0668 new QAction(i18nc("%1 is a 'Contact Owner' or similar action. %2 is a protocol normally web or email though could be irc/ftp or other url variant", 0669 "%1 (%2)", 0670 item, 0671 protocol), 0672 this); 0673 mMailListActionList.append(act); 0674 const QVariant v(url); 0675 act->setData(v); 0676 KMail::Util::addQActionHelpText(act, prettyUrl); 0677 mMailingListActionMenu->addAction(act); 0678 } 0679 0680 void MessageActions::editCurrentMessage() 0681 { 0682 KMCommand *command = nullptr; 0683 if (mCurrentItem.isValid()) { 0684 Akonadi::Collection col = mCurrentItem.parentCollection(); 0685 qCDebug(KMAIL_LOG) << " mCurrentItem.parentCollection()" << mCurrentItem.parentCollection(); 0686 // edit, unlike send again, removes the message from the folder 0687 // we only want that for templates and drafts folders 0688 if (col.isValid() && (CommonKernel->folderIsDraftOrOutbox(col) || CommonKernel->folderIsTemplates(col))) { 0689 command = new KMEditItemCommand(mParent, mCurrentItem, true); 0690 } else { 0691 command = new KMEditItemCommand(mParent, mCurrentItem, false); 0692 } 0693 command->start(); 0694 } else if (mCurrentItem.hasPayload<KMime::Message::Ptr>()) { 0695 command = new KMEditMessageCommand(mParent, mCurrentItem.payload<KMime::Message::Ptr>()); 0696 command->start(); 0697 } 0698 } 0699 0700 void MessageActions::annotateMessage() 0701 { 0702 if (!mCurrentItem.isValid()) { 0703 return; 0704 } 0705 0706 auto dialog = new PimCommon::AnnotationEditDialog(mCurrentItem, mParent); 0707 dialog->exec(); 0708 delete dialog; 0709 } 0710 0711 void MessageActions::addWebShortcutsMenu(QMenu *menu, const QString &text) 0712 { 0713 mWebShortcutMenuManager->setSelectedText(text); 0714 mWebShortcutMenuManager->addWebShortcutsToMenu(menu); 0715 } 0716 0717 QAction *MessageActions::debugAkonadiSearchAction() const 0718 { 0719 return mDebugAkonadiSearchAction; 0720 } 0721 0722 QAction *MessageActions::addFollowupReminderAction() const 0723 { 0724 return mAddFollowupReminderAction; 0725 } 0726 0727 void MessageActions::slotDebugAkonadiSearch() 0728 { 0729 if (!mCurrentItem.isValid()) { 0730 return; 0731 } 0732 QPointer<Akonadi::Search::AkonadiSearchDebugDialog> dlg = new Akonadi::Search::AkonadiSearchDebugDialog; 0733 dlg->setAkonadiId(mCurrentItem.id()); 0734 dlg->setAttribute(Qt::WA_DeleteOnClose); 0735 dlg->setSearchType(Akonadi::Search::AkonadiSearchDebugSearchPathComboBox::Emails); 0736 dlg->doSearch(); 0737 dlg->show(); 0738 } 0739 0740 void MessageActions::slotResendMessage() 0741 { 0742 // mCurrentItem.isValid() may be false here if message was imported via 'File' -> 'Open...' 0743 KMCommand *command = new KMResendMessageCommand(mParent, mCurrentItem); 0744 command->start(); 0745 } 0746 0747 QAction *MessageActions::newMessageFromTemplateAction() const 0748 { 0749 return mNewMessageFromTemplateAction; 0750 } 0751 0752 QAction *MessageActions::sendAgainAction() const 0753 { 0754 return mSendAgainAction; 0755 } 0756 0757 void MessageActions::slotAddFollowupReminder() 0758 { 0759 if (!mCurrentItem.isValid()) { 0760 return; 0761 } 0762 0763 QPointer<MessageComposer::FollowUpReminderSelectDateDialog> dlg = new MessageComposer::FollowUpReminderSelectDateDialog(mParent); 0764 if (dlg->exec()) { 0765 const QDate date = dlg->selectedDate(); 0766 auto job = new CreateFollowupReminderOnExistingMessageJob(this); 0767 job->setDate(date); 0768 job->setCollection(dlg->collection()); 0769 job->setMessageItem(mCurrentItem); 0770 job->start(); 0771 } 0772 delete dlg; 0773 } 0774 0775 void MessageActions::slotExportToPdf() 0776 { 0777 QString fileName = MessageViewer::Util::generateFileNameForExtension(mCurrentItem, QStringLiteral(".pdf")); 0778 fileName = QFileDialog::getSaveFileName(mParent, i18n("Export to PDF"), QDir::homePath() + QLatin1Char('/') + fileName, i18n("PDF document (*.pdf)")); 0779 if (!fileName.isEmpty()) { 0780 mMessageView->viewer()->exportToPdf(fileName); 0781 } 0782 } 0783 0784 void MessageActions::slotArchiveMessage() 0785 { 0786 if (!mCurrentItem.isValid() || !mCurrentItem.parentCollection().isValid()) { 0787 return; 0788 } 0789 Akonadi::Item::List items; 0790 items << mCurrentItem; 0791 auto resource = CommonKernel->collectionFromId(mCurrentItem.parentCollection().id()).resource(); 0792 KMKernel::self()->folderArchiveManager()->setArchiveItems(items, resource); 0793 } 0794 0795 Akonadi::Item MessageActions::currentItem() const 0796 { 0797 return mCurrentItem; 0798 } 0799 0800 QAction *MessageActions::exportToPdfAction() const 0801 { 0802 return mExportToPdfAction; 0803 } 0804 0805 QAction *MessageActions::archiveMessageAction() const 0806 { 0807 return mArchiveMessageAction; 0808 } 0809 0810 #include "moc_messageactions.cpp"