kmkernel.cpp 77.7 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"
Laurent Montel's avatar
Laurent Montel committed
6
#include "libkdepim/broadcaststatus.h"
Allen Winter's avatar
Allen Winter committed
7
using KPIM::BroadcastStatus;
8
#include "kmstartup.h"
9
#include "kmmainwin.h"
Laurent Montel's avatar
Laurent Montel committed
10
#include "editor/composer.h"
11
#include "kmreadermainwin.h"
12
#include "undostack.h"
13 14
#include "kmreaderwin.h"
#include "kmmainwidget.h"
Laurent Montel's avatar
Laurent Montel committed
15
#include "libkdepim/recentaddresses.h"
16
using KPIM::RecentAddresses;
Laurent Montel's avatar
Laurent Montel committed
17
#include "configuredialog/configuredialog.h"
18
#include "kmcommands.h"
19
#include "kmsystemtray.h"
Laurent Montel's avatar
Laurent Montel committed
20
#include <MessageCore/StringUtil>
Laurent Montel's avatar
Laurent Montel committed
21
#include "mailcommon/mailutil.h"
Laurent Montel's avatar
Laurent Montel committed
22
#include "pop3settings.h"
Laurent Montel's avatar
Laurent Montel committed
23 24
#include "MailCommon/FolderTreeView"
#include "MailCommon/KMFilterDialog"
Laurent Montel's avatar
Laurent Montel committed
25
#include "mailcommonsettings_base.h"
Laurent Montel's avatar
Laurent Montel committed
26
#include "PimCommon/PimUtil"
27
#include "folderarchive/folderarchivemanager.h"
28
// kdepim includes
29
#include "kmail-version.h"
30

31
// kdepimlibs includes
Laurent Montel's avatar
Laurent Montel committed
32 33
#include <KIdentityManagement/kidentitymanagement/identity.h>
#include <KIdentityManagement/kidentitymanagement/identitymanager.h>
Laurent Montel's avatar
Laurent Montel committed
34 35 36
#include <MailTransport/mailtransport/transport.h>
#include <MailTransport/mailtransport/transportmanager.h>
#include <MailTransport/mailtransport/dispatcherinterface.h>
Laurent Montel's avatar
Laurent Montel committed
37
#include <AkonadiCore/servermanager.h>
38

Lubo Luk's avatar
Lubo Luk committed
39
#include <kwindowsystem.h>
Laurent Montel's avatar
Laurent Montel committed
40
#include "mailserviceimpl.h"
41
using KMail::MailServiceImpl;
Laurent Montel's avatar
Laurent Montel committed
42
#include "mailcommon/jobscheduler.h"
Laurent Montel's avatar
Laurent Montel committed
43

Laurent Montel's avatar
Laurent Montel committed
44
#include <MessageCore/MessageCoreSettings>
Laurent Montel's avatar
Laurent Montel committed
45
#include "messagelistsettings.h"
Laurent Montel's avatar
Laurent Montel committed
46
#include "gravatarsettings.h"
47
#include "messagelist/messagelistutil.h"
48
#include "messageviewer/messageviewersettings.h"
Laurent Montel's avatar
Laurent Montel committed
49
#include "MessageComposer/AkonadiSender"
Laurent Montel's avatar
Laurent Montel committed
50
#include "messagecomposer/messagecomposersettings.h"
Laurent Montel's avatar
Laurent Montel committed
51 52
#include "MessageComposer/MessageHelper"
#include "MessageComposer/MessageComposerSettings"
Laurent Montel's avatar
Laurent Montel committed
53 54
#include "PimCommon/PimCommonSettings"
#include "PimCommon/AutoCorrection"
55

56
#include "TemplateParser/TemplateParser"
57
#include "globalsettings_templateparser.h"
58
#include "TemplateParser/TemplatesUtil"
59

Laurent Montel's avatar
Laurent Montel committed
60
#include "mailcommon/foldercollection.h"
61
#include "editor/codec/codecmanager.h"
62

63
#include <kmessagebox.h>
64
#include <knotification.h>
Laurent Montel's avatar
Laurent Montel committed
65
#include <libkdepim/progressmanager.h>
Laurent Montel's avatar
Laurent Montel committed
66

67 68
#include <kconfig.h>
#include <kpassivepopup.h>
69
#include <kconfiggroup.h>
Laurent Montel's avatar
Laurent Montel committed
70
#include "kmail_debug.h"
Thomas McGuire's avatar
Thomas McGuire committed
71
#include <kio/jobuidelegate.h>
Volker Krause's avatar
Volker Krause committed
72
#include <kprocess.h>
73
#include <KCrash>
74

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

