kmkernel.cpp 70.9 KB
Newer Older
Laurent Montel's avatar
Laurent Montel committed
1
/*   */
2

Marc Mutz's avatar
Marc Mutz committed
3
4
#include "kmkernel.h"

Laurent Montel's avatar
Laurent Montel committed
5
#include "settings/kmailsettings.h"
6
#include <PimCommon/BroadcastStatus>
Laurent Montel's avatar
Laurent Montel committed
7
#include "job/opencomposerjob.h"
Laurent Montel's avatar
Laurent Montel committed
8
#include "job/newmessagejob.h"
Laurent Montel's avatar
Laurent Montel committed
9
#include "job/opencomposerhiddenjob.h"
10
#include "job/fillcomposerjob.h"
11
#include <AkonadiSearch/PIM/indexeditems.h>
Laurent Montel's avatar
Laurent Montel committed
12
#include <PimCommonAkonadi/ProgressManagerAkonadi>
13
using PimCommon::BroadcastStatus;
14
#include "kmmainwin.h"
Laurent Montel's avatar
Laurent Montel committed
15
#include "editor/composer.h"
16
#include "kmreadermainwin.h"
17
#include "undostack.h"
18
#include "kmmainwidget.h"
19

Laurent Montel's avatar
Laurent Montel committed
20
#include "search/checkindexingmanager.h"
Laurent Montel's avatar
Laurent Montel committed
21
#include <Libkdepim/RecentAddresses>
22
using KPIM::RecentAddresses;
Laurent Montel's avatar
Laurent Montel committed
23
#include "configuredialog/configuredialog.h"
24
#include "kmcommands.h"
Laurent Montel's avatar
Laurent Montel committed
25
#include "unityservicemanager.h"
Laurent Montel's avatar
Laurent Montel committed
26
#include <MessageCore/StringUtil>
Laurent Montel's avatar
Laurent Montel committed
27
#include <MailCommon/MailUtil>
Laurent Montel's avatar
Laurent Montel committed
28
#include "pop3settings.h"
Laurent Montel's avatar
Laurent Montel committed
29
30
#include <MailCommon/FolderTreeView>
#include <MailCommon/KMFilterDialog>
Laurent Montel's avatar
Laurent Montel committed
31
#include "mailcommonsettings_base.h"
32
#include "mailfilteragentinterface.h"
Laurent Montel's avatar
Laurent Montel committed
33
#include <PimCommon/PimUtil>
34
#include "folderarchive/folderarchivemanager.h"
35
#include "sieveimapinterface/kmailsieveimapinstanceinterface.h"
36
// kdepim includes
37
#include "kmail-version.h"
38

39
// kdepimlibs includes
Laurent Montel's avatar
Laurent Montel committed
40
41
#include <KIdentityManagement/kidentitymanagement/identity.h>
#include <KIdentityManagement/kidentitymanagement/identitymanager.h>
42
43
44
#include <MailTransport/Transport>
#include <MailTransport/TransportManager>
#include <MailTransportAkonadi/DispatcherInterface>
45

Laurent Montel's avatar
Laurent Montel committed
46
#include <KSieveUi/SieveImapInstanceInterfaceManager>
Laurent Montel's avatar
Laurent Montel committed
47
#include "mailserviceimpl.h"
48
using KMail::MailServiceImpl;
Laurent Montel's avatar
Laurent Montel committed
49
#include <MailCommon/JobScheduler>
Laurent Montel's avatar
Laurent Montel committed
50

Laurent Montel's avatar
Laurent Montel committed
51
#include <MessageCore/MessageCoreSettings>
Laurent Montel's avatar
Laurent Montel committed
52
#include "messagelistsettings.h"
Laurent Montel's avatar
Laurent Montel committed
53
#include "gravatarsettings.h"
Laurent Montel's avatar
Laurent Montel committed
54
#include <MessageList/MessageListUtil>
Laurent Montel's avatar
Laurent Montel committed
55
#include <MessageViewer/MessageViewerSettings>
Laurent Montel's avatar
Laurent Montel committed
56
57
58
59
60
61
#include <MessageComposer/AkonadiSender>
#include <MessageComposer/MessageComposerSettings>
#include <MessageComposer/MessageHelper>
#include <MessageComposer/MessageComposerSettings>
#include <PimCommon/PimCommonSettings>
#include <PimCommon/AutoCorrection>
Laurent Montel's avatar
Laurent Montel committed
62
#include <PimCommon/NetworkManager>
63

64
#include "globalsettings_templateparser.h"
Laurent Montel's avatar
Laurent Montel committed
65
#include <TemplateParser/TemplatesUtil>
66

Laurent Montel's avatar
Laurent Montel committed
67
#include <MailCommon/FolderSettings>
68
#include "editor/codec/codecmanager.h"
69

70
71
#include <KMessageBox>
#include <KNotification>
Laurent Montel's avatar
Laurent Montel committed
72
#include <Libkdepim/ProgressManager>
Laurent Montel's avatar
Laurent Montel committed
73

74
75
#include <KConfig>
#include <KConfigGroup>
Laurent Montel's avatar
Laurent Montel committed
76
#include "kmail_debug.h"
Thomas McGuire's avatar
Thomas McGuire committed
77
#include <kio/jobuidelegate.h>
78
#include <KCrash>
79

Laurent Montel's avatar
Laurent Montel committed
80
81
#include <kmime/kmime_message.h>
#include <kmime/kmime_headers.h>
Laurent Montel's avatar
Laurent Montel committed
82
83
84
85
#include <AkonadiCore/Collection>
#include <AkonadiCore/CollectionFetchJob>
#include <AkonadiCore/ChangeRecorder>
#include <AkonadiCore/ItemFetchScope>
Laurent Montel's avatar
Laurent Montel committed
86
87
#include <AkonadiCore/AgentManager>
#include <AkonadiCore/ItemFetchJob>
Laurent Montel's avatar
Laurent Montel committed
88
89
90
91
#include <AkonadiCore/AttributeFactory>
#include <AkonadiCore/Session>
#include <AkonadiCore/EntityTreeModel>
#include <AkonadiCore/entitymimetypefiltermodel.h>
Laurent Montel's avatar
Laurent Montel committed
92
#include <AkonadiCore/CollectionStatisticsJob>
93
#include <AkonadiCore/ServerManager>
Laurent Montel's avatar
Port++    
Laurent Montel committed
94

