Remove commented code
[kdepim.git] / kmail / src / kmkernel.cpp
blob316e58038881e3f3e74f0d2a1245953c7d484ac8
1 /* */
3 #include "kmkernel.h"
5 #include "settings/kmailsettings.h"
6 #include "libkdepim/broadcaststatus.h"
7 #include <AkonadiSearch/PIM/indexeditems.h>
8 using KPIM::BroadcastStatus;
9 #include "kmstartup.h"
10 #include "kmmainwin.h"
11 #include "editor/composer.h"
12 #include "kmreadermainwin.h"
13 #include "undostack.h"
14 #include "kmreaderwin.h"
15 #include "kmmainwidget.h"
16 #include "search/checkindexingmanager.h"
17 #include "libkdepim/recentaddresses.h"
18 using KPIM::RecentAddresses;
19 #include "configuredialog/configuredialog.h"
20 #include "kmcommands.h"
21 #include "kmsystemtray.h"
22 #include <MessageCore/StringUtil>
23 #include "mailcommon/mailutil.h"
24 #include "pop3settings.h"
25 #include "MailCommon/FolderTreeView"
26 #include "MailCommon/KMFilterDialog"
27 #include "mailcommonsettings_base.h"
28 #include "mailfilteragentinterface.h"
29 #include "PimCommon/PimUtil"
30 #include "folderarchive/folderarchivemanager.h"
31 // kdepim includes
32 #include "kmail-version.h"
34 // kdepimlibs includes
35 #include <KIdentityManagement/kidentitymanagement/identity.h>
36 #include <KIdentityManagement/kidentitymanagement/identitymanager.h>
37 #include <MailTransport/mailtransport/transport.h>
38 #include <MailTransport/mailtransport/transportmanager.h>
39 #include <MailTransport/mailtransport/dispatcherinterface.h>
40 #include <AkonadiCore/servermanager.h>
42 #include <kwindowsystem.h>
43 #include "mailserviceimpl.h"
44 using KMail::MailServiceImpl;
45 #include "mailcommon/jobscheduler.h"
47 #include <MessageCore/MessageCoreSettings>
48 #include "messagelistsettings.h"
49 #include "gravatarsettings.h"
50 #include "messagelist/messagelistutil.h"
51 #include "messageviewer/messageviewersettings.h"
52 #include "MessageComposer/AkonadiSender"
53 #include "messagecomposer/messagecomposersettings.h"
54 #include "MessageComposer/MessageHelper"
55 #include "MessageComposer/MessageComposerSettings"
56 #include "PimCommon/PimCommonSettings"
57 #include "PimCommon/AutoCorrection"
59 #include "TemplateParser/TemplateParser"
60 #include "globalsettings_templateparser.h"
61 #include "TemplateParser/TemplatesUtil"
63 #include "mailcommon/foldercollection.h"
64 #include "editor/codec/codecmanager.h"
66 #include <kmessagebox.h>
67 #include <knotification.h>
68 #include <libkdepim/progressmanager.h>
70 #include <kconfig.h>
71 #include <kpassivepopup.h>
72 #include <kconfiggroup.h>
73 #include "kmail_debug.h"
74 #include <kio/jobuidelegate.h>
75 #include <kprocess.h>
76 #include <KCrash>
78 #include <kmime/kmime_message.h>
79 #include <kmime/kmime_headers.h>
80 #include <AkonadiCore/Collection>
81 #include <AkonadiCore/CollectionFetchJob>
82 #include <AkonadiCore/ChangeRecorder>
83 #include <AkonadiCore/ItemFetchScope>
84 #include <AkonadiCore/AgentManager>
85 #include <AkonadiCore/ItemFetchJob>
86 #include <AkonadiCore/AttributeFactory>
87 #include <AkonadiCore/Session>
88 #include <AkonadiCore/EntityTreeModel>
89 #include <AkonadiCore/entitymimetypefiltermodel.h>
90 #include <AkonadiCore/CollectionStatisticsJob>
92 #include <QNetworkConfigurationManager>
93 #include <QDir>
94 #include <QWidget>
95 #include <QFileInfo>
96 #include <QtDBus/QtDBus>
97 #include <QMimeDatabase>
99 #include <sys/types.h>
100 #include <dirent.h>
101 #include <sys/stat.h>
102 #include <unistd.h>
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <assert.h>
106 #include <MailCommon/ResourceReadConfigFile>
108 #include <kstartupinfo.h>
109 #include <kmailadaptor.h>
110 #include <KLocalizedString>
111 #include <QStandardPaths>
112 #include "kmailinterface.h"
113 #include "mailcommon/foldercollectionmonitor.h"
114 #include "imapresourcesettings.h"
115 #include "util.h"
116 #include "MailCommon/MailKernel"
118 #include "searchdialog/searchdescriptionattribute.h"
119 #include "kmail_options.h"
121 using namespace MailCommon;
123 static KMKernel *mySelf = Q_NULLPTR;
124 static bool s_askingToGoOnline = false;
125 static QNetworkConfigurationManager *s_networkConfigMgr = 0;
126 /********************************************************************/
127 /* Constructor and destructor */
128 /********************************************************************/
129 KMKernel::KMKernel(QObject *parent) :
130 QObject(parent),
131 mIdentityManager(Q_NULLPTR),
132 mConfigureDialog(Q_NULLPTR),
133 mMailService(Q_NULLPTR),
134 mSystemNetworkStatus(true),
135 mSystemTray(Q_NULLPTR),
136 mDebugBaloo(false)
138 mDebugBaloo = !qEnvironmentVariableIsEmpty("KDEPIM_BALOO_DEBUG");
140 if (!s_networkConfigMgr) {
141 s_networkConfigMgr = new QNetworkConfigurationManager(QCoreApplication::instance());
143 mSystemNetworkStatus = s_networkConfigMgr->isOnline();
145 Akonadi::AttributeFactory::registerAttribute<Akonadi::SearchDescriptionAttribute>();
146 QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kmail"));
147 qCDebug(KMAIL_LOG) << "Starting up...";
149 mySelf = this;
150 the_firstInstance = true;
152 the_undoStack = Q_NULLPTR;
153 the_msgSender = Q_NULLPTR;
154 mFilterEditDialog = Q_NULLPTR;
155 mWin = Q_NULLPTR;
156 // make sure that we check for config updates before doing anything else
157 KMKernel::config();
158 // this shares the kmailrc parsing too (via KSharedConfig), and reads values from it
159 // so better do it here, than in some code where changing the group of config()
160 // would be unexpected
161 KMailSettings::self();
163 mJobScheduler = new JobScheduler(this);
164 mXmlGuiInstance = QStringLiteral("kmail2");
166 mAutoCorrection = new PimCommon::AutoCorrection();
167 KMime::setUseOutlookAttachmentEncoding(MessageComposer::MessageComposerSettings::self()->outlookCompatibleAttachments());
169 // cberzan: this crap moved to CodecManager ======================
170 mNetCodec = QTextCodec::codecForLocale();
172 // In the case of Japan. Japanese locale name is "eucjp" but
173 // The Japanese mail systems normally used "iso-2022-jp" of locale name.
174 // We want to change locale name from eucjp to iso-2022-jp at KMail only.
176 // (Introduction to i18n, 6.6 Limit of Locale technology):
177 // EUC-JP is the de-facto standard for UNIX systems, ISO 2022-JP
178 // is the standard for Internet, and Shift-JIS is the encoding
179 // for Windows and Macintosh.
180 if (mNetCodec->name().toLower() == "eucjp"
181 #if defined Q_OS_WIN || defined Q_OS_MACX
182 || netCodec->name().toLower() == "shift-jis" // OK?
183 #endif
185 mNetCodec = QTextCodec::codecForName("jis7");
187 // until here ================================================
189 Akonadi::Session *session = new Akonadi::Session("KMail Kernel ETM", this);
191 mFolderCollectionMonitor = new FolderCollectionMonitor(session, this);
193 connect(mFolderCollectionMonitor->monitor(), &Akonadi::Monitor::collectionRemoved, this, &KMKernel::slotCollectionRemoved);
195 mEntityTreeModel = new Akonadi::EntityTreeModel(folderCollectionMonitor(), this);
196 mEntityTreeModel->setListFilter(Akonadi::CollectionFetchScope::Enabled);
197 mEntityTreeModel->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation);
199 mCollectionModel = new Akonadi::EntityMimeTypeFilterModel(this);
200 mCollectionModel->setSourceModel(mEntityTreeModel);
201 mCollectionModel->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType());
202 mCollectionModel->setHeaderGroup(Akonadi::EntityTreeModel::CollectionTreeHeaders);
203 mCollectionModel->setDynamicSortFilter(true);
204 mCollectionModel->setSortCaseSensitivity(Qt::CaseInsensitive);
206 connect(folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)),
207 SLOT(slotCollectionChanged(Akonadi::Collection,QSet<QByteArray>)));
209 connect(MailTransport::TransportManager::self(), &MailTransport::TransportManager::transportRemoved, this, &KMKernel::transportRemoved);
210 connect(MailTransport::TransportManager::self(), &MailTransport::TransportManager::transportRenamed, this, &KMKernel::transportRenamed);
212 QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/MailDispatcherAgent"), QStringLiteral("org.freedesktop.Akonadi.MailDispatcherAgent"), QStringLiteral("itemDispatchStarted"), this, SLOT(itemDispatchStarted()));
213 connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceStatusChanged, this, &KMKernel::instanceStatusChanged);
215 connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceError, this, &KMKernel::slotInstanceError);
217 connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceWarning, this, &KMKernel::slotInstanceWarning);
219 connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceRemoved, this, &KMKernel::slotInstanceRemoved);
221 connect(s_networkConfigMgr, &QNetworkConfigurationManager::onlineStateChanged,
222 this, &KMKernel::slotSystemNetworkStatusChanged);
224 connect(KPIM::ProgressManager::instance(), &KPIM::ProgressManager::progressItemCompleted,
225 this, &KMKernel::slotProgressItemCompletedOrCanceled);
226 connect(KPIM::ProgressManager::instance(), &KPIM::ProgressManager::progressItemCanceled,
227 this, &KMKernel::slotProgressItemCompletedOrCanceled);
228 connect(identityManager(), &KIdentityManagement::IdentityManager::deleted, this, &KMKernel::slotDeleteIdentity);
229 CommonKernel->registerKernelIf(this);
230 CommonKernel->registerSettingsIf(this);
231 CommonKernel->registerFilterIf(this);
232 mFolderArchiveManager = new FolderArchiveManager(this);
233 mIndexedItems = new Akonadi::Search::PIM::IndexedItems(this);
234 mCheckIndexingManager = new CheckIndexingManager(mIndexedItems, this);
237 KMKernel::~KMKernel()
239 delete mMailService;
240 mMailService = Q_NULLPTR;
242 mSystemTray = Q_NULLPTR;
244 stopAgentInstance();
245 slotSyncConfig();
247 delete mAutoCorrection;
248 mySelf = Q_NULLPTR;
251 Akonadi::ChangeRecorder *KMKernel::folderCollectionMonitor() const
253 return mFolderCollectionMonitor->monitor();
256 Akonadi::EntityTreeModel *KMKernel::entityTreeModel() const
258 return mEntityTreeModel;
261 Akonadi::EntityMimeTypeFilterModel *KMKernel::collectionModel() const
263 return mCollectionModel;
266 void KMKernel::setupDBus()
268 (void) new KmailAdaptor(this);
269 QDBusConnection::sessionBus().registerObject(QStringLiteral("/KMail"), this);
270 mMailService = new MailServiceImpl();
273 static QUrl makeAbsoluteUrl(const QString &str, const QString &cwd)
275 return QUrl::fromUserInput(str, cwd, QUrl::AssumeLocalFile);
278 bool KMKernel::handleCommandLine(bool noArgsOpensReader, const QStringList &args, const QString &workingDir)
280 QString to, cc, bcc, subj, body, inReplyTo, replyTo;
281 QStringList customHeaders;
282 QUrl messageFile;
283 QList<QUrl> attachURLs;
284 bool mailto = false;
285 bool checkMail = false;
286 bool viewOnly = false;
287 bool calledWithSession = false; // for ignoring '-session foo'
289 // process args:
290 QCommandLineParser parser;
291 kmail_options(&parser);
292 parser.process(args);
293 if (parser.isSet(QStringLiteral("subject"))) {
294 subj = parser.value(QStringLiteral("subject"));
295 // if kmail is called with 'kmail -session abc' then this doesn't mean
296 // that the user wants to send a message with subject "ession" but
297 // (most likely) that the user clicked on KMail's system tray applet
298 // which results in KMKernel::raise() calling "kmail kmail newInstance"
299 // via D-Bus which apparently executes the application with the original
300 // command line arguments and those include "-session ..." if
301 // kmail/kontact was restored by session management
302 if (subj == QLatin1String("ession")) {
303 subj.clear();
304 calledWithSession = true;
305 } else {
306 mailto = true;
310 if (parser.isSet(QStringLiteral("cc"))) {
311 mailto = true;
312 cc = parser.value(QStringLiteral("cc"));
315 if (parser.isSet(QStringLiteral("bcc"))) {
316 mailto = true;
317 bcc = parser.value(QStringLiteral("bcc"));
320 if (parser.isSet(QStringLiteral("replyTo"))) {
321 mailto = true;
322 replyTo = parser.value(QStringLiteral("replyTo"));
325 if (parser.isSet(QStringLiteral("msg"))) {
326 mailto = true;
327 const QString file = parser.value(QStringLiteral("msg"));
328 messageFile = makeAbsoluteUrl(file, workingDir);
331 if (parser.isSet(QStringLiteral("body"))) {
332 mailto = true;
333 body = parser.value(QStringLiteral("body"));
336 const QStringList attachList = parser.values(QStringLiteral("attach"));
337 if (!attachList.isEmpty()) {
338 mailto = true;
339 QStringList::ConstIterator end = attachList.constEnd();
340 for (QStringList::ConstIterator it = attachList.constBegin();
341 it != end; ++it) {
342 if (!(*it).isEmpty()) {
343 if ((*it) != QLatin1String("--")) {
344 attachURLs.append(makeAbsoluteUrl(*it, workingDir));
350 customHeaders = parser.values(QStringLiteral("header"));
352 if (parser.isSet(QStringLiteral("composer"))) {
353 mailto = true;
356 if (parser.isSet(QStringLiteral("check"))) {
357 checkMail = true;
360 if (parser.isSet(QStringLiteral("view"))) {
361 viewOnly = true;
362 const QString filename =
363 parser.value(QStringLiteral("view"));
364 messageFile = QUrl::fromLocalFile(filename);
365 if (!messageFile.isValid()) {
366 messageFile = QUrl();
367 messageFile.setPath(filename);
371 if (!calledWithSession) {
372 // only read additional command line arguments if kmail/kontact is
373 // not called with "-session foo"
374 for (const QString &arg : parser.positionalArguments()) {
375 if (arg.startsWith(QStringLiteral("mailto:"), Qt::CaseInsensitive)) {
376 const QUrl urlDecoded(QUrl::fromPercentEncoding(arg.toUtf8()));
377 QMap<QString, QString> values = MessageCore::StringUtil::parseMailtoUrl(urlDecoded);
378 if (!values.value(QStringLiteral("to")).isEmpty()) {
379 to += values.value(QStringLiteral("to")) + QStringLiteral(", ");
381 if (!values.value(QStringLiteral("cc")).isEmpty()) {
382 cc += values.value(QStringLiteral("cc")) + QStringLiteral(", ");
384 if (!values.value(QStringLiteral("bcc")).isEmpty()) {
385 bcc += values.value(QStringLiteral("bcc")) + QStringLiteral(", ");
387 if (!values.value(QStringLiteral("subject")).isEmpty()) {
388 subj = values.value(QStringLiteral("subject"));
390 if (!values.value(QStringLiteral("body")).isEmpty()) {
391 body = values.value(QStringLiteral("body"));
393 if (!values.value(QStringLiteral("in-reply-to")).isEmpty()) {
394 inReplyTo = values.value(QStringLiteral("in-reply-to"));
396 QString attach = values.value(QStringLiteral("attachment"));
397 if (!attach.isEmpty()) {
398 attachURLs << makeAbsoluteUrl(attach, workingDir);
400 attach = values.value(QStringLiteral("attach"));
401 if (!attach.isEmpty()) {
402 attachURLs << makeAbsoluteUrl(attach, workingDir);
405 } else {
406 QUrl url(arg);
407 if (url.isValid() && !url.scheme().isEmpty()) {
408 attachURLs += url;
409 } else {
410 to += arg + QStringLiteral(", ");
413 mailto = true;
415 if (!to.isEmpty()) {
416 // cut off the superfluous trailing ", "
417 to.truncate(to.length() - 2);
421 if (!noArgsOpensReader && !mailto && !checkMail && !viewOnly) {
422 return false;
425 if (viewOnly) {
426 viewMessage(messageFile);
427 } else
428 action(mailto, checkMail, to, cc, bcc, subj, body, messageFile,
429 attachURLs, customHeaders, replyTo, inReplyTo);
430 return true;
433 /********************************************************************/
434 /* D-Bus-callable, and command line actions */
435 /********************************************************************/
436 void KMKernel::checkMail() //might create a new reader but won't show!!
438 if (!kmkernel->askToGoOnline()) {
439 return;
442 const QString resourceGroupPattern(QStringLiteral("Resource %1"));
444 const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
445 foreach (Akonadi::AgentInstance type, lst) {
446 const QString id = type.identifier();
447 KConfigGroup group(KMKernel::config(), resourceGroupPattern.arg(id));
448 if (group.readEntry("IncludeInManualChecks", true)) {
449 if (!type.isOnline()) {
450 type.setIsOnline(true);
452 if (mResourcesBeingChecked.isEmpty()) {
453 qCDebug(KMAIL_LOG) << "Starting manual mail check";
454 Q_EMIT startCheckMail();
457 if (!mResourcesBeingChecked.contains(id)) {
458 mResourcesBeingChecked.append(id);
460 type.synchronize();
465 void KMKernel::openReader()
467 openReader(false);
470 void KMKernel::setSystrayIconNotificationsEnabled(bool enabled)
472 if (mSystemTray) {
473 mSystemTray->setSystrayIconNotificationsEnabled(enabled);
477 QStringList KMKernel::accounts()
479 QStringList accountLst;
480 const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
481 accountLst.reserve(lst.count());
482 foreach (const Akonadi::AgentInstance &type, lst) {
483 // Explicitly make a copy, as we're not changing values of the list but only
484 // the local copy which is passed to action.
485 accountLst << type.identifier();
487 return accountLst;
490 void KMKernel::checkAccount(const QString &account) //might create a new reader but won't show!!
492 if (account.isEmpty()) {
493 checkMail();
494 } else {
495 Akonadi::AgentInstance agent = Akonadi::AgentManager::self()->instance(account);
496 if (agent.isValid()) {
497 agent.synchronize();
498 } else {
499 qCDebug(KMAIL_LOG) << "- account with name '" << account << "' not found";
504 void KMKernel::openReader(bool onlyCheck)
506 mWin = Q_NULLPTR;
507 KMainWindow *ktmw = Q_NULLPTR;
509 foreach (KMainWindow *window, KMainWindow::memberList()) {
510 if (::qobject_cast<KMMainWin *>(window)) {
511 ktmw = window;
512 break;
516 bool activate;
517 if (ktmw) {
518 mWin = static_cast<KMMainWin *>(ktmw);
519 activate = !onlyCheck; // existing window: only activate if not --check
520 if (activate) {
521 mWin->show();
523 } else {
524 mWin = new KMMainWin;
525 mWin->show();
526 activate = false; // new window: no explicit activation (#73591)
529 if (activate) {
530 // Activate window - doing this instead of KWindowSystem::activateWindow(mWin->winId());
531 // so that it also works when called from KMailApplication::newInstance()
532 #if defined Q_OS_X11 && ! defined K_WS_QTONLY
533 KStartupInfo::setNewStartupId(mWin, KStartupInfo::startupId());
534 #endif
538 int KMKernel::openComposer(const QString &to, const QString &cc,
539 const QString &bcc, const QString &subject,
540 const QString &body, bool hidden,
541 const QString &messageFile,
542 const QStringList &attachmentPaths,
543 const QStringList &customHeaders,
544 const QString &replyTo, const QString &inReplyTo)
546 KMail::Composer::TemplateContext context = KMail::Composer::New;
547 KMime::Message::Ptr msg(new KMime::Message);
548 MessageHelper::initHeader(msg, identityManager());
549 msg->contentType()->setCharset("utf-8");
550 if (!to.isEmpty()) {
551 msg->to()->fromUnicodeString(to, "utf-8");
554 if (!cc.isEmpty()) {
555 msg->cc()->fromUnicodeString(cc, "utf-8");
558 if (!bcc.isEmpty()) {
559 msg->bcc()->fromUnicodeString(bcc, "utf-8");
562 if (!subject.isEmpty()) {
563 msg->subject()->fromUnicodeString(subject, "utf-8");
566 if (!messageFile.isEmpty() && QFile::exists(messageFile)) {
567 QFile f(messageFile);
568 QByteArray str;
569 if (!f.open(QIODevice::ReadOnly)) {
570 qCWarning(KMAIL_LOG) << "Failed to load message: " << f.errorString();
571 } else {
572 str = f.readAll();
573 f.close();
575 if (!str.isEmpty()) {
576 context = KMail::Composer::NoTemplate;
577 msg->setBody(QString::fromLocal8Bit(str.data(), str.size()).toUtf8());
578 } else {
579 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
580 parser.setIdentityManager(KMKernel::self()->identityManager());
581 parser.process(msg);
583 } else if (!body.isEmpty()) {
584 context = KMail::Composer::NoTemplate;
585 msg->setBody(body.toUtf8());
586 } else {
587 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
588 parser.setIdentityManager(KMKernel::self()->identityManager());
589 parser.process(msg);
592 if (!inReplyTo.isEmpty()) {
593 KMime::Headers::InReplyTo *header = new KMime::Headers::InReplyTo;
594 header->fromUnicodeString(inReplyTo, "utf-8");
595 msg->setHeader(header);
598 msg->assemble();
599 KMail::Composer *cWin = KMail::makeComposer(msg, false, false, context);
600 if (!to.isEmpty()) {
601 cWin->setFocusToSubject();
603 QList<QUrl> attachURLs = QUrl::fromStringList(attachmentPaths);
604 QList<QUrl>::ConstIterator endAttachment(attachURLs.constEnd());
605 for (QList<QUrl>::ConstIterator it = attachURLs.constBegin(); it != endAttachment; ++it) {
606 QMimeDatabase mimeDb;
607 if (mimeDb.mimeTypeForUrl(*it).name() == QLatin1String("inode/directory")) {
608 if (KMessageBox::questionYesNo(Q_NULLPTR, i18n("Do you want to attach this folder \"%1\"?", (*it).toDisplayString()), i18n("Attach Folder")) == KMessageBox::No) {
609 continue;
612 cWin->addAttachment((*it), QString());
614 if (!replyTo.isEmpty()) {
615 cWin->setCurrentReplyTo(replyTo);
618 if (!customHeaders.isEmpty()) {
619 QMap<QByteArray, QString> extraCustomHeaders;
620 QStringList::ConstIterator end = customHeaders.constEnd();
621 for (QStringList::ConstIterator it = customHeaders.constBegin(); it != end; ++it) {
622 if (!(*it).isEmpty()) {
623 const int pos = (*it).indexOf(QLatin1Char(':'));
624 if (pos > 0) {
625 const QString header = (*it).left(pos).trimmed();
626 const QString value = (*it).mid(pos + 1).trimmed();
627 if (!header.isEmpty() && !value.isEmpty()) {
628 extraCustomHeaders.insert(header.toUtf8(), value);
633 if (!extraCustomHeaders.isEmpty()) {
634 cWin->addExtraCustomHeaders(extraCustomHeaders);
637 if (!hidden) {
638 cWin->show();
639 // Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
640 // so that it also works when called from KMailApplication::newInstance()
641 #if defined Q_OS_X11 && ! defined K_WS_QTONLY
642 KStartupInfo::setNewStartupId(cWin, KStartupInfo::startupId());
643 #endif
645 return 1;
648 int KMKernel::openComposer(const QString &to, const QString &cc,
649 const QString &bcc, const QString &subject,
650 const QString &body, bool hidden,
651 const QString &attachName,
652 const QByteArray &attachCte,
653 const QByteArray &attachData,
654 const QByteArray &attachType,
655 const QByteArray &attachSubType,
656 const QByteArray &attachParamAttr,
657 const QString &attachParamValue,
658 const QByteArray &attachContDisp,
659 const QByteArray &attachCharset,
660 unsigned int identity)
662 KMail::Composer *cWin;
663 bool iCalAutoSend = fillComposer(cWin, to, cc, bcc,
664 subject, body,
665 attachName, attachCte, attachData,
666 attachType, attachSubType, attachParamAttr, attachParamValue,
667 attachContDisp, attachCharset, identity);
669 if (!hidden && !iCalAutoSend) {
670 cWin->show();
671 // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
672 // so that it also works when called from KMailApplication::newInstance()
673 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
674 KStartupInfo::setNewStartupId(cWin, KStartupInfo::startupId());
675 #endif
676 } else {
678 // Always disable word wrap when we don't show the composer, since otherwise QTextEdit
679 // gets the widget size wrong and wraps much too early.
680 cWin->disableWordWrap();
681 cWin->slotSendNow();
683 return 1;
686 int KMKernel::openComposer(const QString &to, const QString &cc,
687 const QString &bcc, const QString &subject,
688 const QString &body,
689 const QString &attachName,
690 const QByteArray &attachCte,
691 const QByteArray &attachData,
692 const QByteArray &attachType,
693 const QByteArray &attachSubType,
694 const QByteArray &attachParamAttr,
695 const QString &attachParamValue,
696 const QByteArray &attachContDisp,
697 const QByteArray &attachCharset,
698 unsigned int identity)
700 KMail::Composer *cWin;
701 fillComposer(cWin, to, cc, bcc,
702 subject, body,
703 attachName, attachCte, attachData,
704 attachType, attachSubType, attachParamAttr, attachParamValue,
705 attachContDisp, attachCharset, identity);
706 cWin->show();
707 // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
708 // so that it also works when called from KMailApplication::newInstance()
709 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
710 KStartupInfo::setNewStartupId(cWin, KStartupInfo::startupId());
711 #endif
713 return 1;
716 bool KMKernel::fillComposer(KMail::Composer *&cWin,
717 const QString &to, const QString &cc,
718 const QString &bcc, const QString &subject,
719 const QString &body,
720 const QString &attachName,
721 const QByteArray &attachCte,
722 const QByteArray &attachData,
723 const QByteArray &attachType,
724 const QByteArray &attachSubType,
725 const QByteArray &attachParamAttr,
726 const QString &attachParamValue,
727 const QByteArray &attachContDisp,
728 const QByteArray &attachCharset,
729 unsigned int identity)
731 KMail::Composer::TemplateContext context = KMail::Composer::New;
732 KMime::Message::Ptr msg(new KMime::Message);
733 KMime::Content *msgPart = Q_NULLPTR;
734 MessageHelper::initHeader(msg, identityManager());
735 msg->contentType()->setCharset("utf-8");
736 if (!cc.isEmpty()) {
737 msg->cc()->fromUnicodeString(cc, "utf-8");
739 if (!bcc.isEmpty()) {
740 msg->bcc()->fromUnicodeString(bcc, "utf-8");
742 if (!subject.isEmpty()) {
743 msg->subject()->fromUnicodeString(subject, "utf-8");
745 if (!to.isEmpty()) {
746 msg->to()->fromUnicodeString(to, "utf-8");
748 if (identity > 0) {
749 KMime::Headers::Generic *h = new KMime::Headers::Generic("X-KMail-Identity");
750 h->from7BitString(QByteArray::number(identity));
751 msg->setHeader(h);
753 if (!body.isEmpty()) {
754 msg->setBody(body.toUtf8());
755 } else {
756 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
757 parser.setIdentityManager(KMKernel::self()->identityManager());
758 parser.process(KMime::Message::Ptr());
761 bool iCalAutoSend = false;
762 bool noWordWrap = false;
763 bool isICalInvitation = false;
764 if (!attachData.isEmpty()) {
765 isICalInvitation = (attachName == QLatin1String("cal.ics")) &&
766 attachType == "text" &&
767 attachSubType == "calendar" &&
768 attachParamAttr == "method";
769 // Remove BCC from identity on ical invitations (https://intevation.de/roundup/kolab/issue474)
770 if (isICalInvitation && bcc.isEmpty()) {
771 msg->removeHeader<KMime::Headers::Bcc>();
773 if (isICalInvitation &&
774 MessageViewer::MessageViewerSettings::self()->legacyBodyInvites()) {
775 // KOrganizer invitation caught and to be sent as body instead
776 msg->setBody(attachData);
777 msg->contentType()->from7BitString(
778 QStringLiteral("text/calendar; method=%1; "
779 "charset=\"utf-8\"").
780 arg(attachParamValue).toLatin1());
782 iCalAutoSend = true; // no point in editing raw ICAL
783 noWordWrap = true; // we shant word wrap inline invitations
784 } else {
785 // Just do what we're told to do
786 msgPart = new KMime::Content;
787 msgPart->contentTransferEncoding()->fromUnicodeString(QLatin1String(attachCte), "utf-8");
788 msgPart->setBody(attachData); //TODO: check if was setBodyEncoded
789 msgPart->contentType()->setMimeType(attachType + '/' + attachSubType);
790 msgPart->contentType()->setParameter(QLatin1String(attachParamAttr), attachParamValue); //TODO: Check if the content disposition parameter needs to be set!
791 if (! MessageViewer::MessageViewerSettings::self()->exchangeCompatibleInvitations()) {
792 msgPart->contentDisposition()->fromUnicodeString(QLatin1String(attachContDisp), "utf-8");
794 if (!attachCharset.isEmpty()) {
795 // qCDebug(KMAIL_LOG) << "Set attachCharset to" << attachCharset;
796 msgPart->contentType()->setCharset(attachCharset);
799 msgPart->contentType()->setName(attachName, "utf-8");
800 msgPart->assemble();
801 // Don't show the composer window if the automatic sending is checked
802 iCalAutoSend = MessageViewer::MessageViewerSettings::self()->automaticSending();
806 msg->assemble();
808 if (!msg->body().isEmpty()) {
809 context = KMail::Composer::NoTemplate;
812 cWin = KMail::makeComposer(KMime::Message::Ptr(), false, false, context);
813 cWin->setMessage(msg, false, false, !isICalInvitation /* mayAutoSign */);
814 cWin->setSigningAndEncryptionDisabled(isICalInvitation
815 && MessageViewer::MessageViewerSettings::self()->legacyBodyInvites());
816 if (noWordWrap) {
817 cWin->disableWordWrap();
819 if (msgPart) {
820 cWin->addAttach(msgPart);
822 if (isICalInvitation) {
823 cWin->disableWordWrap();
824 cWin->forceDisableHtml();
825 cWin->disableForgottenAttachmentsCheck();
827 return iCalAutoSend;
830 QDBusObjectPath KMKernel::openComposer(const QString &to, const QString &cc,
831 const QString &bcc,
832 const QString &subject,
833 const QString &body, bool hidden)
835 KMime::Message::Ptr msg(new KMime::Message);
836 MessageHelper::initHeader(msg, identityManager());
837 msg->contentType()->setCharset("utf-8");
838 if (!cc.isEmpty()) {
839 msg->cc()->fromUnicodeString(cc, "utf-8");
841 if (!bcc.isEmpty()) {
842 msg->bcc()->fromUnicodeString(bcc, "utf-8");
844 if (!subject.isEmpty()) {
845 msg->subject()->fromUnicodeString(subject, "utf-8");
847 if (!to.isEmpty()) {
848 msg->to()->fromUnicodeString(to, "utf-8");
850 if (!body.isEmpty()) {
851 msg->setBody(body.toUtf8());
852 } else {
853 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
854 parser.setIdentityManager(KMKernel::self()->identityManager());
855 parser.process(KMime::Message::Ptr());
858 msg->assemble();
859 const KMail::Composer::TemplateContext context = body.isEmpty() ? KMail::Composer::New :
860 KMail::Composer::NoTemplate;
861 KMail::Composer *cWin = KMail::makeComposer(msg, false, false, context);
862 if (!hidden) {
863 cWin->show();
864 // Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
865 // so that it also works when called from KMailApplication::newInstance()
866 #if defined Q_OS_X11 && ! defined K_WS_QTONLY
867 KStartupInfo::setNewStartupId(cWin, KStartupInfo::startupId());
868 #endif
869 } else {
870 // Always disable word wrap when we don't show the composer; otherwise,
871 // QTextEdit gets the widget size wrong and wraps much too early.
872 cWin->disableWordWrap();
873 cWin->slotSendNow();
876 return QDBusObjectPath(cWin->dbusObjectPath());
879 QDBusObjectPath KMKernel::newMessage(const QString &to,
880 const QString &cc,
881 const QString &bcc,
882 bool hidden,
883 bool useFolderId,
884 const QString & /*messageFile*/,
885 const QString &_attachURL)
887 QUrl attachURL = QUrl::fromLocalFile(_attachURL);
888 KMime::Message::Ptr msg(new KMime::Message);
889 QSharedPointer<FolderCollection> folder;
890 uint id = 0;
892 if (useFolderId) {
893 //create message with required folder identity
894 folder = currentFolderCollection();
895 id = folder ? folder->identity() : 0;
897 MessageHelper::initHeader(msg, identityManager(), id);
898 msg->contentType()->setCharset("utf-8");
899 //set basic headers
900 if (!cc.isEmpty()) {
901 msg->cc()->fromUnicodeString(cc, "utf-8");
903 if (!bcc.isEmpty()) {
904 msg->bcc()->fromUnicodeString(bcc, "utf-8");
906 if (!to.isEmpty()) {
907 msg->to()->fromUnicodeString(to, "utf-8");
910 msg->assemble();
911 TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
912 parser.setIdentityManager(identityManager());
913 Akonadi::Collection col = folder ? folder->collection() : Akonadi::Collection();
914 parser.process(msg, col);
916 KMail::Composer *win = makeComposer(msg, false, false, KMail::Composer::New, id);
918 win->setCollectionForNewMessage(col);
919 //Add the attachment if we have one
920 if (!attachURL.isEmpty() && attachURL.isValid()) {
921 win->addAttachment(attachURL, QString());
924 //only show window when required
925 if (!hidden) {
926 win->show();
928 return QDBusObjectPath(win->dbusObjectPath());
931 void KMKernel::viewMessage(const QUrl &url)
933 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand(Q_NULLPTR, url);
935 openCommand->start();
938 int KMKernel::viewMessage(const QString &messageFile)
940 KMOpenMsgCommand *openCommand = new KMOpenMsgCommand(Q_NULLPTR, QUrl::fromLocalFile(messageFile));
942 openCommand->start();
943 return 1;
946 void KMKernel::raise()
948 QDBusInterface iface(QStringLiteral("org.kde.kmail"), QStringLiteral("/MainApplication"),
949 QStringLiteral("org.kde.PIMUniqueApplication"),
950 QDBusConnection::sessionBus());
951 QDBusReply<int> reply;
952 if (!iface.isValid() || !(reply = iface.call(QStringLiteral("newInstance"))).isValid()) {
953 QDBusError err = iface.lastError();
954 qCritical() << "Communication problem with KMail. "
955 << "Error message was:" << err.name() << ": \"" << err.message() << "\"";
960 bool KMKernel::showMail(qint64 serialNumber)
962 KMMainWidget *mainWidget = Q_NULLPTR;
964 // First look for a KMainWindow.
965 foreach (KMainWindow *window, KMainWindow::memberList()) {
966 // Then look for a KMMainWidget.
967 QList<KMMainWidget *> l = window->findChildren<KMMainWidget *>();
968 if (!l.isEmpty() && l.first()) {
969 mainWidget = l.first();
970 if (window->isActiveWindow()) {
971 break;
975 if (mainWidget) {
976 Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(Akonadi::Item(serialNumber), this);
977 job->fetchScope().fetchFullPayload();
978 if (job->exec()) {
979 if (job->items().count() >= 1) {
980 KMReaderMainWin *win = new KMReaderMainWin(MessageViewer::Viewer::UseGlobalSetting, false);
981 win->showMessage(MessageCore::MessageCoreSettings::self()->overrideCharacterEncoding(),
982 job->items().at(0));
983 win->show();
984 return true;
988 return false;
991 void KMKernel::pauseBackgroundJobs()
993 mBackgroundTasksTimer->stop();
994 mJobScheduler->pause();
997 void KMKernel::resumeBackgroundJobs()
999 mJobScheduler->resume();
1000 mBackgroundTasksTimer->start(4 * 60 * 60 * 1000);
1003 void KMKernel::stopNetworkJobs()
1005 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Offline) {
1006 return;
1009 setAccountStatus(false);
1011 KMailSettings::setNetworkState(KMailSettings::EnumNetworkState::Offline);
1012 BroadcastStatus::instance()->setStatusMsg(i18n("KMail is set to be offline; all network jobs are suspended"));
1013 Q_EMIT onlineStatusChanged((KMailSettings::EnumNetworkState::type)KMailSettings::networkState());
1017 void KMKernel::setAccountStatus(bool goOnline)
1019 const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances(false);
1020 foreach (Akonadi::AgentInstance type, lst) {
1021 const QString identifier(type.identifier());
1022 if (PimCommon::Util::isImapResource(identifier) ||
1023 identifier.contains(POP3_RESOURCE_IDENTIFIER) ||
1024 identifier.contains(QStringLiteral("akonadi_maildispatcher_agent")) ||
1025 type.type().capabilities().contains(QStringLiteral("NeedsNetwork"))) {
1026 type.setIsOnline(goOnline);
1029 if (goOnline && MessageComposer::MessageComposerSettings::self()->sendImmediate()) {
1030 const qint64 nbMsgOutboxCollection = MailCommon::Util::updatedCollection(CommonKernel->outboxCollectionFolder()).statistics().count();
1031 if (nbMsgOutboxCollection > 0) {
1032 kmkernel->msgSender()->sendQueued();
1037 const QString KMKernel::xmlGuiInstanceName() const
1039 return mXmlGuiInstance;
1042 void KMKernel::setXmlGuiInstanceName(const QString &instance)
1044 mXmlGuiInstance = instance;
1047 KMail::UndoStack *KMKernel::undoStack() const
1049 return the_undoStack;
1052 void KMKernel::resumeNetworkJobs()
1054 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Online) {
1055 return;
1058 if (mSystemNetworkStatus) {
1059 setAccountStatus(true);
1060 BroadcastStatus::instance()->setStatusMsg(i18n("KMail is set to be online; all network jobs resumed"));
1061 } else {
1062 BroadcastStatus::instance()->setStatusMsg(i18n("KMail is set to be online; all network jobs will resume when a network connection is detected"));
1064 KMailSettings::setNetworkState(KMailSettings::EnumNetworkState::Online);
1065 Q_EMIT onlineStatusChanged((KMailSettings::EnumNetworkState::type)KMailSettings::networkState());
1066 KMMainWidget *widget = getKMMainWidget();
1067 if (widget) {
1068 widget->clearViewer();
1072 bool KMKernel::isOffline()
1074 if ((KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Offline) || !s_networkConfigMgr->isOnline()) {
1075 return true;
1076 } else {
1077 return false;
1081 void KMKernel::verifyAccount()
1083 const QString resourceGroupPattern(QStringLiteral("Resource %1"));
1085 const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
1086 foreach (Akonadi::AgentInstance type, lst) {
1087 KConfigGroup group(KMKernel::config(), resourceGroupPattern.arg(type.identifier()));
1088 if (group.readEntry("CheckOnStartup", false)) {
1089 if (!type.isOnline()) {
1090 type.setIsOnline(true);
1092 type.synchronize();
1095 // "false" is also hardcoded in ConfigureDialog, don't forget to change there.
1096 if (group.readEntry("OfflineOnShutdown", false)) {
1097 if (!type.isOnline()) {
1098 type.setIsOnline(true);
1104 void KMKernel::slotCheckAccount(Akonadi::ServerManager::State state)
1106 if (state == Akonadi::ServerManager::Running) {
1107 disconnect(Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)));
1108 verifyAccount();
1112 void KMKernel::checkMailOnStartup()
1114 if (!kmkernel->askToGoOnline()) {
1115 return;
1118 if (Akonadi::ServerManager::state() != Akonadi::ServerManager::Running) {
1119 connect(Akonadi::ServerManager::self(), &Akonadi::ServerManager::stateChanged, this, &KMKernel::slotCheckAccount);
1120 } else {
1121 verifyAccount();
1125 bool KMKernel::askToGoOnline()
1127 // already asking means we are offline and need to wait anyhow
1128 if (s_askingToGoOnline) {
1129 return false;
1132 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Offline) {
1133 s_askingToGoOnline = true;
1134 int rc =
1135 KMessageBox::questionYesNo(KMKernel::self()->mainWin(),
1136 i18n("KMail is currently in offline mode. "
1137 "How do you want to proceed?"),
1138 i18n("Online/Offline"),
1139 KGuiItem(i18n("Work Online")),
1140 KGuiItem(i18n("Work Offline")));
1142 s_askingToGoOnline = false;
1143 if (rc == KMessageBox::No) {
1144 return false;
1145 } else {
1146 kmkernel->resumeNetworkJobs();
1149 if (kmkernel->isOffline()) {
1150 return false;
1153 return true;
1156 void KMKernel::slotSystemNetworkStatusChanged(bool isOnline)
1158 mSystemNetworkStatus = isOnline;
1159 if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Offline) {
1160 return;
1163 if (isOnline) {
1164 BroadcastStatus::instance()->setStatusMsg(i18n(
1165 "Network connection detected, all network jobs resumed"));
1166 kmkernel->setAccountStatus(true);
1167 } else {
1168 BroadcastStatus::instance()->setStatusMsg(i18n(
1169 "No network connection detected, all network jobs are suspended"));
1170 kmkernel->setAccountStatus(false);
1174 /********************************************************************/
1175 /* Kernel methods */
1176 /********************************************************************/
1178 void KMKernel::quit()
1180 // Called when all windows are closed. Will take care of compacting,
1181 // sending... should handle session management too!!
1183 /* TODO later:
1184 Asuming that:
1185 - msgsender is nonblocking
1186 (our own, QSocketNotifier based. Pops up errors and sends signal
1187 senderFinished when done)
1189 o If we are getting mail, stop it (but don't lose something!)
1190 [Done already, see mailCheckAborted]
1191 o If we are sending mail, go on UNLESS this was called by SM,
1192 in which case stop ASAP that too (can we warn? should we continue
1193 on next start?)
1194 o If we are compacting, or expunging, go on UNLESS this was SM call.
1195 In that case stop compacting ASAP and continue on next start, before
1196 touching any folders. [Not needed anymore with CompactionJob]
1198 KMKernel::quit ()
1200 SM call?
1201 if compacting, stop;
1202 if sending, stop;
1203 if receiving, stop;
1204 Windows will take care of themselves (composer should dump
1205 its messages, if any but not in deadMail)
1206 declare us ready for the End of the Session
1208 No, normal quit call
1209 All windows are off. Anything to do, should compact or sender sends?
1210 Yes, maybe put an icon in panel as a sign of life
1211 if sender sending, connect us to his finished slot, declare us ready
1212 for quit and wait for senderFinished
1213 if not, Folder manager, go compact sent-mail and outbox
1214 } (= call slotFinished())
1216 void KMKernel::slotSenderFinished()
1218 good, Folder manager go compact sent-mail and outbox
1219 clean up stage1 (release folders and config, unregister from dcop)
1220 -- another kmail may start now ---
1221 qApp->quit();
1225 /********************************************************************/
1226 /* Init, Exit, and handler methods */
1227 /********************************************************************/
1229 //-----------------------------------------------------------------------------
1230 // Open a composer for each message found in the dead.letter folder
1231 void KMKernel::recoverDeadLetters()
1233 const QString pathName = localDataPath();
1234 QDir dir(pathName);
1235 if (!dir.exists(QStringLiteral("autosave"))) {
1236 return;
1239 dir.cd(localDataPath() + QLatin1String("autosave"));
1240 const QFileInfoList autoSaveFiles = dir.entryInfoList();
1241 foreach (const QFileInfo &file, autoSaveFiles) {
1242 // Disregard the '.' and '..' folders
1243 const QString filename = file.fileName();
1244 if (filename == QLatin1String(".") ||
1245 filename == QLatin1String("..")
1246 || file.isDir()) {
1247 continue;
1249 qCDebug(KMAIL_LOG) << "Opening autosave file:" << file.absoluteFilePath();
1250 QFile autoSaveFile(file.absoluteFilePath());
1251 if (autoSaveFile.open(QIODevice::ReadOnly)) {
1252 const KMime::Message::Ptr autoSaveMessage(new KMime::Message());
1253 const QByteArray msgData = autoSaveFile.readAll();
1254 autoSaveMessage->setContent(msgData);
1255 autoSaveMessage->parse();
1257 // Show the a new composer dialog for the message
1258 KMail::Composer *autoSaveWin = KMail::makeComposer();
1259 autoSaveWin->setMessage(autoSaveMessage, false, false, false);
1260 autoSaveWin->setAutoSaveFileName(filename);
1261 autoSaveWin->show();
1262 autoSaveFile.close();
1263 } else {
1264 KMessageBox::sorry(Q_NULLPTR, i18n("Failed to open autosave file at %1.\nReason: %2",
1265 file.absoluteFilePath(), autoSaveFile.errorString()),
1266 i18n("Opening Autosave File Failed"));
1271 void KMKernel::akonadiStateChanged(Akonadi::ServerManager::State state)
1273 qCDebug(KMAIL_LOG) << "KMKernel has akonadi state changed to:" << int(state);
1275 if (state == Akonadi::ServerManager::Running) {
1276 CommonKernel->initFolders();
1279 static void kmCrashHandler(int sigId)
1281 fprintf(stderr, "*** KMail got signal %d (Exiting)\n", sigId);
1282 // try to cleanup all windows
1283 if (kmkernel) {
1284 kmkernel->dumpDeadLetters();
1285 fprintf(stderr, "*** Dead letters dumped.\n");
1286 kmkernel->stopAgentInstance();
1290 void KMKernel::init()
1292 the_shuttingDown = false;
1294 the_firstStart = KMailSettings::self()->firstStart();
1295 KMailSettings::self()->setFirstStart(false);
1296 the_previousVersion = KMailSettings::self()->previousVersion();
1297 KMailSettings::self()->setPreviousVersion(QStringLiteral(KDEPIM_VERSION));
1299 the_undoStack = new UndoStack(20);
1301 the_msgSender = new MessageComposer::AkonadiSender;
1302 // filterMgr->dump();
1304 mBackgroundTasksTimer = new QTimer(this);
1305 mBackgroundTasksTimer->setSingleShot(true);
1306 connect(mBackgroundTasksTimer, &QTimer::timeout, this, &KMKernel::slotRunBackgroundTasks);
1307 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
1308 mBackgroundTasksTimer->start(10000); // 10s, singleshot
1309 #else
1310 mBackgroundTasksTimer->start(5 * 60000); // 5 minutes, singleshot
1311 #endif
1313 KCrash::setEmergencySaveFunction(kmCrashHandler);
1315 qCDebug(KMAIL_LOG) << "KMail init with akonadi server state:" << int(Akonadi::ServerManager::state());
1316 if (Akonadi::ServerManager::state() == Akonadi::ServerManager::Running) {
1317 CommonKernel->initFolders();
1320 connect(Akonadi::ServerManager::self(), &Akonadi::ServerManager::stateChanged, this, &KMKernel::akonadiStateChanged);
1323 bool KMKernel::doSessionManagement()
1326 // Do session management
1327 if (qApp->isSessionRestored()) {
1328 int n = 1;
1329 while (KMMainWin::canBeRestored(n)) {
1330 //only restore main windows! (Matthias);
1331 if (KMMainWin::classNameOfToplevel(n) == QLatin1String("KMMainWin")) {
1332 (new KMMainWin)->restoreDockedState(n);
1334 ++n;
1336 return true; // we were restored by SM
1338 return false; // no, we were not restored
1341 bool KMKernel::firstInstance() const
1343 return the_firstInstance;
1346 void KMKernel::setFirstInstance(bool value)
1348 the_firstInstance = value;
1351 void KMKernel::closeAllKMailWindows()
1353 QList<KMainWindow *> windowsToDelete;
1355 foreach (KMainWindow *window, KMainWindow::memberList()) {
1356 if (::qobject_cast<KMMainWin *>(window) ||
1357 ::qobject_cast<KMail::SecondaryWindow *>(window)) {
1358 // close and delete the window
1359 window->setAttribute(Qt::WA_DeleteOnClose);
1360 window->close();
1361 windowsToDelete.append(window);
1365 // We delete all main windows here. Above we called close(), but that calls
1366 // deleteLater() internally, therefore does not delete it immediately.
1367 // This would lead to problems when closing Kontact when a composer window
1368 // is open, because the destruction order is:
1370 // 1. destructor of the Kontact mainwinow
1371 // 2. delete all parts
1372 // 3. the KMail part destructor calls KMKernel::cleanup(), which calls
1373 // this function
1374 // 4. delete all other mainwindows
1376 // Deleting the composer windows here will make sure that step 4 will not delete
1377 // any composer window, which would fail because the kernel is already deleted.
1378 qDeleteAll(windowsToDelete);
1379 windowsToDelete.clear();
1382 void KMKernel::cleanup(void)
1384 disconnect(Akonadi::AgentManager::self(), SIGNAL(instanceStatusChanged(Akonadi::AgentInstance)));
1385 disconnect(Akonadi::AgentManager::self(), SIGNAL(instanceError(Akonadi::AgentInstance,QString)));
1386 disconnect(Akonadi::AgentManager::self(), SIGNAL(instanceWarning(Akonadi::AgentInstance,QString)));
1387 disconnect(Akonadi::AgentManager::self(), SIGNAL(instanceRemoved(Akonadi::AgentInstance)));
1388 disconnect(KPIM::ProgressManager::instance(), SIGNAL(progressItemCompleted(KPIM::ProgressItem*)));
1389 disconnect(KPIM::ProgressManager::instance(), SIGNAL(progressItemCanceled(KPIM::ProgressItem*)));
1391 dumpDeadLetters();
1392 the_shuttingDown = true;
1393 closeAllKMailWindows();
1395 // Flush the cache of foldercollection objects. This results
1396 // in configuration writes, so we need to do it early enough.
1397 MailCommon::FolderCollection::clearCache();
1399 // Write the config while all other managers are alive
1400 delete the_msgSender;
1401 the_msgSender = Q_NULLPTR;
1402 delete the_undoStack;
1403 the_undoStack = Q_NULLPTR;
1404 delete mConfigureDialog;
1405 mConfigureDialog = Q_NULLPTR;
1406 // do not delete, because mWin may point to an existing window
1407 // delete mWin;
1408 mWin = Q_NULLPTR;
1410 KSharedConfig::Ptr config = KMKernel::config();
1411 if (RecentAddresses::exists()) {
1412 RecentAddresses::self(config.data())->save(config.data());
1415 Akonadi::Collection trashCollection = CommonKernel->trashCollectionFolder();
1416 if (trashCollection.isValid()) {
1417 if (KMailSettings::self()->emptyTrashOnExit()) {
1418 OrgFreedesktopAkonadiMailFilterAgentInterface mailFilterInterface(QStringLiteral("org.freedesktop.Akonadi.MailFilterAgent"), QStringLiteral("/MailFilterAgent"), QDBusConnection::sessionBus(), this);
1419 if (mailFilterInterface.isValid()) {
1420 mailFilterInterface.expunge((qlonglong)trashCollection.id());
1421 } else {
1422 qCWarning(KMAIL_LOG) << "Mailfilter is not active";
1428 void KMKernel::dumpDeadLetters()
1430 if (shuttingDown()) {
1431 return; //All documents should be saved before shutting down is set!
1434 // make all composer windows autosave their contents
1435 foreach (KMainWindow *window, KMainWindow::memberList()) {
1436 if (KMail::Composer *win = ::qobject_cast<KMail::Composer *>(window)) {
1437 win->autoSaveMessage(true);
1439 while (win->isComposing()) {
1440 qCWarning(KMAIL_LOG) << "Danger, using an event loop, this should no longer be happening!";
1441 qApp->processEvents();
1447 void KMKernel::action(bool mailto, bool check, const QString &to,
1448 const QString &cc, const QString &bcc,
1449 const QString &subj, const QString &body,
1450 const QUrl &messageFile,
1451 const QList<QUrl> &attachURLs,
1452 const QStringList &customHeaders,
1453 const QString &replyTo,
1454 const QString &inReplyTo)
1456 if (mailto) {
1457 openComposer(to, cc, bcc, subj, body, 0,
1458 messageFile.toLocalFile(), QUrl::toStringList(attachURLs),
1459 customHeaders, replyTo, inReplyTo);
1460 } else {
1461 openReader(check);
1464 if (check) {
1465 checkMail();
1467 //Anything else?
1470 void KMKernel::slotRequestConfigSync()
1472 // ### FIXME: delay as promised in the kdoc of this function ;-)
1473 slotSyncConfig();
1476 void KMKernel::slotSyncConfig()
1478 PimCommon::PimCommonSettings::self()->save();
1479 MessageCore::MessageCoreSettings::self()->save();
1480 MessageViewer::MessageViewerSettings::self()->save();
1481 MessageComposer::MessageComposerSettings::self()->save();
1482 TemplateParser::TemplateParserSettings::self()->save();
1483 MessageList::MessageListSettings::self()->save();
1484 MailCommon::MailCommonSettings::self()->save();
1485 Gravatar::GravatarSettings::self()->save();
1486 KMailSettings::self()->save();
1487 KMKernel::config()->sync();
1488 //Laurent investigate why we need to reload them.
1489 PimCommon::PimCommonSettings::self()->load();
1490 MessageCore::MessageCoreSettings::self()->load();
1491 MessageViewer::MessageViewerSettings::self()->load();
1492 MessageComposer::MessageComposerSettings::self()->load();
1493 TemplateParser::TemplateParserSettings::self()->load();
1494 MessageList::MessageListSettings::self()->load();
1495 MailCommon::MailCommonSettings::self()->load();
1496 Gravatar::GravatarSettings::self()->load();
1497 KMailSettings::self()->load();
1498 KMKernel::config()->reparseConfiguration();
1501 void KMKernel::updateConfig()
1503 slotConfigChanged();
1506 void KMKernel::slotShowConfigurationDialog()
1508 if (KMKernel::getKMMainWidget() == Q_NULLPTR) {
1509 // ensure that there is a main widget available
1510 // as parts of the configure dialog (identity) rely on this
1511 // and this slot can be called when there is only a KMComposeWin showing
1512 KMMainWin *win = new KMMainWin;
1513 win->show();
1517 if (!mConfigureDialog) {
1518 mConfigureDialog = new ConfigureDialog(Q_NULLPTR, false);
1519 mConfigureDialog->setObjectName(QStringLiteral("configure"));
1520 connect(mConfigureDialog, &ConfigureDialog::configChanged, this, &KMKernel::slotConfigChanged);
1523 // Save all current settings.
1524 if (getKMMainWidget()) {
1525 getKMMainWidget()->writeReaderConfig();
1528 if (mConfigureDialog->isHidden()) {
1529 mConfigureDialog->show();
1530 } else {
1531 mConfigureDialog->raise();
1535 void KMKernel::slotConfigChanged()
1537 CodecManager::self()->updatePreferredCharsets();
1538 Q_EMIT configChanged();
1541 //-------------------------------------------------------------------------------
1542 //static
1543 QString KMKernel::localDataPath()
1545 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kmail2/");
1548 //-------------------------------------------------------------------------------
1550 bool KMKernel::haveSystemTrayApplet() const
1552 return (mSystemTray != Q_NULLPTR);
1555 void KMKernel::updateSystemTray()
1557 if (mSystemTray && !the_shuttingDown) {
1558 mSystemTray->updateSystemTray();
1562 KIdentityManagement::IdentityManager *KMKernel::identityManager()
1564 if (!mIdentityManager) {
1565 mIdentityManager = new KIdentityManagement::IdentityManager(false, this, "mIdentityManager");
1567 return mIdentityManager;
1570 KMainWindow *KMKernel::mainWin()
1572 // First look for a KMMainWin.
1573 foreach (KMainWindow *window, KMainWindow::memberList())
1574 if (::qobject_cast<KMMainWin *>(window)) {
1575 return window;
1578 // There is no KMMainWin. Use any other KMainWindow instead (e.g. in
1579 // case we are running inside Kontact) because we anyway only need
1580 // it for modal message boxes and for KNotify events.
1581 if (!KMainWindow::memberList().isEmpty()) {
1582 KMainWindow *kmWin = KMainWindow::memberList().first();
1583 if (kmWin) {
1584 return kmWin;
1588 // There's not a single KMainWindow. Create a KMMainWin.
1589 // This could happen if we want to pop up an error message
1590 // while we are still doing the startup wizard and no other
1591 // KMainWindow is running.
1592 mWin = new KMMainWin;
1593 return mWin;
1596 KMKernel *KMKernel::self()
1598 return mySelf;
1601 KSharedConfig::Ptr KMKernel::config()
1603 assert(mySelf);
1604 if (!mySelf->mConfig) {
1605 mySelf->mConfig = KSharedConfig::openConfig(QStringLiteral("kmail2rc"));
1606 // Check that all updates have been run on the config file:
1607 MessageList::MessageListSettings::self()->setSharedConfig(mySelf->mConfig);
1608 MessageList::MessageListSettings::self()->load();
1609 TemplateParser::TemplateParserSettings::self()->setSharedConfig(mySelf->mConfig);
1610 TemplateParser::TemplateParserSettings::self()->load();
1611 MessageComposer::MessageComposerSettings::self()->setSharedConfig(mySelf->mConfig);
1612 MessageComposer::MessageComposerSettings::self()->load();
1613 MessageCore::MessageCoreSettings::self()->setSharedConfig(mySelf->mConfig);
1614 MessageCore::MessageCoreSettings::self()->load();
1615 MessageViewer::MessageViewerSettings::self()->setSharedConfig(mySelf->mConfig);
1616 MessageViewer::MessageViewerSettings::self()->load();
1617 MailCommon::MailCommonSettings::self()->setSharedConfig(mySelf->mConfig);
1618 MailCommon::MailCommonSettings::self()->load();
1619 PimCommon::PimCommonSettings::self()->setSharedConfig(mySelf->mConfig);
1620 PimCommon::PimCommonSettings::self()->load();
1621 Gravatar::GravatarSettings::self()->setSharedConfig(mySelf->mConfig);
1622 Gravatar::GravatarSettings::self()->load();
1624 return mySelf->mConfig;
1627 void KMKernel::syncConfig()
1629 slotRequestConfigSync();
1632 void KMKernel::selectCollectionFromId(Akonadi::Collection::Id id)
1634 KMMainWidget *widget = getKMMainWidget();
1635 Q_ASSERT(widget);
1636 if (!widget) {
1637 return;
1640 Akonadi::Collection colFolder = CommonKernel->collectionFromId(id);
1642 if (colFolder.isValid()) {
1643 widget->slotSelectCollectionFolder(colFolder);
1647 bool KMKernel::selectFolder(const QString &folder)
1649 KMMainWidget *widget = getKMMainWidget();
1650 Q_ASSERT(widget);
1651 if (!widget) {
1652 return false;
1655 const Akonadi::Collection colFolder = CommonKernel->collectionFromId(folder.toLongLong());
1657 if (colFolder.isValid()) {
1658 widget->slotSelectCollectionFolder(colFolder);
1659 return true;
1661 return false;
1664 KMMainWidget *KMKernel::getKMMainWidget()
1666 //This could definitely use a speadup
1667 QWidgetList l = QApplication::topLevelWidgets();
1668 QWidget *wid;
1670 Q_FOREACH (wid, l) {
1671 QList<KMMainWidget *> l2 = wid->window()->findChildren<KMMainWidget *>();
1672 if (!l2.isEmpty() && l2.first()) {
1673 return l2.first();
1676 return Q_NULLPTR;
1679 void KMKernel::slotRunBackgroundTasks() // called regularly by timer
1681 // Hidden KConfig keys. Not meant to be used, but a nice fallback in case
1682 // a stable kmail release goes out with a nasty bug in CompactionJob...
1683 if (KMailSettings::self()->autoExpiring()) {
1684 mFolderCollectionMonitor->expireAllFolders(false /*scheduled, not immediate*/, entityTreeModel());
1686 if (KMailSettings::self()->checkCollectionsIndexing()) {
1687 mCheckIndexingManager->start(entityTreeModel());
1689 #ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
1690 mBackgroundTasksTimer->start(60 * 1000); // check again in 1 minute
1691 #else
1692 mBackgroundTasksTimer->start(4 * 60 * 60 * 1000); // check again in 4 hours
1693 #endif
1697 static Akonadi::Collection::List collect_collections(const QAbstractItemModel *model,
1698 const QModelIndex &parent)
1700 Akonadi::Collection::List collections;
1701 const int numberOfCollection(model->rowCount(parent));
1702 for (int i = 0; i < numberOfCollection; ++i) {
1703 const QModelIndex child = model->index(i, 0, parent);
1704 Akonadi::Collection collection =
1705 model->data(child, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
1706 if (collection.isValid()) {
1707 collections << collection;
1709 collections += collect_collections(model, child);
1711 return collections;
1714 Akonadi::Collection::List KMKernel::allFolders() const
1716 return collect_collections(collectionModel(), QModelIndex());
1719 void KMKernel::expireAllFoldersNow() // called by the GUI
1721 mFolderCollectionMonitor->expireAllFolders(true /*immediate*/, entityTreeModel());
1724 bool KMKernel::canQueryClose()
1726 if (KMMainWidget::mainWidgetList() &&
1727 KMMainWidget::mainWidgetList()->count() > 1) {
1728 return true;
1730 if (!mSystemTray) {
1731 return true;
1733 if (mSystemTray->mode() == KMailSettings::EnumSystemTrayPolicy::ShowAlways) {
1734 mSystemTray->hideKMail();
1735 return false;
1736 } else if ((mSystemTray->mode() == KMailSettings::EnumSystemTrayPolicy::ShowOnUnread)) {
1737 if (mSystemTray->hasUnreadMail()) {
1738 mSystemTray->setStatus(KStatusNotifierItem::Active);
1740 mSystemTray->hideKMail();
1741 return false;
1743 return true;
1746 QSharedPointer<FolderCollection> KMKernel::currentFolderCollection()
1748 KMMainWidget *widget = getKMMainWidget();
1749 QSharedPointer<FolderCollection> folder;
1750 if (widget) {
1751 folder = widget->currentFolder();
1753 return folder;
1756 Akonadi::Search::PIM::IndexedItems *KMKernel::indexedItems() const
1758 return mIndexedItems;
1761 // can't be inline, since KMSender isn't known to implement
1762 // KMail::MessageSender outside this .cpp file
1763 MessageComposer::MessageSender *KMKernel::msgSender()
1765 return the_msgSender;
1768 void KMKernel::transportRemoved(int id, const QString &name)
1770 Q_UNUSED(id);
1772 // reset all identities using the deleted transport
1773 QStringList changedIdents;
1774 KIdentityManagement::IdentityManager *im = identityManager();
1775 KIdentityManagement::IdentityManager::Iterator end = im->modifyEnd();
1776 for (KIdentityManagement::IdentityManager::Iterator it = im->modifyBegin(); it != end; ++it) {
1777 if (name == (*it).transport()) {
1778 (*it).setTransport(QString());
1779 changedIdents += (*it).identityName();
1783 // if the deleted transport is the currently used transport reset it to default
1784 const QString &currentTransport = KMailSettings::self()->currentTransport();
1785 if (name == currentTransport) {
1786 KMailSettings::self()->setCurrentTransport(QString());
1789 if (!changedIdents.isEmpty()) {
1790 QString information = i18np("This identity has been changed to use the default transport:",
1791 "These %1 identities have been changed to use the default transport:",
1792 changedIdents.count());
1793 //Don't set parent otherwise we will swith to current KMail and we configure it. So not good
1794 KMessageBox::informationList(Q_NULLPTR, information, changedIdents);
1795 im->commit();
1799 void KMKernel::transportRenamed(int id, const QString &oldName, const QString &newName)
1801 Q_UNUSED(id);
1803 QStringList changedIdents;
1804 KIdentityManagement::IdentityManager *im = identityManager();
1805 KIdentityManagement::IdentityManager::Iterator end = im->modifyEnd();
1806 for (KIdentityManagement::IdentityManager::Iterator it = im->modifyBegin(); it != end; ++it) {
1807 if (oldName == (*it).transport()) {
1808 (*it).setTransport(newName);
1809 changedIdents << (*it).identityName();
1813 if (!changedIdents.isEmpty()) {
1814 const QString information =
1815 i18np("This identity has been changed to use the modified transport:",
1816 "These %1 identities have been changed to use the modified transport:",
1817 changedIdents.count());
1818 //Don't set parent otherwise we will swith to current KMail and we configure it. So not good
1819 KMessageBox::informationList(Q_NULLPTR, information, changedIdents);
1820 im->commit();
1824 void KMKernel::itemDispatchStarted()
1826 // Watch progress of the MDA.
1827 KPIM::ProgressManager::createProgressItem(Q_NULLPTR,
1828 MailTransport::DispatcherInterface().dispatcherInstance(),
1829 QStringLiteral("Sender"),
1830 i18n("Sending messages"),
1831 i18n("Initiating sending process..."),
1832 true);
1835 void KMKernel::instanceStatusChanged(const Akonadi::AgentInstance &instance)
1837 if (instance.identifier() == QLatin1String("akonadi_mailfilter_agent")) {
1838 // Creating a progress item twice is ok, it will simply return the already existing
1839 // item
1840 KPIM::ProgressItem *progress = KPIM::ProgressManager::createProgressItem(Q_NULLPTR, instance,
1841 instance.identifier(), instance.name(), instance.statusMessage(),
1842 false, KPIM::ProgressItem::Encrypted);
1843 progress->setProperty("AgentIdentifier", instance.identifier());
1844 return;
1846 if (MailCommon::Util::agentInstances(true).contains(instance)) {
1847 if (instance.status() == Akonadi::AgentInstance::Running) {
1849 if (mResourcesBeingChecked.isEmpty()) {
1850 qCDebug(KMAIL_LOG) << "A Resource started to synchronize, starting a mail check.";
1851 Q_EMIT startCheckMail();
1854 const QString identifier(instance.identifier());
1855 if (!mResourcesBeingChecked.contains(identifier)) {
1856 mResourcesBeingChecked.append(identifier);
1859 KPIM::ProgressItem::CryptoStatus cryptoStatus = KPIM::ProgressItem::Unencrypted;
1860 if (mResourceCryptoSettingCache.contains(identifier)) {
1861 cryptoStatus = mResourceCryptoSettingCache.value(identifier);
1862 } else {
1863 if (PimCommon::Util::isImapResource(identifier)) {
1864 PimCommon::ResourceReadConfigFile resourceFile(identifier);
1865 const KConfigGroup grp = resourceFile.group(QStringLiteral("network"));
1866 if (grp.isValid()) {
1867 const QString imapSafety = grp.readEntry(QStringLiteral("Safety"));
1868 if (imapSafety == QLatin1String("None")) {
1869 cryptoStatus = KPIM::ProgressItem::Unencrypted;
1870 } else {
1871 cryptoStatus = KPIM::ProgressItem::Encrypted;
1874 mResourceCryptoSettingCache.insert(identifier, cryptoStatus);
1876 } else if (identifier.contains(POP3_RESOURCE_IDENTIFIER)) {
1877 PimCommon::ResourceReadConfigFile resourceFile(identifier);
1878 const KConfigGroup grp = resourceFile.group(QStringLiteral("General"));
1879 if (grp.isValid()) {
1880 if (grp.readEntry(QStringLiteral("useSSL"), false) || grp.readEntry(QStringLiteral("useTLS"), false)) {
1881 cryptoStatus = KPIM::ProgressItem::Encrypted;
1883 mResourceCryptoSettingCache.insert(identifier, cryptoStatus);
1888 // Creating a progress item twice is ok, it will simply return the already existing
1889 // item
1890 KPIM::ProgressItem *progress = KPIM::ProgressManager::createProgressItem(Q_NULLPTR, instance,
1891 instance.identifier(), instance.name(), instance.statusMessage(),
1892 true, cryptoStatus);
1893 progress->setProperty("AgentIdentifier", instance.identifier());
1894 } else if (instance.status() == Akonadi::AgentInstance::Broken) {
1895 agentInstanceBroken(instance);
1900 void KMKernel::agentInstanceBroken(const Akonadi::AgentInstance &instance)
1902 const QString summary = i18n("Resource %1 is broken.", instance.name());
1903 KNotification::event(QStringLiteral("akonadi-resource-broken"),
1904 summary,
1905 QPixmap(),
1906 Q_NULLPTR,
1907 KNotification::CloseOnTimeout);
1910 void KMKernel::slotProgressItemCompletedOrCanceled(KPIM::ProgressItem *item)
1912 const QString identifier = item->property("AgentIdentifier").toString();
1913 const Akonadi::AgentInstance agent = Akonadi::AgentManager::self()->instance(identifier);
1914 if (agent.isValid()) {
1915 mResourcesBeingChecked.removeAll(identifier);
1916 if (mResourcesBeingChecked.isEmpty()) {
1917 qCDebug(KMAIL_LOG) << "Last resource finished syncing, mail check done";
1918 Q_EMIT endCheckMail();
1923 void KMKernel::updatedTemplates()
1925 Q_EMIT customTemplatesChanged();
1928 void KMKernel::stopAgentInstance()
1930 const QString resourceGroupPattern(QStringLiteral("Resource %1"));
1932 const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
1933 foreach (Akonadi::AgentInstance type, lst) {
1934 const QString identifier = type.identifier();
1935 KConfigGroup group(KMKernel::config(), resourceGroupPattern.arg(identifier));
1937 // Keep sync in ConfigureDialog, don't forget to change there.
1938 if (group.readEntry("OfflineOnShutdown", identifier.startsWith(QStringLiteral("akonadi_pop3_resource")) ? true : false)) {
1939 type.setIsOnline(false);
1944 void KMKernel::slotCollectionRemoved(const Akonadi::Collection &col)
1946 KConfigGroup group(KMKernel::config(), MailCommon::FolderCollection::configGroupName(col));
1947 group.deleteGroup();
1948 group.sync();
1949 const QString colStr = QString::number(col.id());
1950 TemplateParser::Util::deleteTemplate(colStr);
1951 MessageList::Util::deleteConfig(colStr);
1954 void KMKernel::slotDeleteIdentity(uint identity)
1956 TemplateParser::Util::deleteTemplate(QStringLiteral("IDENTITY_%1").arg(identity));
1959 bool KMKernel::showPopupAfterDnD()
1961 return KMailSettings::self()->showPopupAfterDnD();
1964 bool KMKernel::excludeImportantMailFromExpiry()
1966 return KMailSettings::self()->excludeImportantMailFromExpiry();
1969 qreal KMKernel::closeToQuotaThreshold()
1971 return KMailSettings::self()->closeToQuotaThreshold();
1974 Akonadi::Collection::Id KMKernel::lastSelectedFolder()
1976 return KMailSettings::self()->lastSelectedFolder();
1979 void KMKernel::setLastSelectedFolder(Akonadi::Collection::Id col)
1981 KMailSettings::self()->setLastSelectedFolder(col);
1984 QStringList KMKernel::customTemplates()
1986 return GlobalSettingsBase::self()->customTemplates();
1989 void KMKernel::openFilterDialog(bool createDummyFilter)
1991 if (!mFilterEditDialog) {
1992 mFilterEditDialog = new MailCommon::KMFilterDialog(getKMMainWidget()->actionCollections(), Q_NULLPTR, createDummyFilter);
1993 mFilterEditDialog->setObjectName(QStringLiteral("filterdialog"));
1995 mFilterEditDialog->show();
1996 mFilterEditDialog->raise();
1997 mFilterEditDialog->activateWindow();
2000 void KMKernel::createFilter(const QByteArray &field, const QString &value)
2002 mFilterEditDialog->createFilter(field, value);
2006 void KMKernel::checkFolderFromResources(const Akonadi::Collection::List &collectionList)
2008 const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
2009 foreach (const Akonadi::AgentInstance &type, lst) {
2010 if (type.status() == Akonadi::AgentInstance::Broken) {
2011 continue;
2013 const QString typeIdentifier(type.identifier());
2014 if (PimCommon::Util::isImapResource(typeIdentifier)) {
2015 OrgKdeAkonadiImapSettingsInterface *iface = PimCommon::Util::createImapSettingsInterface(typeIdentifier);
2016 if (iface && iface->isValid()) {
2017 const Akonadi::Collection::Id imapTrashId = iface->trashCollection();
2018 foreach (const Akonadi::Collection &collection, collectionList) {
2019 const Akonadi::Collection::Id collectionId = collection.id();
2020 if (imapTrashId == collectionId) {
2021 //Use default trash
2022 iface->setTrashCollection(CommonKernel->trashCollectionFolder().id());
2023 iface->save();
2024 break;
2028 delete iface;
2029 } else if (typeIdentifier.contains(POP3_RESOURCE_IDENTIFIER)) {
2030 OrgKdeAkonadiPOP3SettingsInterface *iface = MailCommon::Util::createPop3SettingsInterface(typeIdentifier);
2031 if (iface->isValid()) {
2032 foreach (const Akonadi::Collection &collection, collectionList) {
2033 const Akonadi::Collection::Id collectionId = collection.id();
2034 if (iface->targetCollection() == collectionId) {
2035 //Use default inbox
2036 iface->setTargetCollection(CommonKernel->inboxCollectionFolder().id());
2037 iface->save();
2038 break;
2042 delete iface;
2047 const QAbstractItemModel *KMKernel::treeviewModelSelection()
2049 if (getKMMainWidget()) {
2050 return getKMMainWidget()->folderTreeView()->selectionModel()->model();
2051 } else {
2052 return entityTreeModel();
2056 void KMKernel::slotInstanceWarning(const Akonadi::AgentInstance &instance, const QString &message)
2058 const QString summary = i18nc("<source>: <error message>", "%1: %2", instance.name(), message);
2059 KNotification::event(QStringLiteral("akonadi-instance-warning"),
2060 summary,
2061 QPixmap(),
2062 Q_NULLPTR,
2063 KNotification::CloseOnTimeout);
2066 void KMKernel::slotInstanceError(const Akonadi::AgentInstance &instance, const QString &message)
2068 const QString summary = i18nc("<source>: <error message>", "%1: %2", instance.name(), message);
2069 KNotification::event(QStringLiteral("akonadi-instance-error"),
2070 summary,
2071 QPixmap(),
2072 Q_NULLPTR,
2073 KNotification::CloseOnTimeout);
2076 void KMKernel::slotInstanceRemoved(const Akonadi::AgentInstance &instance)
2078 const QString identifier(instance.identifier());
2079 const QString resourceGroup = QStringLiteral("Resource %1").arg(identifier);
2080 if (KMKernel::config()->hasGroup(resourceGroup)) {
2081 KConfigGroup group(KMKernel::config(), resourceGroup);
2082 group.deleteGroup();
2083 group.sync();
2085 if (mResourceCryptoSettingCache.contains(identifier)) {
2086 mResourceCryptoSettingCache.remove(identifier);
2088 mFolderArchiveManager->slotInstanceRemoved(instance);
2091 void KMKernel::savePaneSelection()
2093 KMMainWidget *widget = getKMMainWidget();
2094 if (widget) {
2095 widget->savePaneSelection();
2099 void KMKernel::updatePaneTagComboBox()
2101 KMMainWidget *widget = getKMMainWidget();
2102 if (widget) {
2103 widget->updatePaneTagComboBox();
2107 void KMKernel::resourceGoOnLine()
2109 KMMainWidget *widget = getKMMainWidget();
2110 if (widget) {
2111 if (widget->currentFolder()) {
2112 Akonadi::Collection collection = widget->currentFolder()->collection();
2113 Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance(collection.resource());
2114 instance.setIsOnline(true);
2115 widget->clearViewer();
2120 void KMKernel::makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode mode)
2122 switch (mode) {
2123 case MessageViewer::Viewer::AllResources:
2124 resumeNetworkJobs();
2125 break;
2126 case MessageViewer::Viewer::SelectedResource:
2127 resourceGoOnLine();
2128 break;
2132 PimCommon::AutoCorrection *KMKernel::composerAutoCorrection()
2134 return mAutoCorrection;
2137 void KMKernel::toggleSystemTray()
2139 KMMainWidget *widget = getKMMainWidget();
2140 if (widget) {
2141 if (!mSystemTray && KMailSettings::self()->systemTrayEnabled()) {
2142 mSystemTray = new KMail::KMSystemTray(widget);
2143 } else if (mSystemTray && !KMailSettings::self()->systemTrayEnabled()) {
2144 // Get rid of system tray on user's request
2145 qCDebug(KMAIL_LOG) << "deleting systray";
2146 delete mSystemTray;
2147 mSystemTray = Q_NULLPTR;
2150 // Set mode of systemtray. If mode has changed, tray will handle this.
2151 if (mSystemTray) {
2152 mSystemTray->setMode(KMailSettings::self()->systemTrayPolicy());
2158 void KMKernel::showFolder(const QString &collectionId)
2160 if (!collectionId.isEmpty()) {
2161 const Akonadi::Collection::Id id = collectionId.toLongLong();
2162 selectCollectionFromId(id);
2166 void KMKernel::reloadFolderArchiveConfig()
2168 mFolderArchiveManager->reloadConfig();
2171 void KMKernel::slotCollectionChanged(const Akonadi::Collection &, const QSet<QByteArray> &set)
2173 if (set.contains("newmailnotifierattribute")) {
2174 if (mSystemTray) {
2175 mSystemTray->updateSystemTray();
2180 FolderArchiveManager *KMKernel::folderArchiveManager() const
2182 return mFolderArchiveManager;
2185 bool KMKernel::allowToDebugBalooSupport() const
2187 return mDebugBaloo;
2190 bool KMKernel::firstStart() const
2192 return the_firstStart;
2195 QString KMKernel::previousVersion() const
2197 return the_previousVersion;
2200 bool KMKernel::shuttingDown() const
2202 return the_shuttingDown;
2205 void KMKernel::setShuttingDown(bool flag)
2207 the_shuttingDown = flag;
2210 void KMKernel::expunge(Akonadi::Collection::Id col, bool sync)
2212 Q_UNUSED(col);
2213 Q_UNUSED(sync);