Laurent Montel's avatar
Laurent Montel committed
89
#include <QNetworkConfigurationManager>
Andreas Gungl's avatar
Andreas Gungl committed
90 91
#include <QDir>
#include <QWidget>
92
#include <QFileInfo>
93
#include <QtDBus/QtDBus>
Volker Krause's avatar
Volker Krause committed
94
#include <QMimeDatabase>
95

96 97 98 99 100 101 102
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
103
#include <MailCommon/ResourceReadConfigFile>
104

105
#include <kstartupinfo.h>
106
#include <kmailadaptor.h>
Laurent Montel's avatar
Laurent Montel committed
107
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
108
#include <QStandardPaths>
Laurent Montel's avatar
Laurent Montel committed
109
#include "kmailinterface.h"
Laurent Montel's avatar
Laurent Montel committed
110
#include "mailcommon/foldercollectionmonitor.h"
111
#include "imapresourcesettings.h"
Laurent Montel's avatar
++port  
Laurent Montel committed
112
#include "util.h"
Laurent Montel's avatar
Laurent Montel committed
113
#include "MailCommon/MailKernel"
114

Laurent Montel's avatar
Laurent Montel committed
115
#include "searchdialog/searchdescriptionattribute.h"
116
#include "kmail_options.h"
117

Andras Mantia's avatar
Andras Mantia committed
118 119
using namespace MailCommon;

Laurent Montel's avatar
Laurent Montel committed
120
static KMKernel *mySelf = Q_NULLPTR;
121
static bool s_askingToGoOnline = false;
Laurent Montel's avatar
Laurent Montel committed
122
static QNetworkConfigurationManager *s_networkConfigMgr = 0;
123 124 125
/********************************************************************/
/*                     Constructor and destructor                   */
/********************************************************************/
Laurent Montel's avatar
Laurent Montel committed
126
KMKernel::KMKernel(QObject *parent) :
Laurent Montel's avatar
Laurent Montel committed
127
    QObject(parent),
Laurent Montel's avatar
Laurent Montel committed
128 129 130
    mIdentityManager(Q_NULLPTR),
    mConfigureDialog(Q_NULLPTR),
    mMailService(Q_NULLPTR),
Laurent Montel's avatar
Laurent Montel committed
131
    mSystemNetworkStatus(true),
Laurent Montel's avatar
Laurent Montel committed
132
    mSystemTray(Q_NULLPTR),
133
    mDebugBaloo(false)
Laurent Montel's avatar
Laurent Montel committed
134
{
135 136
    mDebugBaloo = !qEnvironmentVariableIsEmpty("KDEPIM_BALOO_DEBUG");

Laurent Montel's avatar
Laurent Montel committed
137
    if (!s_networkConfigMgr) {
Laurent Montel's avatar
Laurent Montel committed
138
        s_networkConfigMgr = new QNetworkConfigurationManager(QCoreApplication::instance());
Laurent Montel's avatar
Laurent Montel committed
139
    }
Laurent Montel's avatar
Laurent Montel committed
140 141
    mSystemNetworkStatus = s_networkConfigMgr->isOnline();

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

    mySelf = this;
    the_firstInstance = true;

Laurent Montel's avatar
Laurent Montel committed
149 150 151 152
    the_undoStack = Q_NULLPTR;
    the_msgSender = Q_NULLPTR;
    mFilterEditDialog = Q_NULLPTR;
    mWin = Q_NULLPTR;
Laurent Montel's avatar
Laurent Montel committed
153 154 155 156 157
    // 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
158
    KMailSettings::self();
Laurent Montel's avatar
Laurent Montel committed
159

Laurent Montel's avatar
Laurent Montel committed
160
    mJobScheduler = new JobScheduler(this);
161
    mXmlGuiInstance = QStringLiteral("kmail2");
Laurent Montel's avatar
Laurent Montel committed
162 163

    mAutoCorrection = new PimCommon::AutoCorrection();
Laurent Montel's avatar
Laurent Montel committed
164
    KMime::setUseOutlookAttachmentEncoding(MessageComposer::MessageComposerSettings::self()->outlookCompatibleAttachments());
Laurent Montel's avatar
Laurent Montel committed
165 166

    // cberzan: this crap moved to CodecManager ======================
Volker Krause's avatar
Volker Krause committed
167
    mNetCodec = QTextCodec::codecForLocale();
Laurent Montel's avatar
Laurent Montel committed
168 169 170 171 172 173 174 175 176

    // 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
177 178 179 180 181
    if (mNetCodec->name().toLower() == "eucjp"
#if defined Q_OS_WIN || defined Q_OS_MACX
            || netCodec->name().toLower() == "shift-jis" // OK?
#endif
       ) {
Laurent Montel's avatar
Laurent Montel committed
182
        mNetCodec = QTextCodec::codecForName("jis7");
Laurent Montel's avatar
Laurent Montel committed
183 184 185
    }
    // until here ================================================

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

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

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

Laurent Montel's avatar
Laurent Montel committed
192
    mEntityTreeModel = new Akonadi::EntityTreeModel(folderCollectionMonitor(), this);
193
    mEntityTreeModel->setListFilter(Akonadi::CollectionFetchScope::Enabled);
Laurent Montel's avatar
Laurent Montel committed
194
    mEntityTreeModel->setItemPopulationStrategy(Akonadi::EntityTreeModel::LazyPopulation);
Laurent Montel's avatar
Laurent Montel committed
195

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

Laurent Montel's avatar
Laurent Montel committed
203 204
    connect(folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)),
            SLOT(slotCollectionChanged(Akonadi::Collection,QSet<QByteArray>)));