Laurent Montel's avatar
Laurent Montel committed
95
#include <QNetworkConfigurationManager>
Andreas Gungl's avatar
Andreas Gungl committed
96
97
#include <QDir>
#include <QWidget>
98
#include <QFileInfo>
Yuri Chornoivan's avatar
Yuri Chornoivan committed
99
#include <QtDBus>
100

101
#include <MailCommon/ResourceReadConfigFile>
102

103
#include <kmailadaptor.h>
Laurent Montel's avatar
Laurent Montel committed
104
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
105
#include <QStandardPaths>
Laurent Montel's avatar
Laurent Montel committed
106
#include "kmailinterface.h"
Laurent Montel's avatar
Laurent Montel committed
107
#include <MailCommon/FolderCollectionMonitor>
108
#include "imapresourcesettings.h"
Laurent Montel's avatar
++port    
Laurent Montel committed
109
#include "util.h"
Laurent Montel's avatar
Laurent Montel committed
110
#include <MailCommon/MailKernel>
111

Laurent Montel's avatar
Laurent Montel committed
112
#include "searchdialog/searchdescriptionattribute.h"
113
#include "kmail_options.h"
Laurent Montel's avatar
Laurent Montel committed
114
115
#ifdef WITH_KUSERFEEDBACK
#include <KUserFeedback/Provider>
Laurent Montel's avatar
Laurent Montel committed
116
#include "userfeedback/kmailuserfeedbackprovider.h"
Laurent Montel's avatar
Laurent Montel committed
117
118
#endif

Laurent Montel's avatar
Laurent Montel committed
119
//#define DEBUG_SCHEDULER 1
Andras Mantia's avatar
Andras Mantia committed
120
121
using namespace MailCommon;

Laurent Montel's avatar
Laurent Montel committed
122
static KMKernel *mySelf = nullptr;
123
static bool s_askingToGoOnline = false;
124
125
126
/********************************************************************/
/*                     Constructor and destructor                   */
/********************************************************************/
Laurent Montel's avatar
Laurent Montel committed
127
128
KMKernel::KMKernel(QObject *parent)
    : QObject(parent)
Laurent Montel's avatar
Laurent Montel committed
129
{
130
131
    //Initialize kmail sieveimap interface
    KSieveUi::SieveImapInstanceInterfaceManager::self()->setSieveImapInstanceInterface(new KMailSieveImapInstanceInterface);
132
    mDebug = !qEnvironmentVariableIsEmpty("KDEPIM_DEBUGGING");
133

Laurent Montel's avatar
Laurent Montel committed
134
#ifdef WITH_KUSERFEEDBACK
Laurent Montel's avatar
Laurent Montel committed
135
    mUserFeedbackProvider = new KMailUserFeedbackProvider(this);
Laurent Montel's avatar
Laurent Montel committed
136
#endif
Laurent Montel's avatar
Laurent Montel committed
137
    mSystemNetworkStatus = PimCommon::NetworkManager::self()->networkConfigureManager()->isOnline();
Laurent Montel's avatar
Laurent Montel committed
138

Laurent Montel's avatar
Laurent Montel committed
139
    Akonadi::AttributeFactory::registerAttribute<Akonadi::SearchDescriptionAttribute>();
Laurent Montel's avatar
Laurent Montel committed
140
    QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kmail"));
Laurent Montel's avatar
Laurent Montel committed
141
    qCDebug(KMAIL_LOG) << "Starting up...";
Laurent Montel's avatar
Laurent Montel committed
142
143
144
145

    mySelf = this;
    the_firstInstance = true;

Laurent Montel's avatar
Laurent Montel committed
146
147
148
    the_undoStack = nullptr;
    the_msgSender = nullptr;
    mFilterEditDialog = nullptr;
Laurent Montel's avatar
Laurent Montel committed
149
150
151
152
153
    // make sure that we check for config updates before doing anything else
    KMKernel::config();
    // this shares the kmailrc parsing too (via KSharedConfig), and reads values from it
    // so better do it here, than in some code where changing the group of config()
    // would be unexpected
Laurent Montel's avatar
Laurent Montel committed
154
    KMailSettings::self();
Laurent Montel's avatar
Laurent Montel committed
155

Laurent Montel's avatar
Laurent Montel committed
156
    mJobScheduler = new JobScheduler(this);
Laurent Montel's avatar
Laurent Montel committed
157
158

    mAutoCorrection = new PimCommon::AutoCorrection();
Laurent Montel's avatar
Laurent Montel committed
159
    KMime::setUseOutlookAttachmentEncoding(MessageComposer::MessageComposerSettings::self()->outlookCompatibleAttachments());
Laurent Montel's avatar
Laurent Montel committed
160
161

    // cberzan: this crap moved to CodecManager ======================
Volker Krause's avatar
Volker Krause committed
162
    mNetCodec = QTextCodec::codecForLocale();
Laurent Montel's avatar
Laurent Montel committed
163
164
165
166
167
168
169
170
171

    // In the case of Japan. Japanese locale name is "eucjp" but
    // The Japanese mail systems normally used "iso-2022-jp" of locale name.
    // We want to change locale name from eucjp to iso-2022-jp at KMail only.

    // (Introduction to i18n, 6.6 Limit of Locale technology):
    // EUC-JP is the de-facto standard for UNIX systems, ISO 2022-JP
    // is the standard for Internet, and Shift-JIS is the encoding
    // for Windows and Macintosh.
Laurent Montel's avatar
Laurent Montel committed
172
173
    const QByteArray netCodecLower = mNetCodec->name().toLower();
    if (netCodecLower == "eucjp"
Laurent Montel's avatar
Laurent Montel committed
174
#if defined Q_OS_WIN || defined Q_OS_MACX
Laurent Montel's avatar
Laurent Montel committed
175
        || netCodecLower == "shift-jis"     // OK?
Laurent Montel's avatar
Laurent Montel committed
176
#endif
Laurent Montel's avatar
Laurent Montel committed
177
        ) {
Laurent Montel's avatar
Laurent Montel committed
178
        mNetCodec = QTextCodec::codecForName("jis7");
Laurent Montel's avatar
Laurent Montel committed
179
180
181
    }
    // until here ================================================

Laurent Montel's avatar
Laurent Montel committed
182
    Akonadi::Session *session = new Akonadi::Session("KMail Kernel ETM", this);
Laurent Montel's avatar
Laurent Montel committed
183

Laurent Montel's avatar
Laurent Montel committed
184
    mFolderCollectionMonitor = new FolderCollectionMonitor(session, this);
Laurent Montel's avatar
Laurent Montel committed
185

Laurent Montel's avatar
Laurent Montel committed
186
    connect(mFolderCollectionMonitor->monitor(), &Akonadi::Monitor::collectionRemoved, this, &KMKernel::slotCollectionRemoved);
Laurent Montel's avatar
Laurent Montel committed
187

Laurent Montel's avatar
Laurent Montel committed
188
    mEntityTreeModel = new Akonadi::EntityTreeModel(folderCollectionMonitor(), this);
189
    mEntityTreeModel->setListFilter(Akonadi::CollectionFetchScope::Enabled);
Laurent Montel's avatar
Laurent Montel committed
190
    mEntityTreeModel->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation);
