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 22
#include <PimCommonAkonadi/RecentAddresses>
using PimCommon::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

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

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

Laurent Montel's avatar
Laurent Montel committed
50
#include <MessageCore/MessageCoreSettings>
Laurent Montel's avatar
Laurent Montel committed
51
#include "messagelistsettings.h"
Laurent Montel's avatar
Laurent Montel committed
52
#include "gravatarsettings.h"
Laurent Montel's avatar
Laurent Montel committed
53
#include <MessageList/MessageListUtil>
Laurent Montel's avatar
Laurent Montel committed
54
#include <MessageViewer/MessageViewerSettings>
Laurent Montel's avatar
Laurent Montel committed
55 56 57 58 59 60
#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
61
#include <PimCommon/NetworkManager>
62

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

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

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

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

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

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

100
#include <MailCommon/ResourceReadConfigFile>
101

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

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

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

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

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

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

    mySelf = this;
    the_firstInstance = true;

Laurent Montel's avatar
Laurent Montel committed
147
    mFilterEditDialog = nullptr;
Laurent Montel's avatar
Laurent Montel committed
148 149 150 151 152
    // 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
153
    KMailSettings::self();
Laurent Montel's avatar
Laurent Montel committed
154 155

    mAutoCorrection = new PimCommon::AutoCorrection();
Laurent Montel's avatar
Laurent Montel committed
156
    KMime::setUseOutlookAttachmentEncoding(MessageComposer::MessageComposerSettings::self()->outlookCompatibleAttachments());
Laurent Montel's avatar
Laurent Montel committed
157 158

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

    // 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
169 170
    const QByteArray netCodecLower = mNetCodec->name().toLower();
    if (netCodecLower == "eucjp"
Laurent Montel's avatar
Laurent Montel committed
171
#if defined Q_OS_WIN || defined Q_OS_MACX
Laurent Montel's avatar
Laurent Montel committed
172
        || netCodecLower == "shift-jis"     // OK?
Laurent Montel's avatar
Laurent Montel committed
173
#endif
Laurent Montel's avatar
Laurent Montel committed
174
        ) {
Laurent Montel's avatar
Laurent Montel committed
175
        mNetCodec = QTextCodec::codecForName("jis7");
Laurent Montel's avatar
Laurent Montel committed
176 177 178
    }
    // until here ================================================

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

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

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

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

Laurent Montel's avatar
Laurent Montel committed
189 190 191 192 193 194
    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
195

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

Laurent Montel's avatar
Laurent Montel committed
199 200
    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
201

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

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

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

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

212 213
    connect(Akonadi::AgentManager::self(), &Akonadi::AgentManager::instanceAdded, this, &KMKernel::slotInstanceAdded);

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

217 218 219 220 221
    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
222 223 224
    CommonKernel->registerKernelIf(this);
    CommonKernel->registerSettingsIf(this);
    CommonKernel->registerFilterIf(this);
Laurent Montel's avatar
Laurent Montel committed
225

226 227
    mIndexedItems = new Akonadi::Search::PIM::IndexedItems(this);
    mCheckIndexingManager = new CheckIndexingManager(mIndexedItems, this);
228
    mUnityServiceManager = new KMail::UnityServiceManager(this);
229 230
}

Laurent Montel's avatar
Laurent Montel committed
231
KMKernel::~KMKernel()
232
{
Laurent Montel's avatar
Laurent Montel committed
233
    delete mMailService;
Laurent Montel's avatar
Laurent Montel committed
234
    mMailService = nullptr;
235

Laurent Montel's avatar
Laurent Montel committed
236
    stopAgentInstance();
237
    saveConfig();
238

Laurent Montel's avatar
Laurent Montel committed
239
    delete mAutoCorrection;
Laurent Montel's avatar
Laurent Montel committed
240
    delete mMailCommonSettings;
Laurent Montel's avatar
Laurent Montel committed
241
    mySelf = nullptr;
242 243
}

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

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

Laurent Montel's avatar
Laurent Montel committed
254
Akonadi::EntityMimeTypeFilterModel *KMKernel::collectionModel() const
255
{
Laurent Montel's avatar
Laurent Montel committed
256
    return mCollectionModel;
257 258
}

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

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

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

    // process args:
285 286
    QCommandLineParser parser;
    kmail_options(&parser);
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
    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);
309 310
    if (parser.isSet(QStringLiteral("subject"))) {
        subj = parser.value(QStringLiteral("subject"));
Laurent Montel's avatar
Laurent Montel committed
311 312 313 314 315 316 317
        // 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
318
        if (subj == QLatin1String("ession")) {
Laurent Montel's avatar
Laurent Montel committed
319 320
            subj.clear();
            calledWithSession = true;
Laurent Montel's avatar
Laurent Montel committed
321
        } else {
Laurent Montel's avatar
Laurent Montel committed
322
            mailto = true;
Laurent Montel's avatar
Laurent Montel committed
323
        }
324
    }