Laurent Montel's avatar
Laurent Montel committed
205

Laurent Montel's avatar
Laurent Montel committed
206 207
    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
208

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

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

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

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

Laurent Montel's avatar
Laurent Montel committed
218 219
    connect(s_networkConfigMgr, &QNetworkConfigurationManager::onlineStateChanged,
            this, &KMKernel::slotSystemNetworkStatusChanged);
Laurent Montel's avatar
Laurent Montel committed
220

221 222 223 224 225
    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
226 227 228
    CommonKernel->registerKernelIf(this);
    CommonKernel->registerSettingsIf(this);
    CommonKernel->registerFilterIf(this);
Laurent Montel's avatar
Laurent Montel committed
229
    mFolderArchiveManager = new FolderArchiveManager(this);
230 231
}

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

Laurent Montel's avatar
Laurent Montel committed
237
    mSystemTray = Q_NULLPTR;
Laurent Montel's avatar
Laurent Montel committed
238

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

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

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

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

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

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

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

273
bool KMKernel::handleCommandLine(bool noArgsOpensReader, const QStringList &args, const QString &workingDir)
274
{
Laurent Montel's avatar
Laurent Montel committed
275 276
    QString to, cc, bcc, subj, body, inReplyTo, replyTo;
    QStringList customHeaders;
Laurent Montel's avatar
KUrl--  
Laurent Montel committed
277
    QUrl messageFile;
278
    QList<QUrl> attachURLs;
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 287
    QCommandLineParser parser;
    kmail_options(&parser);
    parser.process(args);
288 289
    if (parser.isSet(QStringLiteral("subject"))) {
        subj = parser.value(QStringLiteral("subject"));
Laurent Montel's avatar
Laurent Montel committed
290 291 292 293 294 295 296
        // 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
297
        if (subj == QLatin1String("ession")) {
Laurent Montel's avatar
Laurent Montel committed
298 299
            subj.clear();
            calledWithSession = true;
Laurent Montel's avatar
Laurent Montel committed
300
        } else {
Laurent Montel's avatar
Laurent Montel committed
301
            mailto = true;
Laurent Montel's avatar
Laurent Montel committed
302
        }
303
    }
Laurent Montel's avatar
Laurent Montel committed
304

305
    if (parser.isSet(QStringLiteral("cc"))) {
Laurent Montel's avatar
Laurent Montel committed
306
        mailto = true;
307
        cc = parser.value(QStringLiteral("cc"));
308 309
    }

310
    if (parser.isSet(QStringLiteral("bcc"))) {
Laurent Montel's avatar
Laurent Montel committed
311
        mailto = true;
312
        bcc = parser.value(QStringLiteral("bcc"));
Laurent Montel's avatar
Laurent Montel committed
313
    }
314

315
    if (parser.isSet(QStringLiteral("replyTo"))) {
Laurent Montel's avatar
Laurent Montel committed
316
        mailto = true;
317
        replyTo = parser.value(QStringLiteral("replyTo"));
Laurent Montel's avatar
Laurent Montel committed
318 319
    }

320
    if (parser.isSet(QStringLiteral("msg"))) {
Laurent Montel's avatar
Laurent Montel committed
321
        mailto = true;
322
        const QString file = parser.value(QStringLiteral("msg"));
323
        messageFile = makeAbsoluteUrl(file, workingDir);
Laurent Montel's avatar
Laurent Montel committed
324 325
    }

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

331
    const QStringList attachList = parser.values(QStringLiteral("attach"));
Laurent Montel's avatar
Laurent Montel committed
332
    if (!attachList.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
333 334
        mailto = true;
        QStringList::ConstIterator end = attachList.constEnd();
Laurent Montel's avatar
Laurent Montel committed
335 336 337
        for (QStringList::ConstIterator it = attachList.constBegin();
                it != end; ++it) {
            if (!(*it).isEmpty()) {
338
                if ((*it) != QLatin1String("--")) {
339
                    attachURLs.append(makeAbsoluteUrl(*it, workingDir));
340
                }
Laurent Montel's avatar
Laurent Montel committed
341 342 343 344
            }
        }
    }

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

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

351
    if (parser.isSet(QStringLiteral("check"))) {
Laurent Montel's avatar
Laurent Montel committed
352
        checkMail = true;
Laurent Montel's avatar
Laurent Montel committed
353
    }
Laurent Montel's avatar
Laurent Montel committed
354

355
    if (parser.isSet(QStringLiteral("view"))) {
Laurent Montel's avatar
Laurent Montel committed
356 357
        viewOnly = true;
        const QString filename =
358
            parser.value(QStringLiteral("view"));
Laurent Montel's avatar
KUrl--  
Laurent Montel committed
359
        messageFile = QUrl::fromLocalFile(filename);
Laurent Montel's avatar
Laurent Montel committed
360
        if (!messageFile.isValid()) {
Laurent Montel's avatar
KUrl--  
Laurent Montel committed
361
            messageFile = QUrl();
Laurent Montel's avatar
Laurent Montel committed
362
            messageFile.setPath(filename);
Laurent Montel's avatar
Laurent Montel committed
363 364 365
        }
    }

Laurent Montel's avatar
Laurent Montel committed
366
    if (!calledWithSession) {
Laurent Montel's avatar
Laurent Montel committed
367 368
        // only read additional command line arguments if kmail/kontact is
        // not called with "-session foo"
369
        for (const QString &arg : parser.positionalArguments()) {
370
            if (arg.startsWith(QStringLiteral("mailto:"), Qt::CaseInsensitive)) {
371
                QMap<QString, QString> values = MessageCore::StringUtil::parseMailtoUrl(QUrl::fromUserInput(arg));
372 373
                if (!values.value(QStringLiteral("to")).isEmpty()) {
                    to += values.value(QStringLiteral("to")) + QStringLiteral(", ");
Laurent Montel's avatar
Laurent Montel committed
374
                }
375 376
                if (!values.value(QStringLiteral("cc")).isEmpty()) {
                    cc += values.value(QStringLiteral("cc")) + QStringLiteral(", ");
Laurent Montel's avatar
Laurent Montel committed
377
                }
Laurent Montel's avatar
Laurent Montel committed
378 379 380
                if (!values.value(QStringLiteral("bcc")).isEmpty()) {
                    bcc += values.value(QStringLiteral("bcc")) + QStringLiteral(", ");
                }
381 382
                if (!values.value(QStringLiteral("subject")).isEmpty()) {
                    subj = values.value(QStringLiteral("subject"));
Laurent Montel's avatar
Laurent Montel committed
383
                }
384 385
                if (!values.value(QStringLiteral("body")).isEmpty()) {
                    body = values.value(QStringLiteral("body"));
Laurent Montel's avatar
Laurent Montel committed
386
                }
387 388
                if (!values.value(QStringLiteral("in-reply-to")).isEmpty()) {
                    inReplyTo = values.value(QStringLiteral("in-reply-to"));
Laurent Montel's avatar
Laurent Montel committed
389
                }
390
                QString attach = values.value(QStringLiteral("attachment"));
Laurent Montel's avatar
Laurent Montel committed
391
                if (!attach.isEmpty()) {
392
                    attachURLs << makeAbsoluteUrl(attach, workingDir);
Laurent Montel's avatar
Laurent Montel committed
393
                }
394 395 396 397 398
                attach = values.value(QStringLiteral("attach"));
                if (!attach.isEmpty()) {
                    attachURLs << makeAbsoluteUrl(attach, workingDir);
                }

Laurent Montel's avatar
Laurent Montel committed
399
            } else {
400
                QUrl url(arg);
Laurent Montel's avatar
Laurent Montel committed
401
                if (url.isValid() && !url.scheme().isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
402
                    attachURLs += url;
Laurent Montel's avatar
Laurent Montel committed
403
                } else {
404
                    to += arg + QStringLiteral(", ");
Laurent Montel's avatar
Laurent Montel committed
405
                }
Laurent Montel's avatar
Laurent Montel committed
406 407 408
            }
            mailto = true;
        }
Laurent Montel's avatar
Laurent Montel committed
409
        if (!to.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
410
            // cut off the superfluous trailing ", "
Laurent Montel's avatar
Laurent Montel committed
411
            to.truncate(to.length() - 2);
Laurent Montel's avatar
Laurent Montel committed
412 413 414
        }
    }

Laurent Montel's avatar
Laurent Montel committed
415
    if (!noArgsOpensReader && !mailto && !checkMail && !viewOnly) {
Laurent Montel's avatar
Laurent Montel committed
416
        return false;
Laurent Montel's avatar
Laurent Montel committed
417
    }
Laurent Montel's avatar
Laurent Montel committed
418

Laurent Montel's avatar
Laurent Montel committed
419
    if (viewOnly) {
420
        viewMessage(messageFile);
Laurent Montel's avatar
Laurent Montel committed
421 422 423
    } else
        action(mailto, checkMail, to, cc, bcc, subj, body, messageFile,
               attachURLs, customHeaders, replyTo, inReplyTo);
Laurent Montel's avatar
Laurent Montel committed
424
    return true;
425
}
426