Laurent Montel's avatar
Laurent Montel committed
191

Laurent Montel's avatar
Laurent Montel committed
192
193
194
195
196
197
    mCollectionModel = new Akonadi::EntityMimeTypeFilterModel(this);
    mCollectionModel->setSourceModel(mEntityTreeModel);
    mCollectionModel->addMimeTypeInclusionFilter(Akonadi::Collection::mimeType());
    mCollectionModel->setHeaderGroup(Akonadi::EntityTreeModel::CollectionTreeHeaders);
    mCollectionModel->setDynamicSortFilter(true);
    mCollectionModel->setSortCaseSensitivity(Qt::CaseInsensitive);
Laurent Montel's avatar
Laurent Montel committed
198

Laurent Montel's avatar
Laurent Montel committed
199
    connect(folderCollectionMonitor(), qOverload<const Akonadi::Collection &, const QSet<QByteArray> &>(&Akonadi::ChangeRecorder::collectionChanged), this,
Laurent Montel's avatar
Laurent Montel committed
200
            &KMKernel::slotCollectionChanged);
Laurent Montel's avatar
Laurent Montel committed
201

Laurent Montel's avatar
Laurent Montel committed
202
203
    connect(MailTransport::TransportManager::self(), &MailTransport::TransportManager::transportRemoved, this, &KMKernel::transportRemoved);
    connect(MailTransport::TransportManager::self(), &MailTransport::TransportManager::transportRenamed, this, &KMKernel::transportRenamed);
Laurent Montel's avatar
Laurent Montel committed
204

Laurent Montel's avatar
Laurent Montel committed
205
206
    QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/MailDispatcherAgent"), QStringLiteral("org.freedesktop.Akonadi.MailDispatcherAgent"), QStringLiteral(
                                              "itemDispatchStarted"), this, SLOT(itemDispatchStarted()));
Laurent Montel's avatar
Laurent Montel committed
207
    connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceStatusChanged, this, &KMKernel::instanceStatusChanged);
Laurent Montel's avatar
Laurent Montel committed
208

Laurent Montel's avatar
Laurent Montel committed
209
    connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceError, this, &KMKernel::slotInstanceError);
Laurent Montel's avatar
Laurent Montel committed
210

Laurent Montel's avatar
Laurent Montel committed
211
    connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceWarning, this, &KMKernel::slotInstanceWarning);
Laurent Montel's avatar
Laurent Montel committed
212

Laurent Montel's avatar
Laurent Montel committed
213
    connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceRemoved, this, &KMKernel::slotInstanceRemoved);
Laurent Montel's avatar
Laurent Montel committed
214

215
216
    connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceAdded, this, &KMKernel::slotInstanceAdded);

Laurent Montel's avatar
Laurent Montel committed
217
    connect(PimCommon::NetworkManager::self()->networkConfigureManager(), &QNetworkConfigurationManager::onlineStateChanged,
Laurent Montel's avatar
Laurent Montel committed
218
            this, &KMKernel::slotSystemNetworkStatusChanged);
Laurent Montel's avatar
Laurent Montel committed
219

220
221
222
223
224
    connect(KPIM::ProgressManager::instance(), &KPIM::ProgressManager::progressItemCompleted,
            this, &KMKernel::slotProgressItemCompletedOrCanceled);
    connect(KPIM::ProgressManager::instance(), &KPIM::ProgressManager::progressItemCanceled,
            this, &KMKernel::slotProgressItemCompletedOrCanceled);
    connect(identityManager(), &KIdentityManagement::IdentityManager::deleted, this, &KMKernel::slotDeleteIdentity);
Laurent Montel's avatar
Laurent Montel committed
225
226
227
    CommonKernel->registerKernelIf(this);
    CommonKernel->registerSettingsIf(this);
    CommonKernel->registerFilterIf(this);
Laurent Montel's avatar
Laurent Montel committed
228
    mFolderArchiveManager = new FolderArchiveManager(this);
229
230
    mIndexedItems = new Akonadi::Search::PIM::IndexedItems(this);
    mCheckIndexingManager = new CheckIndexingManager(mIndexedItems, this);
231
    mUnityServiceManager = new KMail::UnityServiceManager(this);
232
233
}

Laurent Montel's avatar
Laurent Montel committed
234
KMKernel::~KMKernel()
235
{
Laurent Montel's avatar
Laurent Montel committed
236
    delete mMailService;
Laurent Montel's avatar
Laurent Montel committed
237
    mMailService = nullptr;
238

Laurent Montel's avatar
Laurent Montel committed
239
    stopAgentInstance();
240
    saveConfig();
241

Laurent Montel's avatar
Laurent Montel committed
242
    delete mAutoCorrection;
Laurent Montel's avatar
Laurent Montel committed
243
    delete mMailCommonSettings;
Laurent Montel's avatar
Laurent Montel committed
244
    mySelf = nullptr;
245
246
}