Laurent Montel's avatar
Laurent Montel committed
325

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

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

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

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

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

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

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

368
    if (parser.isSet(QStringLiteral("composer"))) {
Laurent Montel's avatar
Laurent Montel committed
369
        mailto = true;
Laurent Montel's avatar
Laurent Montel committed
370
    }
Laurent Montel's avatar
Laurent Montel committed
371

372
    if (parser.isSet(QStringLiteral("check"))) {
Laurent Montel's avatar
Laurent Montel committed
373
        checkMail = true;
Laurent Montel's avatar
Laurent Montel committed
374
    }
Laurent Montel's avatar
Laurent Montel committed
375

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

381 382 383 384
    if (parser.isSet(QStringLiteral("identity"))) {
        identity = parser.value(QStringLiteral("identity"));
    }

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

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

Laurent Montel's avatar
Laurent Montel committed
460
    if (!noArgsOpensReader && !mailto && !checkMail && !viewOnly) {
Laurent Montel's avatar
Laurent Montel committed
461
        return false;
Laurent Montel's avatar
Laurent Montel committed
462
    }
Laurent Montel's avatar
Laurent Montel committed
463

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

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

482
    const QString resourceGroupPattern(QStringLiteral("Resource %1"));
Laurent Montel's avatar
Laurent Montel committed
483 484

    const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
Laurent Montel's avatar
Laurent Montel committed
485
    for (Akonadi::AgentInstance type : lst) {
Laurent Montel's avatar
Laurent Montel committed
486
        const QString id = type.identifier();
Laurent Montel's avatar
Laurent Montel committed
487 488 489 490 491 492
        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
493
                qCDebug(KMAIL_LOG) << "Starting manual mail check";
Laurent Montel's avatar
Laurent Montel committed
494
                Q_EMIT startCheckMail();
Laurent Montel's avatar
Laurent Montel committed
495
            }
Thomas McGuire's avatar
Thomas McGuire committed
496

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

505 506
void KMKernel::openReader()
{
507
    openReader(false, false);
508 509
}

Laurent Montel's avatar
Laurent Montel committed
510
QStringList KMKernel::accounts() const
Waldo Bastian's avatar
Waldo Bastian committed
511
{
Laurent Montel's avatar
Laurent Montel committed
512 513
    QStringList accountLst;
    const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
514
    accountLst.reserve(lst.count());
Laurent Montel's avatar
Laurent Montel committed
515
    for (const Akonadi::AgentInstance &type : lst) {
Laurent Montel's avatar
Laurent Montel committed
516 517
        // 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
518
        accountLst << type.identifier();
Laurent Montel's avatar
Laurent Montel committed
519 520
    }
    return accountLst;
Waldo Bastian's avatar
Waldo Bastian committed
521 522
}

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

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

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

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

Laurent Montel's avatar
Laurent Montel committed
565 566
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
567
{
Laurent Montel's avatar
Laurent Montel committed
568 569 570 571 572 573 574 575 576 577
    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();
578 579
}

Laurent Montel's avatar
Laurent Montel committed
580 581
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)
582
{
583 584 585 586 587
    fillComposer(hidden, to, cc, bcc,
                 subject, body,
                 attachName, attachCte, attachData,
                 attachType, attachSubType, attachParamAttr, attachParamValue,
                 attachContDisp, attachCharset, identity, false);
588 589
}

Laurent Montel's avatar
Laurent Montel committed
590 591
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)
592
{
593
    fillComposer(false, to, cc, bcc,
594 595 596
                 subject, body,
                 attachName, attachCte, attachData,
                 attachType, attachSubType, attachParamAttr, attachParamValue,
597
                 attachContDisp, attachCharset, identity, true);
598 599
}

Laurent Montel's avatar
Laurent Montel committed
600 601
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)
602
{
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
    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();
623 624
}

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

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

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

Laurent Montel's avatar
Laurent Montel committed
657 658 659
    NewMessageJob *job = new NewMessageJob(this);
    job->setNewMessageJobSettings(settings);
    job->start();
660 661
}

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

    openCommand->start();
}

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

Laurent Montel's avatar
Laurent Montel committed
673 674
    openCommand->start();
    return 1;
675 676
}

677 678
void KMKernel::raise()
{
679 680
    QDBusInterface iface(QStringLiteral("org.kde.kmail"), QStringLiteral("/MainApplication"),
                         QStringLiteral("org.kde.PIMUniqueApplication"),
Laurent Montel's avatar
Laurent Montel committed
681
                         QDBusConnection::sessionBus());
Laurent Montel's avatar
Laurent Montel committed
682
    QDBusReply<int> reply;
683
    if (!iface.isValid() || !(reply = iface.call(QStringLiteral("newInstance"))).isValid()) {
Laurent Montel's avatar
Laurent Montel committed
684
        QDBusError err = iface.lastError();