427
/********************************************************************/
Laurent Montel's avatar
Port++  
Laurent Montel committed
428
/*             D-Bus-callable, and command line actions              */
429
/********************************************************************/
Laurent Montel's avatar
Laurent Montel committed
430
void KMKernel::checkMail()  //might create a new reader but won't show!!
431
{
Laurent Montel's avatar
Laurent Montel committed
432
    if (!kmkernel->askToGoOnline()) {
Laurent Montel's avatar
Laurent Montel committed
433
        return;
Laurent Montel's avatar
Laurent Montel committed
434
    }
Laurent Montel's avatar
Laurent Montel committed
435

436
    const QString resourceGroupPattern(QStringLiteral("Resource %1"));
Laurent Montel's avatar
Laurent Montel committed
437 438

    const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
Laurent Montel's avatar
Laurent Montel committed
439
    foreach (Akonadi::AgentInstance type, lst) {
Laurent Montel's avatar
Laurent Montel committed
440
        const QString id = type.identifier();
Laurent Montel's avatar
Laurent Montel committed
441 442 443 444 445 446
        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
447
                qCDebug(KMAIL_LOG) << "Starting manual mail check";
Laurent Montel's avatar
Laurent Montel committed
448
                Q_EMIT startCheckMail();
Laurent Montel's avatar
Laurent Montel committed
449
            }
Thomas McGuire's avatar
Thomas McGuire committed
450

Laurent Montel's avatar
Laurent Montel committed
451 452
            if (!mResourcesBeingChecked.contains(id)) {
                mResourcesBeingChecked.append(id);
Laurent Montel's avatar
Laurent Montel committed
453 454 455
            }
            type.synchronize();
        }