Laurent Montel's avatar
Laurent Montel committed
247
Akonadi::ChangeRecorder *KMKernel::folderCollectionMonitor() const
248
{
Laurent Montel's avatar
Laurent Montel committed
249
    return mFolderCollectionMonitor->monitor();
Thomas McGuire's avatar
Thomas McGuire committed
250
251
}

Laurent Montel's avatar
Laurent Montel committed
252
Akonadi::EntityTreeModel *KMKernel::entityTreeModel() const
Thomas McGuire's avatar
Thomas McGuire committed
253
{
Laurent Montel's avatar
Laurent Montel committed
254
    return mEntityTreeModel;
Thomas McGuire's avatar
Thomas McGuire committed
255
256
}

Laurent Montel's avatar
Laurent Montel committed
257
Akonadi::EntityMimeTypeFilterModel *KMKernel::collectionModel() const
258
{
Laurent Montel's avatar
Laurent Montel committed
259
    return mCollectionModel;
260
261
}

262
263
void KMKernel::setupDBus()
{
Laurent Montel's avatar
Laurent Montel committed
264
    (void)new KmailAdaptor(this);
265
    QDBusConnection::sessionBus().registerObject(QStringLiteral("/KMail"), this);
Laurent Montel's avatar
Laurent Montel committed
266
    mMailService = new MailServiceImpl();
267
268
}

269
static QUrl makeAbsoluteUrl(const QString &str, const QString &cwd)
270
{
Milian Wolff's avatar
Milian Wolff committed
271
    return QUrl::fromUserInput(str, cwd, QUrl::AssumeLocalFile);
272
273
}