456
    }
457 458
}

459 460 461 462 463
void KMKernel::openReader()
{
    openReader(false);
}

Laurent Montel's avatar
Laurent Montel committed
464
void KMKernel::setSystrayIconNotificationsEnabled(bool enabled)
465
{
Laurent Montel's avatar
Laurent Montel committed
466 467
    if (mSystemTray) {
        mSystemTray->setSystrayIconNotificationsEnabled(enabled);
Laurent Montel's avatar
Laurent Montel committed
468
    }
469 470
}

Waldo Bastian's avatar
Waldo Bastian committed
471 472
QStringList KMKernel::accounts()
{
Laurent Montel's avatar
Laurent Montel committed
473 474
    QStringList accountLst;
    const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
475
    accountLst.reserve(lst.count());
Laurent Montel's avatar
Laurent Montel committed
476
    foreach (const Akonadi::AgentInstance &type, lst) {
Laurent Montel's avatar
Laurent Montel committed
477 478
        // 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
479
        accountLst << type.identifier();
Laurent Montel's avatar
Laurent Montel committed
480 481
    }
    return accountLst;
Waldo Bastian's avatar
Waldo Bastian committed
482 483
}

Laurent Montel's avatar
Laurent Montel committed
484
void KMKernel::checkAccount(const QString &account)   //might create a new reader but won't show!!
Waldo Bastian's avatar
Waldo Bastian committed
485
{
Laurent Montel's avatar
Laurent Montel committed
486
    if (account.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
487
        checkMail();
Laurent Montel's avatar
Laurent Montel committed
488 489 490
    } else {
        Akonadi::AgentInstance agent = Akonadi::AgentManager::self()->instance(account);
        if (agent.isValid()) {
Laurent Montel's avatar
Laurent Montel committed
491
            agent.synchronize();
Laurent Montel's avatar
Laurent Montel committed
492
        } else {
Laurent Montel's avatar
Laurent Montel committed
493
            qCDebug(KMAIL_LOG) << "- account with name '" << account << "' not found";
Laurent Montel's avatar
Laurent Montel committed
494
        }
Laurent Montel's avatar
Laurent Montel committed
495
    }
Waldo Bastian's avatar
Waldo Bastian committed
496 497
}