274
bool KMKernel::handleCommandLine(bool noArgsOpensReader, const QStringList &args, const QString &workingDir)
275
{
Laurent Montel's avatar
Laurent Montel committed
276
277
    QString to, cc, bcc, subj, body, inReplyTo, replyTo;
    QStringList customHeaders;
Laurent Montel's avatar
KUrl--    
Laurent Montel committed
278
    QUrl messageFile;
279
    QList<QUrl> attachURLs;
280
    QString identity;
281
    bool startInTray = false;
Laurent Montel's avatar
Laurent Montel committed
282
283
284
285
286
287
    bool mailto = false;
    bool checkMail = false;
    bool viewOnly = false;
    bool calledWithSession = false; // for ignoring '-session foo'

    // process args:
288
289
    QCommandLineParser parser;
    kmail_options(&parser);
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    QStringList newargs;
    bool addAttachmentAttribute = false;
    for (const QString &argument : qAsConst(args)) {
        if (argument == QLatin1String("--attach")) {
            addAttachmentAttribute = true;
        } else {
            if (argument.startsWith(QLatin1String("--"))) {
                addAttachmentAttribute = false;
            }
            if (argument.contains(QLatin1Char('@')) || argument.startsWith(QLatin1String("mailto:"))) { //address mustn't be trade as a attachment
                addAttachmentAttribute = false;
            }
            if (addAttachmentAttribute) {
                newargs.append(QStringLiteral("--attach"));
                newargs.append(argument);
            } else {
                newargs.append(argument);
            }
        }
    }

    parser.process(newargs);
312
313
    if (parser.isSet(QStringLiteral("subject"))) {
        subj = parser.value(QStringLiteral("subject"));
Laurent Montel's avatar
Laurent Montel committed
314
315
316
317
318
319
320
        // if kmail is called with 'kmail -session abc' then this doesn't mean
        // that the user wants to send a message with subject "ession" but
        // (most likely) that the user clicked on KMail's system tray applet
        // which results in KMKernel::raise() calling "kmail kmail newInstance"
        // via D-Bus which apparently executes the application with the original
        // command line arguments and those include "-session ..." if
        // kmail/kontact was restored by session management
321
        if (subj == QLatin1String("ession")) {
Laurent Montel's avatar
Laurent Montel committed
322
323
            subj.clear();
            calledWithSession = true;
Laurent Montel's avatar
Laurent Montel committed
324
        } else {
Laurent Montel's avatar
Laurent Montel committed
325
            mailto = true;
Laurent Montel's avatar
Laurent Montel committed
326
        }
327
    }
Laurent Montel's avatar
Laurent Montel committed
328

329
    if (parser.isSet(QStringLiteral("cc"))) {
Laurent Montel's avatar
Laurent Montel committed
330
        mailto = true;
331
        cc = parser.value(QStringLiteral("cc"));
332
333
    }

334
    if (parser.isSet(QStringLiteral("bcc"))) {
Laurent Montel's avatar
Laurent Montel committed
335
        mailto = true;
336
        bcc = parser.value(QStringLiteral("bcc"));
Laurent Montel's avatar
Laurent Montel committed
337
    }
338

339
    if (parser.isSet(QStringLiteral("replyTo"))) {
Laurent Montel's avatar
Laurent Montel committed
340
        mailto = true;
341
        replyTo = parser.value(QStringLiteral("replyTo"));
Laurent Montel's avatar
Laurent Montel committed
342
343
    }

344
    if (parser.isSet(QStringLiteral("msg"))) {
Laurent Montel's avatar
Laurent Montel committed
345
        mailto = true;
346
        const QString file = parser.value(QStringLiteral("msg"));
347
        messageFile = makeAbsoluteUrl(file, workingDir);
Laurent Montel's avatar
Laurent Montel committed
348
349
    }

350
    if (parser.isSet(QStringLiteral("body"))) {
Laurent Montel's avatar
Laurent Montel committed
351
        mailto = true;
352
        body = parser.value(QStringLiteral("body"));
Laurent Montel's avatar
Laurent Montel committed
353
354
    }

355
    const QStringList attachList = parser.values(QStringLiteral("attach"));
Laurent Montel's avatar
Laurent Montel committed
356
    if (!attachList.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
357
358
        mailto = true;
        QStringList::ConstIterator end = attachList.constEnd();
Laurent Montel's avatar
Laurent Montel committed
359
        for (QStringList::ConstIterator it = attachList.constBegin();
Laurent Montel's avatar
Laurent Montel committed
360
             it != end; ++it) {
Laurent Montel's avatar
Laurent Montel committed
361
            if (!(*it).isEmpty()) {
362
                if ((*it) != QLatin1String("--")) {
363
                    attachURLs.append(makeAbsoluteUrl(*it, workingDir));
364
                }
Laurent Montel's avatar
Laurent Montel committed
365
366
367
368
            }
        }
    }

369
    customHeaders = parser.values(QStringLiteral("header"));
Laurent Montel's avatar
Laurent Montel committed
370

371
    if (parser.isSet(QStringLiteral("composer"))) {
Laurent Montel's avatar
Laurent Montel committed
372
        mailto = true;
Laurent Montel's avatar
Laurent Montel committed
373
    }
Laurent Montel's avatar
Laurent Montel committed
374

375
    if (parser.isSet(QStringLiteral("check"))) {
Laurent Montel's avatar
Laurent Montel committed
376
        checkMail = true;
Laurent Montel's avatar
Laurent Montel committed
377
    }
Laurent Montel's avatar
Laurent Montel committed
378

Laurent Montel's avatar
Laurent Montel committed
379
    if (parser.isSet(QStringLiteral("startintray"))) {
380
381
382
383
        KMailSettings::self()->setSystemTrayEnabled(true);
        startInTray = true;
    }

384
385
386
387
    if (parser.isSet(QStringLiteral("identity"))) {
        identity = parser.value(QStringLiteral("identity"));
    }

388
    if (parser.isSet(QStringLiteral("view"))) {
Laurent Montel's avatar
Laurent Montel committed
389
        viewOnly = true;
Laurent Montel's avatar
Laurent Montel committed
390
391
        const QString filename
            = parser.value(QStringLiteral("view"));
Laurent Montel's avatar
Laurent Montel committed
392
        messageFile = QUrl::fromUserInput(filename, workingDir);
Laurent Montel's avatar
Laurent Montel committed
393
394
    }

Laurent Montel's avatar
Laurent Montel committed
395
    if (!calledWithSession) {
Laurent Montel's avatar
Laurent Montel committed
396
397
        // only read additional command line arguments if kmail/kontact is
        // not called with "-session foo"
Laurent Montel's avatar
Laurent Montel committed
398
399
        const QStringList lstPositionalArguments = parser.positionalArguments();
        for (const QString &arg : lstPositionalArguments) {
Laurent Montel's avatar
Laurent Montel committed
400
            if (arg.startsWith(QLatin1String("mailto:"), Qt::CaseInsensitive)) {
401
                const QUrl urlDecoded(QUrl::fromPercentEncoding(arg.toUtf8()));
Laurent Montel's avatar
Laurent Montel committed
402
                const QVector<QPair<QString, QString> > values = MessageCore::StringUtil::parseMailtoUrl(urlDecoded);
403
                QString previousKey;
404
405
406
                for (int i = 0; i < values.count(); ++i) {
                    const QPair<QString, QString> element = values.at(i);
                    const QString key = element.first.toLower();
407
                    if (key == QLatin1String("to")) {
408
409
                        if (!element.second.isEmpty()) {
                            to += element.second + QStringLiteral(", ");
410
                        }
411
                        previousKey.clear();
412
                    } else if (key == QLatin1String("cc")) {
413
414
                        if (!element.second.isEmpty()) {
                            cc += element.second + QStringLiteral(", ");
415
                        }
416
                        previousKey.clear();
417
                    } else if (key == QLatin1String("bcc")) {
418
419
                        if (!element.second.isEmpty()) {
                            bcc += element.second + QStringLiteral(", ");
420
                        }
421
                        previousKey.clear();
422
                    } else if (key == QLatin1String("subject")) {
423
                        subj = element.second;
424
                        previousKey.clear();
425
                    } else if (key == QLatin1String("body")) {
426
                        body = element.second;
427
                        previousKey = key;
428
                    } else if (key == QLatin1String("in-reply-to")) {
429
                        inReplyTo = element.second;
430
                        previousKey.clear();
431
                    } else if (key == QLatin1String("attachment") || key == QLatin1String("attach")) {
432
433
                        if (!element.second.isEmpty()) {
                            attachURLs << makeAbsoluteUrl(element.second, workingDir);
434
                        }
435
436
437
438
439
440
                        previousKey.clear();
                    } else {
                        qCWarning(KMAIL_LOG) << "unknown key" << key;
                        //Workaround: https://bugs.kde.org/show_bug.cgi?id=390939
                        //QMap<QString, QString> parseMailtoUrl(const QUrl &url) parses correctly url
                        //But if we have a "&" unknown key we lost it.
441
                        if (previousKey == QLatin1String("body")) {
442
                            body += QLatin1Char('&') + key + QLatin1Char('=') + element.second;
443
                        }
444
                        //Don't clear previous key.
445
                    }
446
                }
Laurent Montel's avatar
Laurent Montel committed
447
            } else {
448
                QUrl url(arg);
Laurent Montel's avatar
Laurent Montel committed
449
                if (url.isValid() && !url.scheme().isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
450
                    attachURLs += url;
Laurent Montel's avatar
Laurent Montel committed
451
                } else {
452
                    to += arg + QStringLiteral(", ");
Laurent Montel's avatar
Laurent Montel committed
453
                }
Laurent Montel's avatar
Laurent Montel committed
454
455
456
            }
            mailto = true;
        }
Laurent Montel's avatar
Laurent Montel committed
457
        if (!to.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
458
            // cut off the superfluous trailing ", "
459
            to.chop(2);
Laurent Montel's avatar
Laurent Montel committed
460
461
462
        }
    }

Laurent Montel's avatar
Laurent Montel committed
463
    if (!noArgsOpensReader && !mailto && !checkMail && !viewOnly) {
Laurent Montel's avatar
Laurent Montel committed
464
        return false;
Laurent Montel's avatar
Laurent Montel committed
465
    }
Laurent Montel's avatar
Laurent Montel committed
466

Laurent Montel's avatar
Laurent Montel committed
467
    if (viewOnly) {
468
        viewMessage(messageFile);
Laurent Montel's avatar
Laurent Montel committed
469
    } else {
470
        action(mailto, checkMail, startInTray, to, cc, bcc, subj, body, messageFile,
471
               attachURLs, customHeaders, replyTo, inReplyTo, identity);
Laurent Montel's avatar
Laurent Montel committed
472
    }
Laurent Montel's avatar
Laurent Montel committed
473
    return true;
474
}
475