Laurent Montel's avatar
Laurent Montel committed
498
void KMKernel::openReader(bool onlyCheck)
499
{
Laurent Montel's avatar
Laurent Montel committed
500 501
    mWin = Q_NULLPTR;
    KMainWindow *ktmw = Q_NULLPTR;
502

Laurent Montel's avatar
Laurent Montel committed
503 504
    foreach (KMainWindow *window, KMainWindow::memberList()) {
        if (::qobject_cast<KMMainWin *>(window)) {
Laurent Montel's avatar
Laurent Montel committed
505 506 507 508
            ktmw = window;
            break;
        }
    }
509

Laurent Montel's avatar
Laurent Montel committed
510 511 512 513
    bool activate;
    if (ktmw) {
        mWin = static_cast<KMMainWin *>(ktmw);
        activate = !onlyCheck; // existing window: only activate if not --check
Laurent Montel's avatar
Laurent Montel committed
514
        if (activate) {
Laurent Montel's avatar
Laurent Montel committed
515
            mWin->show();
Laurent Montel's avatar
Laurent Montel committed
516 517
        }
    } else {
Laurent Montel's avatar
Laurent Montel committed
518 519 520 521 522
        mWin = new KMMainWin;
        mWin->show();
        activate = false; // new window: no explicit activation (#73591)
    }

Laurent Montel's avatar
Laurent Montel committed
523
    if (activate) {
Laurent Montel's avatar
Laurent Montel committed
524 525
        // Activate window - doing this instead of KWindowSystem::activateWindow(mWin->winId());
        // so that it also works when called from KMailApplication::newInstance()
Laurent Montel's avatar
Laurent Montel committed
526
#if defined Q_OS_X11 && ! defined K_WS_QTONLY
527
        KStartupInfo::setNewStartupId(mWin, KStartupInfo::startupId());
528
#endif
Laurent Montel's avatar
Laurent Montel committed
529
    }
530 531
}