476
/********************************************************************/
Laurent Montel's avatar
Port++    
Laurent Montel committed
477
/*             D-Bus-callable, and command line actions              */
478
/********************************************************************/
Laurent Montel's avatar
Laurent Montel committed
479
void KMKernel::checkMail()  //might create a new reader but won't show!!
480
{
Laurent Montel's avatar
Laurent Montel committed
481
    if (!kmkernel->askToGoOnline()) {
Laurent Montel's avatar
Laurent Montel committed
482
        return;
Laurent Montel's avatar
Laurent Montel committed
483
    }
Laurent Montel's avatar
Laurent Montel committed
484

485
    const QString resourceGroupPattern(QStringLiteral("Resource %1"));
Laurent Montel's avatar
Laurent Montel committed
486
487

    const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
Laurent Montel's avatar
Laurent Montel committed
488
    for (Akonadi::AgentInstance type : lst) {
Laurent Montel's avatar
Laurent Montel committed
489
        const QString id = type.identifier();
Laurent Montel's avatar
Laurent Montel committed
490
491
492
493
494
495
        KConfigGroup group(KMKernel::config(), resourceGroupPattern.arg(id));
        if (group.readEntry("IncludeInManualChecks", true)) {
            if (!type.isOnline()) {
                type.setIsOnline(true);
            }
            if (mResourcesBeingChecked.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
496
                qCDebug(KMAIL_LOG) << "Starting manual mail check";
Laurent Montel's avatar
Laurent Montel committed
497
                Q_EMIT startCheckMail();
Laurent Montel's avatar
Laurent Montel committed
498
            }
Thomas McGuire's avatar
Thomas McGuire committed
499

Laurent Montel's avatar
Laurent Montel committed
500
501
            if (!mResourcesBeingChecked.contains(id)) {
                mResourcesBeingChecked.append(id);
Laurent Montel's avatar
Laurent Montel committed
502
503
504
            }
            type.synchronize();
        }
505
    }
506
507
}

508
509
void KMKernel::openReader()
{
510
    openReader(false, false);
511
512
}

Laurent Montel's avatar
Laurent Montel committed
513
QStringList KMKernel::accounts() const
Waldo Bastian's avatar
Waldo Bastian committed
514
{
Laurent Montel's avatar
Laurent Montel committed
515
516
    QStringList accountLst;
    const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
517
    accountLst.reserve(lst.count());
Laurent Montel's avatar
Laurent Montel committed
518
    for (const Akonadi::AgentInstance &type : lst) {
Laurent Montel's avatar
Laurent Montel committed
519
520
        // Explicitly make a copy, as we're not changing values of the list but only
        // the local copy which is passed to action.
Laurent Montel's avatar
Laurent Montel committed
521
        accountLst << type.identifier();
Laurent Montel's avatar
Laurent Montel committed
522
523
    }
    return accountLst;
Waldo Bastian's avatar
Waldo Bastian committed
524
525
}

Laurent Montel's avatar
Laurent Montel committed
526
void KMKernel::checkAccount(const QString &account)   //might create a new reader but won't show!!
Waldo Bastian's avatar
Waldo Bastian committed
527
{
Laurent Montel's avatar
Laurent Montel committed
528
    if (account.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
529
        checkMail();
Laurent Montel's avatar
Laurent Montel committed
530
531
532
    } else {
        Akonadi::AgentInstance agent = Akonadi::AgentManager::self()->instance(account);
        if (agent.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
533
            agent.synchronize();
Laurent Montel's avatar
Laurent Montel committed
534
        } else {
Laurent Montel's avatar
Laurent Montel committed
535
            qCDebug(KMAIL_LOG) << "- account with name '" << account << "' not found";
Laurent Montel's avatar
Laurent Montel committed
536
        }
Laurent Montel's avatar
Laurent Montel committed
537
    }
Waldo Bastian's avatar
Waldo Bastian committed
538
539
}

540
void KMKernel::openReader(bool onlyCheck, bool startInTray)
541
{
Laurent Montel's avatar
Laurent Montel committed
542
    KMainWindow *ktmw = nullptr;
543

Laurent Montel's avatar
Laurent Montel committed
544
545
    const auto lst = KMainWindow::memberList();
    for (KMainWindow *window : lst) {
Laurent Montel's avatar
Laurent Montel committed
546
        if (::qobject_cast<KMMainWin *>(window)) {
Laurent Montel's avatar
Laurent Montel committed
547
548
549
550
            ktmw = window;
            break;
        }
    }
551

Laurent Montel's avatar
Laurent Montel committed
552
553
    bool activate;
    if (ktmw) {
554
        KMMainWin *win = static_cast<KMMainWin *>(ktmw);
Laurent Montel's avatar
Laurent Montel committed
555
        activate = !onlyCheck; // existing window: only activate if not --check
Laurent Montel's avatar
Laurent Montel committed
556
        if (activate) {
Laurent Montel's avatar
Laurent Montel committed
557
            win->showAndActivateWindow();
Laurent Montel's avatar
Laurent Montel committed
558
559
        }
    } else {
560
        KMMainWin *win = new KMMainWin;
Laurent Montel's avatar
Laurent Montel committed
561
        if (!startInTray && !KMailSettings::self()->startInTray()) {
Laurent Montel's avatar
Laurent Montel committed
562
            win->showAndActivateWindow();
Laurent Montel's avatar
Laurent Montel committed
563
        }
Laurent Montel's avatar
Laurent Montel committed
564
565
        activate = false; // new window: no explicit activation (#73591)
    }
566
567
}