Laurent Montel's avatar
Laurent Montel committed
532
int KMKernel::openComposer(const QString &to, const QString &cc,
Laurent Montel's avatar
Laurent Montel committed
533 534 535 536 537 538 539 540
                           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)
{
    KMail::Composer::TemplateContext context = KMail::Composer::New;
Laurent Montel's avatar
Laurent Montel committed
541 542
    KMime::Message::Ptr msg(new KMime::Message);
    MessageHelper::initHeader(msg, identityManager());
Laurent Montel's avatar
Laurent Montel committed
543
    msg->contentType()->setCharset("utf-8");
Laurent Montel's avatar
Laurent Montel committed
544 545 546
    if (!to.isEmpty()) {
        msg->to()->fromUnicodeString(to, "utf-8");
    }
Laurent Montel's avatar
Laurent Montel committed
547

Laurent Montel's avatar
Laurent Montel committed
548 549 550
    if (!cc.isEmpty()) {
        msg->cc()->fromUnicodeString(cc, "utf-8");
    }
Laurent Montel's avatar
Laurent Montel committed
551

Laurent Montel's avatar
Laurent Montel committed
552 553 554
    if (!bcc.isEmpty()) {
        msg->bcc()->fromUnicodeString(bcc, "utf-8");
    }
Laurent Montel's avatar
Laurent Montel committed
555

Laurent Montel's avatar
Laurent Montel committed
556 557 558
    if (!subject.isEmpty()) {
        msg->subject()->fromUnicodeString(subject, "utf-8");
    }
Laurent Montel's avatar
Laurent Montel committed
559

560 561
    if (!messageFile.isEmpty() && QFile::exists(messageFile)) {
        QFile f(messageFile);
562 563
        QByteArray str;
        if (!f.open(QIODevice::ReadOnly)) {
Laurent Montel's avatar
Laurent Montel committed
564
            qCWarning(KMAIL_LOG) << "Failed to load message: " << f.errorString();
565 566 567 568
        } else {
            str = f.readAll();
            f.close();
        }
Laurent Montel's avatar
Laurent Montel committed
569
        if (!str.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
570
            context = KMail::Composer::NoTemplate;
Laurent Montel's avatar
Laurent Montel committed
571
            msg->setBody(QString::fromLocal8Bit(str.data(), str.size()).toUtf8());
572
        } else {
Laurent Montel's avatar
Laurent Montel committed
573 574 575
            TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
            parser.setIdentityManager(KMKernel::self()->identityManager());
            parser.process(msg);
Laurent Montel's avatar
Laurent Montel committed
576
        }
Laurent Montel's avatar
Laurent Montel committed
577
    } else if (!body.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
578
        context = KMail::Composer::NoTemplate;
Laurent Montel's avatar
Laurent Montel committed
579 580 581 582 583
        msg->setBody(body.toUtf8());
    } else {
        TemplateParser::TemplateParser parser(msg, TemplateParser::TemplateParser::NewMessage);
        parser.setIdentityManager(KMKernel::self()->identityManager());
        parser.process(msg);
Laurent Montel's avatar
Laurent Montel committed
584 585 586
    }

    if (!inReplyTo.isEmpty()) {
587
        KMime::Headers::InReplyTo *header = new KMime::Headers::InReplyTo;
588
        header->fromUnicodeString(inReplyTo, "utf-8");
Laurent Montel's avatar
Laurent Montel committed
589
        msg->setHeader(header);
Laurent Montel's avatar
Laurent Montel committed
590 591 592
    }

    msg->assemble();
Laurent Montel's avatar
Laurent Montel committed
593 594
    KMail::Composer *cWin = KMail::makeComposer(msg, false, false, context);
    if (!to.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
595
        cWin->setFocusToSubject();
Laurent Montel's avatar
Laurent Montel committed
596
    }
Laurent Montel's avatar
KUrl--  
Laurent Montel committed
597 598
    QList<QUrl> attachURLs = QUrl::fromStringList(attachmentPaths);
    QList<QUrl>::ConstIterator endAttachment(attachURLs.constEnd());
Laurent Montel's avatar
Laurent Montel committed
599
    for (QList<QUrl>::ConstIterator it = attachURLs.constBegin(); it != endAttachment; ++it) {
Volker Krause's avatar
Volker Krause committed
600 601
        QMimeDatabase mimeDb;
        if (mimeDb.mimeTypeForUrl(*it).name() == QLatin1String("inode/directory")) {
Laurent Montel's avatar
Laurent Montel committed
602
            if (KMessageBox::questionYesNo(Q_NULLPTR, i18n("Do you want to attach this folder \"%1\"?", (*it).toDisplayString()), i18n("Attach Folder")) == KMessageBox::No) {
Laurent Montel's avatar
Laurent Montel committed
603 604 605
                continue;
            }
        }
Laurent Montel's avatar
Laurent Montel committed
606
        cWin->addAttachment((*it), QString());
Laurent Montel's avatar
Laurent Montel committed
607 608 609 610 611 612 613 614
    }
    if (!replyTo.isEmpty()) {
        cWin->setCurrentReplyTo(replyTo);
    }

    if (!customHeaders.isEmpty()) {
        QMap<QByteArray, QString> extraCustomHeaders;
        QStringList::ConstIterator end = customHeaders.constEnd();
Laurent Montel's avatar
Laurent Montel committed
615
        for (QStringList::ConstIterator it = customHeaders.constBegin(); it != end; ++it) {
Laurent Montel's avatar
Laurent Montel committed
616 617 618 619 620 621
            if (!(*it).isEmpty()) {
                const int pos = (*it).indexOf(QLatin1Char(':'));
                if (pos > 0) {
                    const QString header = (*it).left(pos).trimmed();
                    const QString value = (*it).mid(pos + 1).trimmed();
                    if (!header.isEmpty() && !value.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
622 623 624 625 626
                        extraCustomHeaders.insert(header.toUtf8(), value);
                    }
                }
            }
        }
Laurent Montel's avatar
Laurent Montel committed
627
        if (!extraCustomHeaders.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
628
            cWin->addExtraCustomHeaders(extraCustomHeaders);
Laurent Montel's avatar
Laurent Montel committed
629
        }
Laurent Montel's avatar
Laurent Montel committed
630
    }
Laurent Montel's avatar
Laurent Montel committed
631
    if (!hidden) {
Laurent Montel's avatar
Laurent Montel committed
632 633 634
        cWin->show();
        // Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
        // so that it also works when called from KMailApplication::newInstance()
Laurent Montel's avatar
Laurent Montel committed
635
#if defined Q_OS_X11 && ! defined K_WS_QTONLY
636
        KStartupInfo::setNewStartupId(cWin, KStartupInfo::startupId());
637
#endif
Laurent Montel's avatar
Laurent Montel committed
638 639
    }
    return 1;
640 641
}