Laurent Montel's avatar
Laurent Montel committed
568
569
void KMKernel::openComposer(const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, bool hidden, const QString &messageFile, const QStringList &attachmentPaths, const QStringList &customHeaders, const QString &replyTo, const QString &inReplyTo,
                            const QString &identity)
Laurent Montel's avatar
Laurent Montel committed
570
{
Laurent Montel's avatar
Laurent Montel committed
571
572
573
574
575
576
577
578
579
580
    const OpenComposerSettings settings(to, cc,
                                        bcc, subject,
                                        body, hidden,
                                        messageFile,
                                        attachmentPaths,
                                        customHeaders,
                                        replyTo, inReplyTo, identity);
    OpenComposerJob *job = new OpenComposerJob(this);
    job->setOpenComposerSettings(settings);
    job->start();
581
582
}

Laurent Montel's avatar
Laurent Montel committed
583
584
void KMKernel::openComposer(const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, bool hidden, const QString &attachName, const QByteArray &attachCte, const QByteArray &attachData, const QByteArray &attachType, const QByteArray &attachSubType,
                            const QByteArray &attachParamAttr, const QString &attachParamValue, const QByteArray &attachContDisp, const QByteArray &attachCharset, unsigned int identity)
585
{
586
587
588
589
590
    fillComposer(hidden, to, cc, bcc,
                 subject, body,
                 attachName, attachCte, attachData,
                 attachType, attachSubType, attachParamAttr, attachParamValue,
                 attachContDisp, attachCharset, identity, false);
591
592
}

Laurent Montel's avatar
Laurent Montel committed
593
594
void KMKernel::openComposer(const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, const QString &attachName, const QByteArray &attachCte, const QByteArray &attachData, const QByteArray &attachType, const QByteArray &attachSubType,
                            const QByteArray &attachParamAttr, const QString &attachParamValue, const QByteArray &attachContDisp, const QByteArray &attachCharset, unsigned int identity)
595
{
596
    fillComposer(false, to, cc, bcc,
597
598
599
                 subject, body,
                 attachName, attachCte, attachData,
                 attachType, attachSubType, attachParamAttr, attachParamValue,
600
                 attachContDisp, attachCharset, identity, true);
601
602
}

Laurent Montel's avatar
Laurent Montel committed
603
604
void KMKernel::fillComposer(bool hidden, const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, const QString &attachName, const QByteArray &attachCte, const QByteArray &attachData, const QByteArray &attachType, const QByteArray &attachSubType,
                            const QByteArray &attachParamAttr, const QString &attachParamValue, const QByteArray &attachContDisp, const QByteArray &attachCharset, unsigned int identity, bool forceShowWindow)
605
{
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
    const FillComposerJobSettings settings(hidden,
                                           to,
                                           cc,
                                           bcc,
                                           subject,
                                           body,
                                           attachName,
                                           attachCte,
                                           attachData,
                                           attachType,
                                           attachSubType,
                                           attachParamAttr,
                                           attachParamValue,
                                           attachContDisp,
                                           attachCharset,
                                           identity,
                                           forceShowWindow);
    FillComposerJob *job = new FillComposerJob;
    job->setSettings(settings);
    job->start();
626
627
}

Laurent Montel's avatar
Laurent Montel committed
628
void KMKernel::openComposer(const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, bool hidden)
629
{
Laurent Montel's avatar
Laurent Montel committed
630
    const OpenComposerHiddenJobSettings settings(to, cc,
Laurent Montel's avatar
Laurent Montel committed
631
632
633
                                                 bcc,
                                                 subject,
                                                 body, hidden);
Laurent Montel's avatar
Laurent Montel committed
634
635
636
    OpenComposerHiddenJob *job = new OpenComposerHiddenJob(this);
    job->setSettings(settings);
    job->start();
637
638
}

Laurent Montel's avatar
Laurent Montel committed
639
void KMKernel::newMessage(const QString &to, const QString &cc, const QString &bcc, bool hidden, bool useFolderId, const QString & /*messageFile*/, const QString &_attachURL)
640
{
Laurent Montel's avatar
Laurent Montel committed
641
    QSharedPointer<FolderSettings> folder;
Laurent Montel's avatar
Laurent Montel committed
642
    Akonadi::Collection col;
Laurent Montel's avatar
Laurent Montel committed
643
    uint id = 0;
Laurent Montel's avatar
Laurent Montel committed
644
    if (useFolderId) {
Laurent Montel's avatar
Laurent Montel committed
645
646
647
        //create message with required folder identity
        folder = currentFolderCollection();
        id = folder ? folder->identity() : 0;
Laurent Montel's avatar
Laurent Montel committed
648
        col = currentCollection();
Laurent Montel's avatar
Laurent Montel committed
649
    }
Laurent Montel's avatar
Laurent Montel committed
650

Laurent Montel's avatar
Laurent Montel committed
651
652
653
654
    const NewMessageJobSettings settings(to,
                                         cc,
                                         bcc,
                                         hidden,
Laurent Montel's avatar
Laurent Montel committed
655
656
657
658
                                         _attachURL,
                                         folder,
                                         id,
                                         col);
Laurent Montel's avatar
Laurent Montel committed
659

Laurent Montel's avatar
Laurent Montel committed
660
661
662
    NewMessageJob *job = new NewMessageJob(this);
    job->setNewMessageJobSettings(settings);
    job->start();
663
664
}

665
666
void KMKernel::viewMessage(const QUrl &url)
{
Laurent Montel's avatar
Laurent Montel committed
667
    KMOpenMsgCommand *openCommand = new KMOpenMsgCommand(nullptr, url);
668
669
670
671

    openCommand->start();
}

Laurent Montel's avatar
Laurent Montel committed
672
int KMKernel::viewMessage(const QString &messageFile)
673
{
Laurent Montel's avatar
Laurent Montel committed
674
    KMOpenMsgCommand *openCommand = new KMOpenMsgCommand(nullptr, QUrl::fromLocalFile(messageFile));
675

Laurent Montel's avatar
Laurent Montel committed
676
677
    openCommand->start();
    return 1;
678
679
}

680
681
void KMKernel::raise()
{
682
683
    QDBusInterface iface(QStringLiteral("org.kde.kmail"), QStringLiteral("/MainApplication"),
                         QStringLiteral("org.kde.PIMUniqueApplication"),
Laurent Montel's avatar
Laurent Montel committed
684
                         QDBusConnection::sessionBus());
Laurent Montel's avatar
Laurent Montel committed
685
    QDBusReply<int> reply;
686
    if (!iface.isValid() || !(reply = iface.call(QStringLiteral("newInstance"))).isValid()) {
Laurent Montel's avatar
Laurent Montel committed
687
        QDBusError err = iface.lastError();
Laurent Montel's avatar
Laurent Montel committed
688
        qCritical() << "Communication problem with KMail. "
Laurent Montel's avatar
Laurent Montel committed
689
                    << "Error message was:" << err.name() << ": \"" << err.message() << "\"";
Laurent Montel's avatar
Laurent Montel committed
690
    }
691
692
}

Laurent Montel's avatar
Laurent Montel committed
693
bool KMKernel::showMail(qint64 serialNumber)
694
{
Laurent Montel's avatar
Laurent Montel committed
695
    KMMainWidget *mainWidget = nullptr;
Andreas Gungl's avatar
Andreas Gungl committed
696

Laurent Montel's avatar
Laurent Montel committed
697
    // First look for a KMainWindow.
Laurent Montel's avatar
Laurent Montel committed
698
699
    const auto lst = KMainWindow::memberList();
    for (KMainWindow *window : lst) {
Laurent Montel's avatar
Laurent Montel committed
700
        // Then look for a KMMainWidget.
Laurent Montel's avatar
Laurent Montel committed
701
702
        QList<KMMainWidget *> l = window->findChildren<KMMainWidget *>();
        if (!l.isEmpty() && l.first()) {
Laurent Montel's avatar
Laurent Montel committed
703
            mainWidget = l.first();
Laurent Montel's avatar
Laurent Montel committed
704
            if (window->isActiveWindow()) {
Laurent Montel's avatar
Laurent Montel committed
705
                break;
Laurent Montel's avatar
Laurent Montel committed
706
            }
Laurent Montel's avatar
Laurent Montel committed
707
        }
708
    }
Laurent Montel's avatar
Laurent Montel committed
709
710
    if (mainWidget) {
        Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(Akonadi::Item(serialNumber), this);
Laurent Montel's avatar
Laurent Montel committed
711
        job->fetchScope().fetchFullPayload();
712
        job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
Laurent Montel's avatar
Laurent Montel committed
713
714
715
        if (job->exec()) {
            if (job->items().count() >= 1) {
                KMReaderMainWin *win = new KMReaderMainWin(MessageViewer::Viewer::UseGlobalSetting, false);
716
                const auto item = job->items().at(0);
Laurent Montel's avatar
Laurent Montel committed
717
                win->showMessage(MessageCore::MessageCoreSettings::self()->overrideCharacterEncoding(),
718
                                 item, item.parentCollection());
Laurent Montel's avatar
Laurent Montel committed
719
                win->showAndActivateWindow();
Laurent Montel's avatar
Laurent Montel committed
720
721
722
                return true;
            }
        }
Laurent Montel's avatar
Port++    
Laurent Montel committed
723
    }
Laurent Montel's avatar
Laurent Montel committed
724
    return false;
725
726
}

727
728
void KMKernel::pauseBackgroundJobs()
{
Laurent Montel's avatar
Laurent Montel committed
729
730
    mBackgroundTasksTimer->stop();
    mJobScheduler->pause();
731
732
733
734
}

void KMKernel::resumeBackgroundJobs()
{
Laurent Montel's avatar
Laurent Montel committed
735
    mJobScheduler->resume();
Laurent Montel's avatar
Laurent Montel committed
736
    mBackgroundTasksTimer->start(4 * 60 * 60 * 1000);
737
}
738

Matt Douhan's avatar
Matt Douhan committed
739
740
void KMKernel::stopNetworkJobs()
{
Laurent Montel's avatar
Laurent Montel committed
741
    if (KMailSettings::self()->networkState() == KMailSettings::EnumNetworkState::Offline) {
Laurent Montel's avatar
Laurent Montel committed
742
        return;
Laurent Montel's avatar
Laurent Montel committed
743
    }
Matt Douhan's avatar
Matt Douhan committed
744

Laurent Montel's avatar
Laurent Montel committed
745
    setAccountStatus(false);
746

Laurent Montel's avatar
Laurent Montel committed
747
    KMailSettings::setNetworkState(KMailSettings::EnumNetworkState::Offline);
Laurent Montel's avatar
Laurent Montel committed
748
    BroadcastStatus::instance()->setStatusMsg(i18n("KMail is set to be offline; all network jobs are suspended"));
Laurent Montel's avatar
Laurent Montel committed
749
    Q_EMIT onlineStatusChanged((KMailSettings::EnumNetworkState::type)KMailSettings::networkState());
750
751
}

752
void KMKernel::setAccountStatus(bool goOnline)
Matt Douhan's avatar
Matt Douhan committed
753
{
Laurent Montel's avatar
Laurent Montel committed
754
    const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances(false);
Laurent Montel's avatar
Laurent Montel committed
755
    for (Akonadi::AgentInstance type : lst) {
Laurent Montel's avatar
Laurent Montel committed
756
        const QString identifier(type.identifier());
Laurent Montel's avatar
Laurent Montel committed
757
758
        if (PimCommon::Util::isImapResource(identifier)
            || identifier.contains(POP3_RESOURCE_IDENTIFIER)
Laurent Montel's avatar
Laurent Montel committed
759
760
            || identifier.contains(QLatin1String("akonadi_maildispatcher_agent"))
            || type.type().capabilities().contains(QLatin1String("NeedsNetwork"))) {
Laurent Montel's avatar
Laurent Montel committed
761
            type.setIsOnline(goOnline);
Laurent Montel's avatar
Laurent Montel committed
762
        }
763
    }
Laurent Montel's avatar
Laurent Montel committed
764
    if (goOnline && MessageComposer::MessageComposerSettings::self()->sendImmediate()) {
765
766
        const auto col =