642 643 644 645 646 647 648 649 650 651 652 653 654 655
int 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)
{
656 657
    KMail::Composer *cWin;
    bool iCalAutoSend = fillComposer(cWin, to, cc, bcc,
Laurent Montel's avatar
Laurent Montel committed
658 659 660 661
                                     subject, body,
                                     attachName, attachCte, attachData,
                                     attachType, attachSubType, attachParamAttr, attachParamValue,
                                     attachContDisp, attachCharset, identity);
662

Laurent Montel's avatar
Laurent Montel committed
663
    if (!hidden && !iCalAutoSend) {
664 665 666 667
        cWin->show();
        // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
        // so that it also works when called from KMailApplication::newInstance()
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
668
        KStartupInfo::setNewStartupId(cWin, KStartupInfo::startupId());
669 670 671 672 673 674 675 676 677
#endif
    } else {

        // Always disable word wrap when we don't show the composer, since otherwise QTextEdit
        // gets the widget size wrong and wraps much too early.
        cWin->disableWordWrap();
        cWin->slotSendNow();
    }
    return 1;
678 679
}

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
int 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)
{
    KMail::Composer *cWin;
    fillComposer(cWin, to, cc, bcc,
                 subject, body,
                 attachName, attachCte, attachData,
                 attachType, attachSubType, attachParamAttr, attachParamValue,
                 attachContDisp, attachCharset, identity);
    cWin->show();
    // Activate window - doing this instead of KWin::activateWindow(cWin->winId());
    // so that it also works when called from KMailApplication::newInstance()
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
704
    KStartupInfo::setNewStartupId(cWin, KStartupInfo::startupId());
705
#endif
706

707 708 709
    return 1;
}

Laurent Montel's avatar
Laurent Montel committed
710
bool KMKernel::fillComposer(KMail::Composer *&cWin,
711
                            const QString &to, const QString &cc,
712
                            const QString &bcc, const QString &subject,
713
                            const QString &body,
714 715 716 717 718 719 720 721
                            const QString &attachName,
                            const QByteArray &attachCte,
                            const QByteArray &attachData,
                            const QByteArray &attachType,
                            const QByteArray &attachSubType,
                            const QByteArray &attachParamAttr,
                            const QString &attachParamValue,
                            const QByteArray &attachContDisp,
722
                            const QByteArray &attachCharset,
723
                            unsigned int identity)
724
{
Laurent Montel's avatar
Laurent Montel committed
725
    KMail::Composer::TemplateContext context = KMail::Composer::New;
Laurent Montel's avatar
Laurent Montel committed
726
    KMime::Message::Ptr msg(new KMime::Message);
Laurent Montel's avatar
Laurent Montel committed
727
    KMime::Content *msgPart = Q_NULLPTR;
Laurent Montel's avatar
Laurent Montel committed
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
    MessageHelper::initHeader(msg, identityManager());
    msg->contentType()->setCharset("utf-8");
    if (!cc.isEmpty()) {
        msg->cc()->fromUnicodeString(cc, "utf-8");
    }
    if (!bcc.isEmpty()) {
        msg->bcc()->fromUnicodeString(bcc, "utf-8");
    }
    if (!subject.isEmpty()) {
        msg->subject()->fromUnicodeString(subject, "utf-8");
    }
    if (!to.isEmpty()) {
        msg->to()->fromUnicodeString(to, "utf-8");
    }
    if (identity > 0) {
743
        KMime::Headers::Generic *h = new KMime::Headers::Generic("X-KMail-Identity");
744
        h->from7BitString(QByteArray::number(identity));