mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
2088 lines
76 KiB
C++
2088 lines
76 KiB
C++
/* -*- mode: C++; c-file-style: "gnu" -*- */
|
|
|
|
#include "kmkernel.h"
|
|
|
|
#include "settings/globalsettings.h"
|
|
#include "misc/broadcaststatus.h"
|
|
using KPIM::BroadcastStatus;
|
|
#include "kmstartup.h"
|
|
#include "kmmainwin.h"
|
|
#include "editor/composer.h"
|
|
#include "kmreadermainwin.h"
|
|
#include "undostack.h"
|
|
#include <kpimutils/kfileio.h>
|
|
#include "kmreaderwin.h"
|
|
#include "kmmainwidget.h"
|
|
#include "addressline/recentaddresses.h"
|
|
using KPIM::RecentAddresses;
|
|
#include "configuredialog/configuredialog.h"
|
|
#include "kmcommands.h"
|
|
#include "kmsystemtray.h"
|
|
#include "utils/stringutil.h"
|
|
#include "util/mailutil.h"
|
|
#include "mailcommon/pop3settings.h"
|
|
#include "mailcommon/folder/foldertreeview.h"
|
|
#include "mailcommon/filter/kmfilterdialog.h"
|
|
#include "mailcommon/mailcommonsettings_base.h"
|
|
#include "pimcommon/util/pimutil.h"
|
|
#include "folderarchive/folderarchivemanager.h"
|
|
#include "pimcommon/storageservice/storageservicemanager.h"
|
|
#include "pimcommon/storageservice/storageservicejobconfig.h"
|
|
#include "storageservice/storageservicesettingsjob.h"
|
|
|
|
// kdepim includes
|
|
#include "kdepim-version.h"
|
|
|
|
// kdepimlibs includes
|
|
#include <kpimidentities/identity.h>
|
|
#include <kpimidentities/identitymanager.h>
|
|
#include <mailtransport/transport.h>
|
|
#include <mailtransport/transportmanager.h>
|
|
#include <mailtransport/dispatcherinterface.h>
|
|
#include <akonadi/servermanager.h>
|
|
|
|
#include <kde_file.h>
|
|
#include <kwindowsystem.h>
|
|
#include "mailserviceimpl.h"
|
|
using KMail::MailServiceImpl;
|
|
#include "job/jobscheduler.h"
|
|
|
|
#include "messagecore/settings/globalsettings.h"
|
|
#include "messagelist/core/settings.h"
|
|
#include "messagelist/messagelistutil.h"
|
|
#include "messageviewer/settings/globalsettings.h"
|
|
#include "messagecomposer/sender/akonadisender.h"
|
|
#include "settings/messagecomposersettings.h"
|
|
#include "messagecomposer/helper/messagehelper.h"
|
|
#include "messagecomposer/settings/messagecomposersettings.h"
|
|
#include "pimcommon/settings/pimcommonsettings.h"
|
|
#include "pimcommon/autocorrection/autocorrection.h"
|
|
|
|
#include "templateparser/templateparser.h"
|
|
#include "templateparser/globalsettings_base.h"
|
|
#include "templateparser/templatesutil.h"
|
|
|
|
#include "foldercollection.h"
|
|
#include "editor/codecmanager.h"
|
|
|
|
|
|
#include <kmessagebox.h>
|
|
#include <knotification.h>
|
|
#include <progresswidget/progressmanager.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kconfig.h>
|
|
#include <kpassivepopup.h>
|
|
#include <kapplication.h>
|
|
#include <ksystemtrayicon.h>
|
|
#include <kconfiggroup.h>
|
|
#include <kdebug.h>
|
|
#include <kio/jobuidelegate.h>
|
|
#include <kprocess.h>
|
|
#include <KCrash>
|
|
|
|
#include <kmime/kmime_message.h>
|
|
#include <kmime/kmime_util.h>
|
|
#include <Akonadi/Collection>
|
|
#include <Akonadi/CollectionFetchJob>
|
|
#include <Akonadi/ChangeRecorder>
|
|
#include <Akonadi/ItemFetchScope>
|
|
#include <Akonadi/AgentManager>
|
|
#include <Akonadi/ItemFetchJob>
|
|
#include <Akonadi/AttributeFactory>
|
|
#include <Akonadi/Session>
|
|
#include <Akonadi/EntityTreeModel>
|
|
#include <akonadi/entitymimetypefiltermodel.h>
|
|
#include <Akonadi/CollectionStatisticsJob>
|
|
|
|
#include <QDir>
|
|
#include <QWidget>
|
|
#include <QFileInfo>
|
|
#include <QtDBus/QtDBus>
|
|
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#include <kcmdlineargs.h>
|
|
#include <kstartupinfo.h>
|
|
#include <kmailadaptor.h>
|
|
#include "kmailinterface.h"
|
|
#include "foldercollectionmonitor.h"
|
|
#include "imapresourcesettings.h"
|
|
#include "util.h"
|
|
#include "mailcommon/kernel/mailkernel.h"
|
|
|
|
#include "searchdialog/searchdescriptionattribute.h"
|
|
|
|
using namespace MailCommon;
|
|
|
|
static KMKernel * mySelf = 0;
|
|
static bool s_askingToGoOnline = false;
|
|
|
|
/********************************************************************/
|
|
/* Constructor and destructor */
|
|
/********************************************************************/
|
|
KMKernel::KMKernel (QObject *parent) :
|
|
QObject(parent),
|
|
mIdentityManager(0),
|
|
mConfigureDialog(0),
|
|
mMailService(0),
|
|
mSystemNetworkStatus ( Solid::Networking::status() ),
|
|
mSystemTray(0),
|
|
mDebugBaloo(false)
|
|
{
|
|
if (!qgetenv("KDEPIM_BALOO_DEBUG").isEmpty()) {
|
|
mDebugBaloo = true;
|
|
}
|
|
Akonadi::AttributeFactory::registerAttribute<Akonadi::SearchDescriptionAttribute>();
|
|
QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.kmail"));
|
|
KMail::Util::migrateFromKMail1();
|
|
kDebug() << "Starting up...";
|
|
|
|
mySelf = this;
|
|
the_firstInstance = true;
|
|
|
|
the_undoStack = 0;
|
|
the_msgSender = 0;
|
|
mFilterEditDialog = 0;
|
|
mWin = 0;
|
|
// 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
|
|
GlobalSettings::self();
|
|
|
|
mJobScheduler = new JobScheduler( this );
|
|
mXmlGuiInstance = KComponentData();
|
|
|
|
mAutoCorrection = new PimCommon::AutoCorrection();
|
|
KMime::setFallbackCharEncoding( MessageCore::GlobalSettings::self()->fallbackCharacterEncoding() );
|
|
KMime::setUseOutlookAttachmentEncoding( MessageComposer::MessageComposerSettings::self()->outlookCompatibleAttachments() );
|
|
|
|
// cberzan: this crap moved to CodecManager ======================
|
|
netCodec = QTextCodec::codecForName( KGlobal::locale()->encoding() );
|
|
|
|
// 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.
|
|
if ( netCodec->name().toLower() == "eucjp"
|
|
#if defined Q_WS_WIN || defined Q_WS_MACX
|
|
|| netCodec->name().toLower() == "shift-jis" // OK?
|
|
#endif
|
|
)
|
|
{
|
|
netCodec = QTextCodec::codecForName("jis7");
|
|
// QTextCodec *cdc = QTextCodec::codecForName("jis7");
|
|
// QTextCodec::setCodecForLocale(cdc);
|
|
// KGlobal::locale()->setEncoding(cdc->mibEnum());
|
|
}
|
|
// until here ================================================
|
|
|
|
Akonadi::Session *session = new Akonadi::Session( "KMail Kernel ETM", this );
|
|
|
|
mFolderCollectionMonitor = new FolderCollectionMonitor( session, this );
|
|
|
|
connect( mFolderCollectionMonitor->monitor(), SIGNAL(collectionRemoved(Akonadi::Collection)), SLOT(slotCollectionRemoved(Akonadi::Collection)));
|
|
|
|
mEntityTreeModel = new Akonadi::EntityTreeModel( folderCollectionMonitor(), this );
|
|
mEntityTreeModel->setIncludeUnsubscribed( false );
|
|
mEntityTreeModel->setItemPopulationStrategy( Akonadi::EntityTreeModel::LazyPopulation );
|
|
|
|
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 );
|
|
|
|
|
|
connect( folderCollectionMonitor(), SIGNAL(collectionChanged(Akonadi::Collection,QSet<QByteArray>)),
|
|
SLOT(slotCollectionChanged(Akonadi::Collection,QSet<QByteArray>)) );
|
|
|
|
connect( MailTransport::TransportManager::self(),
|
|
SIGNAL(transportRemoved(int,QString)),
|
|
SLOT(transportRemoved(int,QString)) );
|
|
connect( MailTransport::TransportManager::self(),
|
|
SIGNAL(transportRenamed(int,QString,QString)),
|
|
SLOT(transportRenamed(int,QString,QString)) );
|
|
|
|
QDBusConnection::sessionBus().connect(QString(), QLatin1String( "/MailDispatcherAgent" ), QLatin1String("org.freedesktop.Akonadi.MailDispatcherAgent"), QLatin1String("itemDispatchStarted"),this, SLOT(itemDispatchStarted()) );
|
|
connect( Akonadi::AgentManager::self(), SIGNAL(instanceStatusChanged(Akonadi::AgentInstance)),
|
|
this, SLOT(instanceStatusChanged(Akonadi::AgentInstance)) );
|
|
|
|
connect( Akonadi::AgentManager::self(), SIGNAL(instanceError(Akonadi::AgentInstance,QString)),
|
|
this, SLOT(slotInstanceError(Akonadi::AgentInstance,QString)) );
|
|
|
|
connect( Akonadi::AgentManager::self(), SIGNAL(instanceWarning(Akonadi::AgentInstance,QString)),
|
|
SLOT(slotInstanceWarning(Akonadi::AgentInstance,QString)) );
|
|
|
|
connect( Akonadi::AgentManager::self(), SIGNAL(instanceRemoved(Akonadi::AgentInstance)),
|
|
this, SLOT(slotInstanceRemoved(Akonadi::AgentInstance)) );
|
|
|
|
connect ( Solid::Networking::notifier(), SIGNAL(statusChanged(Solid::Networking::Status)),
|
|
this, SLOT(slotSystemNetworkStatusChanged(Solid::Networking::Status)) );
|
|
|
|
connect( KPIM::ProgressManager::instance(), SIGNAL(progressItemCompleted(KPIM::ProgressItem*)),
|
|
this, SLOT(slotProgressItemCompletedOrCanceled(KPIM::ProgressItem*)) );
|
|
connect( KPIM::ProgressManager::instance(), SIGNAL(progressItemCanceled(KPIM::ProgressItem*)),
|
|
this, SLOT(slotProgressItemCompletedOrCanceled(KPIM::ProgressItem*)) );
|
|
connect( identityManager(), SIGNAL(deleted(uint)), this, SLOT(slotDeleteIdentity(uint)) );
|
|
CommonKernel->registerKernelIf( this );
|
|
CommonKernel->registerSettingsIf( this );
|
|
CommonKernel->registerFilterIf( this );
|
|
mFolderArchiveManager = new FolderArchiveManager(this);
|
|
mStorageManager = new PimCommon::StorageServiceManager(this);
|
|
StorageServiceSettingsJob *settingsJob = new StorageServiceSettingsJob(this);
|
|
PimCommon::StorageServiceJobConfig *configJob = PimCommon::StorageServiceJobConfig::self();
|
|
configJob->registerConfigIf(settingsJob);
|
|
}
|
|
|
|
KMKernel::~KMKernel ()
|
|
{
|
|
delete mMailService;
|
|
mMailService = 0;
|
|
|
|
mSystemTray = 0;
|
|
|
|
stopAgentInstance();
|
|
slotSyncConfig();
|
|
|
|
delete mAutoCorrection;
|
|
mySelf = 0;
|
|
kDebug();
|
|
}
|
|
|
|
Akonadi::ChangeRecorder * KMKernel::folderCollectionMonitor() const
|
|
{
|
|
return mFolderCollectionMonitor->monitor();
|
|
}
|
|
|
|
Akonadi::EntityTreeModel * KMKernel::entityTreeModel() const
|
|
{
|
|
return mEntityTreeModel;
|
|
}
|
|
|
|
Akonadi::EntityMimeTypeFilterModel * KMKernel::collectionModel() const
|
|
{
|
|
return mCollectionModel;
|
|
}
|
|
|
|
void KMKernel::setupDBus()
|
|
{
|
|
(void) new KmailAdaptor( this );
|
|
QDBusConnection::sessionBus().registerObject( QLatin1String("/KMail"), this );
|
|
mMailService = new MailServiceImpl();
|
|
}
|
|
|
|
static KUrl makeAbsoluteUrl( const QString& str )
|
|
{
|
|
KUrl url( str );
|
|
if ( url.protocol().isEmpty() ) {
|
|
const QString newUrl = KCmdLineArgs::cwd() + QLatin1Char('/') + url.fileName();
|
|
return KUrl( newUrl );
|
|
}
|
|
else {
|
|
return url;
|
|
}
|
|
}
|
|
|
|
bool KMKernel::handleCommandLine( bool noArgsOpensReader )
|
|
{
|
|
QString to, cc, bcc, subj, body, inReplyTo, replyTo;
|
|
QStringList customHeaders;
|
|
KUrl messageFile;
|
|
KUrl::List attachURLs;
|
|
bool mailto = false;
|
|
bool checkMail = false;
|
|
bool viewOnly = false;
|
|
bool calledWithSession = false; // for ignoring '-session foo'
|
|
|
|
// process args:
|
|
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
|
|
if (args->isSet("subject"))
|
|
{
|
|
subj = args->getOption("subject");
|
|
// 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
|
|
if ( subj == QLatin1String("ession") ) {
|
|
subj.clear();
|
|
calledWithSession = true;
|
|
}
|
|
else
|
|
mailto = true;
|
|
}
|
|
|
|
if (args->isSet("cc"))
|
|
{
|
|
mailto = true;
|
|
cc = args->getOption("cc");
|
|
}
|
|
|
|
if (args->isSet("bcc"))
|
|
{
|
|
mailto = true;
|
|
bcc = args->getOption("bcc");
|
|
}
|
|
|
|
if (args->isSet("replyTo"))
|
|
{
|
|
mailto = true;
|
|
replyTo = args->getOption("replyTo");
|
|
}
|
|
|
|
|
|
if (args->isSet("msg"))
|
|
{
|
|
mailto = true;
|
|
const QString file = args->getOption("msg");
|
|
messageFile = makeAbsoluteUrl(file);
|
|
}
|
|
|
|
if (args->isSet("body"))
|
|
{
|
|
mailto = true;
|
|
body = args->getOption("body");
|
|
}
|
|
|
|
const QStringList attachList = args->getOptionList("attach");
|
|
if ( !attachList.isEmpty() ) {
|
|
mailto = true;
|
|
QStringList::ConstIterator end = attachList.constEnd();
|
|
for ( QStringList::ConstIterator it = attachList.constBegin();
|
|
it != end; ++it ) {
|
|
if ( !(*it).isEmpty() ) {
|
|
attachURLs.append( makeAbsoluteUrl( *it ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
customHeaders = args->getOptionList("header");
|
|
|
|
if (args->isSet("composer"))
|
|
mailto = true;
|
|
|
|
if (args->isSet("check"))
|
|
checkMail = true;
|
|
|
|
if ( args->isSet( "view" ) ) {
|
|
viewOnly = true;
|
|
const QString filename =
|
|
args->getOption( "view" );
|
|
messageFile = KUrl( filename );
|
|
if ( !messageFile.isValid() ) {
|
|
messageFile = KUrl();
|
|
messageFile.setPath( filename );
|
|
}
|
|
}
|
|
|
|
if ( !calledWithSession ) {
|
|
// only read additional command line arguments if kmail/kontact is
|
|
// not called with "-session foo"
|
|
const int nbArgs = args->count();
|
|
for (int i= 0; i < nbArgs; ++i)
|
|
{
|
|
if ( args->arg(i).startsWith( QLatin1String( "mailto:" ), Qt::CaseInsensitive ) ) {
|
|
QMap<QString, QString> values = MessageCore::StringUtil::parseMailtoUrl( args->url( i ) );
|
|
if ( !values.value( QLatin1String("to") ).isEmpty() )
|
|
to += values.value( QLatin1String("to") ) + QLatin1String(", ");
|
|
if ( !values.value( QLatin1String("cc") ).isEmpty() )
|
|
cc += values.value( QLatin1String("cc") ) + QLatin1String(", ");
|
|
if ( !values.value( QLatin1String("subject") ).isEmpty() )
|
|
subj = values.value( QLatin1String("subject") );
|
|
if ( !values.value( QLatin1String("body") ).isEmpty() )
|
|
body = values.value(QLatin1String( "body") );
|
|
if ( !values.value( QLatin1String("in-reply-to") ).isEmpty() ) {
|
|
inReplyTo = values.value( QLatin1String("in-reply-to") );
|
|
}
|
|
const QString attach = values.value( QLatin1String("attachment") );
|
|
if ( !attach.isEmpty() ) {
|
|
attachURLs << makeAbsoluteUrl( attach );
|
|
}
|
|
}
|
|
else {
|
|
QString tmpArg = args->arg(i);
|
|
KUrl url( tmpArg );
|
|
if (url.isValid() && !url.protocol().isEmpty())
|
|
attachURLs += url;
|
|
else
|
|
to += tmpArg + QLatin1String(", ");
|
|
}
|
|
mailto = true;
|
|
}
|
|
if ( !to.isEmpty() ) {
|
|
// cut off the superfluous trailing ", "
|
|
to.truncate( to.length() - 2 );
|
|
}
|
|
}
|
|
|
|
if ( !calledWithSession )
|
|
args->clear();
|
|
|
|
if ( !noArgsOpensReader && !mailto && !checkMail && !viewOnly )
|
|
return false;
|
|
|
|
if ( viewOnly )
|
|
viewMessage( messageFile.url() );
|
|
else
|
|
action( mailto, checkMail, to, cc, bcc, subj, body, messageFile,
|
|
attachURLs, customHeaders, replyTo, inReplyTo );
|
|
return true;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* D-Bus-callable, and command line actions */
|
|
/********************************************************************/
|
|
void KMKernel::checkMail () //might create a new reader but won't show!!
|
|
{
|
|
if ( !kmkernel->askToGoOnline() )
|
|
return;
|
|
|
|
const QString resourceGroupPattern( QLatin1String("Resource %1") );
|
|
|
|
const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
|
|
foreach( Akonadi::AgentInstance type, lst ) {
|
|
const QString id = type.identifier();
|
|
KConfigGroup group( KMKernel::config(), resourceGroupPattern.arg( id ) );
|
|
if ( group.readEntry( "IncludeInManualChecks", true ) ) {
|
|
if ( !type.isOnline() )
|
|
type.setIsOnline( true );
|
|
if ( mResourcesBeingChecked.isEmpty() ) {
|
|
kDebug() << "Starting manual mail check";
|
|
emit startCheckMail();
|
|
}
|
|
|
|
if ( !mResourcesBeingChecked.contains( id ) ) {
|
|
mResourcesBeingChecked.append( id );
|
|
}
|
|
type.synchronize();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMKernel::setSystrayIconNotificationsEnabled( bool enabled )
|
|
{
|
|
if ( mSystemTray ) {
|
|
mSystemTray->setSystrayIconNotificationsEnabled( enabled );
|
|
}
|
|
}
|
|
|
|
QStringList KMKernel::accounts()
|
|
{
|
|
QStringList accountLst;
|
|
const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
|
|
foreach ( const Akonadi::AgentInstance& type, lst )
|
|
{
|
|
// Explicitly make a copy, as we're not changing values of the list but only
|
|
// the local copy which is passed to action.
|
|
accountLst<<type.identifier();
|
|
}
|
|
return accountLst;
|
|
}
|
|
|
|
void KMKernel::checkAccount( const QString &account ) //might create a new reader but won't show!!
|
|
{
|
|
kDebug();
|
|
if ( account.isEmpty() )
|
|
checkMail();
|
|
else {
|
|
Akonadi::AgentInstance agent = Akonadi::AgentManager::self()->instance( account );
|
|
if ( agent.isValid() )
|
|
agent.synchronize();
|
|
else
|
|
kDebug() << "- account with name '" << account <<"' not found";
|
|
}
|
|
}
|
|
|
|
void KMKernel::openReader( bool onlyCheck )
|
|
{
|
|
mWin = 0;
|
|
KMainWindow *ktmw = 0;
|
|
kDebug();
|
|
|
|
foreach ( KMainWindow *window, KMainWindow::memberList() )
|
|
{
|
|
if ( ::qobject_cast<KMMainWin *>( window ) )
|
|
{
|
|
ktmw = window;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool activate;
|
|
if (ktmw) {
|
|
mWin = static_cast<KMMainWin *>(ktmw);
|
|
activate = !onlyCheck; // existing window: only activate if not --check
|
|
if ( activate )
|
|
mWin->show();
|
|
}
|
|
else {
|
|
mWin = new KMMainWin;
|
|
mWin->show();
|
|
activate = false; // new window: no explicit activation (#73591)
|
|
}
|
|
|
|
if ( activate ) {
|
|
// Activate window - doing this instead of KWindowSystem::activateWindow(mWin->winId());
|
|
// so that it also works when called from KMailApplication::newInstance()
|
|
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
|
|
KStartupInfo::setNewStartupId( mWin, kapp->startupId() );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int 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)
|
|
{
|
|
kDebug();
|
|
KMail::Composer::TemplateContext context = KMail::Composer::New;
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
MessageHelper::initHeader( msg, identityManager() );
|
|
msg->contentType()->setCharset("utf-8");
|
|
if ( !to.isEmpty() )
|
|
msg->to()->fromUnicodeString( to, "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" );
|
|
|
|
KUrl messageUrl = KUrl( messageFile );
|
|
if ( !messageUrl.isEmpty() && messageUrl.isLocalFile() ) {
|
|
const QByteArray str = KPIMUtils::kFileToByteArray( messageUrl.toLocalFile(), true, false );
|
|
if( !str.isEmpty() ) {
|
|
context = KMail::Composer::NoTemplate;
|
|
msg->setBody( QString::fromLocal8Bit( str.data(), str.size() ).toUtf8() );
|
|
}
|
|
else {
|
|
TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage );
|
|
parser.setIdentityManager( KMKernel::self()->identityManager() );
|
|
parser.process( msg );
|
|
}
|
|
}
|
|
else if ( !body.isEmpty() ) {
|
|
context = KMail::Composer::NoTemplate;
|
|
msg->setBody( body.toUtf8() );
|
|
}
|
|
else {
|
|
TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage );
|
|
parser.setIdentityManager( KMKernel::self()->identityManager() );
|
|
parser.process( msg );
|
|
}
|
|
|
|
if (!inReplyTo.isEmpty()) {
|
|
KMime::Headers::InReplyTo *header = new KMime::Headers::InReplyTo( msg.get(), inReplyTo, "utf-8" );
|
|
msg->setHeader( header );
|
|
}
|
|
|
|
msg->assemble();
|
|
KMail::Composer * cWin = KMail::makeComposer( msg, false, false, context );
|
|
if (!to.isEmpty())
|
|
cWin->setFocusToSubject();
|
|
KUrl::List attachURLs = KUrl::List( attachmentPaths );
|
|
KUrl::List::ConstIterator endAttachment(attachURLs.constEnd());
|
|
for ( KUrl::List::ConstIterator it = attachURLs.constBegin() ; it != endAttachment; ++it ) {
|
|
if( KMimeType::findByUrl( *it )->name() == QLatin1String( "inode/directory" ) ) {
|
|
if(KMessageBox::questionYesNo(0, i18n("Do you want to attach this folder \"%1\"?",(*it).prettyUrl()), i18n("Attach Folder")) == KMessageBox::No ) {
|
|
continue;
|
|
}
|
|
}
|
|
cWin->addAttachment( (*it), QString() );
|
|
}
|
|
if (!replyTo.isEmpty()) {
|
|
cWin->setCurrentReplyTo(replyTo);
|
|
}
|
|
|
|
if (!customHeaders.isEmpty()) {
|
|
QMap<QByteArray, QString> extraCustomHeaders;
|
|
QStringList::ConstIterator end = customHeaders.constEnd();
|
|
for ( QStringList::ConstIterator it = customHeaders.constBegin() ; it != end ; ++it ) {
|
|
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() ) {
|
|
extraCustomHeaders.insert(header.toUtf8(), value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!extraCustomHeaders.isEmpty())
|
|
cWin->addExtraCustomHeaders(extraCustomHeaders);
|
|
}
|
|
if ( !hidden ) {
|
|
cWin->show();
|
|
// Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
|
|
// so that it also works when called from KMailApplication::newInstance()
|
|
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
|
|
KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
|
|
#endif
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
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 )
|
|
{
|
|
kDebug();
|
|
KMail::Composer::TemplateContext context = KMail::Composer::New;
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
KMime::Content *msgPart = 0;
|
|
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 ) {
|
|
KMime::Headers::Generic *h = new KMime::Headers::Generic("X-KMail-Identity", msg.get(), QByteArray::number( identity ) );
|
|
msg->setHeader( h );
|
|
}
|
|
if ( !body.isEmpty() ) {
|
|
msg->setBody(body.toUtf8());
|
|
context = KMail::Composer::NoTemplate;
|
|
} else {
|
|
TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage );
|
|
parser.setIdentityManager( KMKernel::self()->identityManager() );
|
|
parser.process( KMime::Message::Ptr() );
|
|
}
|
|
|
|
bool iCalAutoSend = false;
|
|
bool noWordWrap = false;
|
|
bool isICalInvitation = false;
|
|
if ( !attachData.isEmpty() ) {
|
|
isICalInvitation = (attachName ==QLatin1String("cal.ics")) &&
|
|
attachType == "text" &&
|
|
attachSubType == "calendar" &&
|
|
attachParamAttr == "method";
|
|
// Remove BCC from identity on ical invitations (https://intevation.de/roundup/kolab/issue474)
|
|
if ( isICalInvitation && bcc.isEmpty() )
|
|
msg->bcc()->clear();
|
|
if ( isICalInvitation &&
|
|
MessageViewer::GlobalSettings::self()->legacyBodyInvites() ) {
|
|
// KOrganizer invitation caught and to be sent as body instead
|
|
msg->setBody( attachData );
|
|
context = KMail::Composer::NoTemplate;
|
|
msg->contentType()->from7BitString(
|
|
QString::fromLatin1("text/calendar; method=%1; "
|
|
"charset=\"utf-8\"" ).
|
|
arg( attachParamValue ).toLatin1() );
|
|
|
|
iCalAutoSend = true; // no point in editing raw ICAL
|
|
noWordWrap = true; // we shant word wrap inline invitations
|
|
} else {
|
|
// Just do what we're told to do
|
|
msgPart = new KMime::Content;
|
|
msgPart->contentTransferEncoding()->fromUnicodeString(QLatin1String(attachCte), "utf-8" );
|
|
msgPart->setBody( attachData ); //TODO: check if was setBodyEncoded
|
|
msgPart->contentType()->setMimeType( attachType + '/' + attachSubType );
|
|
msgPart->contentType()->setParameter( QLatin1String(attachParamAttr), attachParamValue ); //TODO: Check if the content disposition parameter needs to be set!
|
|
if( ! MessageViewer::GlobalSettings::self()->exchangeCompatibleInvitations() ) {
|
|
msgPart->contentDisposition()->fromUnicodeString(QLatin1String(attachContDisp), "utf-8" );
|
|
}
|
|
if( !attachCharset.isEmpty() ) {
|
|
// kDebug() << "Set attachCharset to" << attachCharset;
|
|
msgPart->contentType()->setCharset( attachCharset );
|
|
}
|
|
|
|
msgPart->contentType()->setName( attachName, "utf-8" );
|
|
msgPart->assemble();
|
|
// Don't show the composer window if the automatic sending is checked
|
|
iCalAutoSend = MessageViewer::GlobalSettings::self()->automaticSending();
|
|
}
|
|
}
|
|
|
|
msg->assemble();
|
|
KMail::Composer * cWin = KMail::makeComposer( KMime::Message::Ptr(), false, false,context );
|
|
cWin->setMessage( msg, false, false, !isICalInvitation /* mayAutoSign */ );
|
|
cWin->setSigningAndEncryptionDisabled( isICalInvitation
|
|
&& MessageViewer::GlobalSettings::self()->legacyBodyInvites() );
|
|
if ( noWordWrap )
|
|
cWin->disableWordWrap();
|
|
if ( msgPart )
|
|
cWin->addAttach( msgPart );
|
|
if ( isICalInvitation ) {
|
|
cWin->forceDisableHtml();
|
|
//cWin->disableRecipientNumberCheck();
|
|
cWin->disableForgottenAttachmentsCheck();
|
|
}
|
|
|
|
if ( !hidden && !iCalAutoSend ) {
|
|
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
|
|
KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
|
|
#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;
|
|
}
|
|
|
|
QDBusObjectPath KMKernel::openComposer( const QString &to, const QString &cc,
|
|
const QString &bcc,
|
|
const QString &subject,
|
|
const QString &body, bool hidden )
|
|
{
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
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 ( !body.isEmpty() ) {
|
|
msg->setBody( body.toUtf8() );
|
|
} else {
|
|
TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage );
|
|
parser.setIdentityManager( KMKernel::self()->identityManager() );
|
|
parser.process( KMime::Message::Ptr() );
|
|
}
|
|
|
|
msg->assemble();
|
|
const KMail::Composer::TemplateContext context = body.isEmpty() ? KMail::Composer::New :
|
|
KMail::Composer::NoTemplate;
|
|
KMail::Composer * cWin = KMail::makeComposer( msg, false, false, context );
|
|
if ( !hidden ) {
|
|
cWin->show();
|
|
// Activate window - doing this instead of KWindowSystem::activateWindow(cWin->winId());
|
|
// so that it also works when called from KMailApplication::newInstance()
|
|
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
|
|
KStartupInfo::setNewStartupId( cWin, kapp->startupId() );
|
|
#endif
|
|
} else {
|
|
// Always disable word wrap when we don't show the composer; otherwise,
|
|
// QTextEdit gets the widget size wrong and wraps much too early.
|
|
cWin->disableWordWrap();
|
|
cWin->slotSendNow();
|
|
}
|
|
|
|
return QDBusObjectPath(cWin->dbusObjectPath());
|
|
}
|
|
|
|
QDBusObjectPath KMKernel::newMessage( const QString &to,
|
|
const QString &cc,
|
|
const QString &bcc,
|
|
bool hidden,
|
|
bool useFolderId,
|
|
const QString & /*messageFile*/,
|
|
const QString &_attachURL)
|
|
{
|
|
KUrl attachURL( _attachURL );
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
QSharedPointer<FolderCollection> folder;
|
|
uint id = 0;
|
|
|
|
if ( useFolderId ) {
|
|
//create message with required folder identity
|
|
folder = currentFolderCollection();
|
|
id = folder ? folder->identity() : 0;
|
|
}
|
|
MessageHelper::initHeader( msg, identityManager(), id );
|
|
msg->contentType()->setCharset( "utf-8" );
|
|
//set basic headers
|
|
if ( !cc.isEmpty() ) msg->cc()->fromUnicodeString( cc, "utf-8" );
|
|
if ( !bcc.isEmpty() ) msg->bcc()->fromUnicodeString( bcc, "utf-8" );
|
|
if ( !to.isEmpty() ) msg->to()->fromUnicodeString( to, "utf-8" );
|
|
|
|
msg->assemble();
|
|
TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::NewMessage );
|
|
parser.setIdentityManager( identityManager() );
|
|
Akonadi::Collection col = folder ? folder->collection() : Akonadi::Collection();
|
|
parser.process( msg, col );
|
|
|
|
KMail::Composer *win = makeComposer( msg, false, false, KMail::Composer::New, id );
|
|
|
|
win->setCollectionForNewMessage(col);
|
|
//Add the attachment if we have one
|
|
if ( !attachURL.isEmpty() && attachURL.isValid() ) {
|
|
win->addAttachment( attachURL, QString() );
|
|
}
|
|
|
|
//only show window when required
|
|
if ( !hidden ) {
|
|
win->show();
|
|
}
|
|
return QDBusObjectPath( win->dbusObjectPath() );
|
|
}
|
|
|
|
int KMKernel::viewMessage( const QString & messageFile )
|
|
{
|
|
KMOpenMsgCommand *openCommand = new KMOpenMsgCommand( 0, KUrl( messageFile ) );
|
|
|
|
openCommand->start();
|
|
return 1;
|
|
}
|
|
|
|
void KMKernel::raise()
|
|
{
|
|
QDBusInterface iface( QLatin1String("org.kde.kmail"), QLatin1String("/MainApplication"),
|
|
QLatin1String("org.kde.KUniqueApplication"),
|
|
QDBusConnection::sessionBus());
|
|
QDBusReply<int> reply;
|
|
if ( !iface.isValid() || !( reply = iface.call( QLatin1String("newInstance") ) ).isValid() )
|
|
{
|
|
QDBusError err = iface.lastError();
|
|
kError() << "Communication problem with KMail. "
|
|
<< "Error message was:" << err.name() << ": \"" << err.message() << "\"";
|
|
}
|
|
|
|
}
|
|
|
|
bool KMKernel::showMail(qint64 serialNumber)
|
|
{
|
|
KMMainWidget *mainWidget = 0;
|
|
|
|
// First look for a KMainWindow.
|
|
foreach ( KMainWindow* window, KMainWindow::memberList() ) {
|
|
// Then look for a KMMainWidget.
|
|
QList<KMMainWidget*> l = window->findChildren<KMMainWidget*>();
|
|
if ( !l.isEmpty() && l.first() ) {
|
|
mainWidget = l.first();
|
|
if ( window->isActiveWindow() )
|
|
break;
|
|
}
|
|
}
|
|
if ( mainWidget ) {
|
|
Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob( Akonadi::Item(serialNumber ),this );
|
|
job->fetchScope().fetchFullPayload();
|
|
if ( job->exec() ) {
|
|
if ( job->items().count() >= 1 ) {
|
|
KMReaderMainWin *win = new KMReaderMainWin( MessageViewer::Viewer::UseGlobalSetting, false );
|
|
win->showMessage( MessageCore::GlobalSettings::self()->overrideCharacterEncoding(),
|
|
job->items().at( 0 ) );
|
|
win->show();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void KMKernel::pauseBackgroundJobs()
|
|
{
|
|
mBackgroundTasksTimer->stop();
|
|
mJobScheduler->pause();
|
|
}
|
|
|
|
void KMKernel::resumeBackgroundJobs()
|
|
{
|
|
mJobScheduler->resume();
|
|
mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000 );
|
|
}
|
|
|
|
void KMKernel::stopNetworkJobs()
|
|
{
|
|
if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
|
|
return;
|
|
|
|
setAccountStatus(false);
|
|
|
|
GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Offline );
|
|
BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be offline; all network jobs are suspended"));
|
|
emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
|
|
|
|
}
|
|
|
|
void KMKernel::setAccountStatus(bool goOnline)
|
|
{
|
|
const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances(false);
|
|
foreach ( Akonadi::AgentInstance type, lst ) {
|
|
const QString identifier( type.identifier() );
|
|
if ( PimCommon::Util::isImapResource(identifier) ||
|
|
identifier.contains( POP3_RESOURCE_IDENTIFIER ) ||
|
|
identifier.contains( QLatin1String("akonadi_maildispatcher_agent") ) ) {
|
|
type.setIsOnline( goOnline );
|
|
}
|
|
}
|
|
if ( goOnline && MessageComposer::MessageComposerSettings::self()->sendImmediate() ) {
|
|
const qint64 nbMsgOutboxCollection = MailCommon::Util::updatedCollection( CommonKernel->outboxCollectionFolder() ).statistics().count();
|
|
if(nbMsgOutboxCollection > 0) {
|
|
kmkernel->msgSender()->sendQueued();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMKernel::resumeNetworkJobs()
|
|
{
|
|
if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Online )
|
|
return;
|
|
|
|
if ( ( mSystemNetworkStatus == Solid::Networking::Connected ) ||
|
|
( mSystemNetworkStatus == Solid::Networking::Unknown ) ) {
|
|
setAccountStatus(true);
|
|
BroadcastStatus::instance()->setStatusMsg( i18n("KMail is set to be online; all network jobs resumed"));
|
|
}
|
|
else {
|
|
BroadcastStatus::instance()->setStatusMsg( i18n ( "KMail is set to be online; all network jobs will resume when a network connection is detected" ) );
|
|
}
|
|
GlobalSettings::setNetworkState( GlobalSettings::EnumNetworkState::Online );
|
|
emit onlineStatusChanged( (GlobalSettings::EnumNetworkState::type)GlobalSettings::networkState() );
|
|
KMMainWidget *widget = getKMMainWidget();
|
|
if ( widget ) {
|
|
widget->clearViewer();
|
|
}
|
|
}
|
|
|
|
bool KMKernel::isOffline()
|
|
{
|
|
Solid::Networking::Status networkStatus = Solid::Networking::status();
|
|
if ( ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline ) ||
|
|
( networkStatus == Solid::Networking::Unconnected ) ||
|
|
( networkStatus == Solid::Networking::Disconnecting ) ||
|
|
( networkStatus == Solid::Networking::Connecting ))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void KMKernel::verifyAccount()
|
|
{
|
|
const QString resourceGroupPattern( QLatin1String("Resource %1") );
|
|
|
|
const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
|
|
foreach( Akonadi::AgentInstance type, lst ) {
|
|
KConfigGroup group( KMKernel::config(), resourceGroupPattern.arg( type.identifier() ) );
|
|
if ( group.readEntry( "CheckOnStartup", false ) ) {
|
|
if ( !type.isOnline() )
|
|
type.setIsOnline( true );
|
|
type.synchronize();
|
|
}
|
|
|
|
// "false" is also hardcoded in ConfigureDialog, don't forget to change there.
|
|
if ( group.readEntry( "OfflineOnShutdown", false ) ) {
|
|
if ( !type.isOnline() )
|
|
type.setIsOnline( true );
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMKernel::slotCheckAccount(Akonadi::ServerManager::State state)
|
|
{
|
|
if (state == Akonadi::ServerManager::Running) {
|
|
disconnect(Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)));
|
|
verifyAccount();
|
|
}
|
|
}
|
|
|
|
void KMKernel::checkMailOnStartup()
|
|
{
|
|
if ( !kmkernel->askToGoOnline() )
|
|
return;
|
|
|
|
if (Akonadi::ServerManager::state() != Akonadi::ServerManager::Running) {
|
|
connect(Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)),
|
|
SLOT(slotCheckAccount(Akonadi::ServerManager::State)));
|
|
} else {
|
|
verifyAccount();
|
|
}
|
|
}
|
|
|
|
bool KMKernel::askToGoOnline()
|
|
{
|
|
// already asking means we are offline and need to wait anyhow
|
|
if ( s_askingToGoOnline ) {
|
|
return false;
|
|
}
|
|
|
|
if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline ) {
|
|
s_askingToGoOnline = true;
|
|
int rc =
|
|
KMessageBox::questionYesNo( KMKernel::self()->mainWin(),
|
|
i18n("KMail is currently in offline mode. "
|
|
"How do you want to proceed?"),
|
|
i18n("Online/Offline"),
|
|
KGuiItem(i18n("Work Online")),
|
|
KGuiItem(i18n("Work Offline")));
|
|
|
|
s_askingToGoOnline = false;
|
|
if( rc == KMessageBox::No ) {
|
|
return false;
|
|
} else {
|
|
kmkernel->resumeNetworkJobs();
|
|
}
|
|
}
|
|
if( kmkernel->isOffline() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void KMKernel::slotSystemNetworkStatusChanged( Solid::Networking::Status status )
|
|
{
|
|
mSystemNetworkStatus = status;
|
|
if ( GlobalSettings::self()->networkState() == GlobalSettings::EnumNetworkState::Offline )
|
|
return;
|
|
|
|
if ( status == Solid::Networking::Connected || status == Solid::Networking::Unknown) {
|
|
BroadcastStatus::instance()->setStatusMsg( i18n(
|
|
"Network connection detected, all network jobs resumed") );
|
|
kmkernel->setAccountStatus( true );
|
|
}
|
|
else {
|
|
BroadcastStatus::instance()->setStatusMsg( i18n(
|
|
"No network connection detected, all network jobs are suspended"));
|
|
kmkernel->setAccountStatus( false );
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* Kernel methods */
|
|
/********************************************************************/
|
|
|
|
void KMKernel::quit()
|
|
{
|
|
// Called when all windows are closed. Will take care of compacting,
|
|
// sending... should handle session management too!!
|
|
}
|
|
/* TODO later:
|
|
Asuming that:
|
|
- msgsender is nonblocking
|
|
(our own, QSocketNotifier based. Pops up errors and sends signal
|
|
senderFinished when done)
|
|
|
|
o If we are getting mail, stop it (but don't lose something!)
|
|
[Done already, see mailCheckAborted]
|
|
o If we are sending mail, go on UNLESS this was called by SM,
|
|
in which case stop ASAP that too (can we warn? should we continue
|
|
on next start?)
|
|
o If we are compacting, or expunging, go on UNLESS this was SM call.
|
|
In that case stop compacting ASAP and continue on next start, before
|
|
touching any folders. [Not needed anymore with CompactionJob]
|
|
|
|
KMKernel::quit ()
|
|
{
|
|
SM call?
|
|
if compacting, stop;
|
|
if sending, stop;
|
|
if receiving, stop;
|
|
Windows will take care of themselves (composer should dump
|
|
its messages, if any but not in deadMail)
|
|
declare us ready for the End of the Session
|
|
|
|
No, normal quit call
|
|
All windows are off. Anything to do, should compact or sender sends?
|
|
Yes, maybe put an icon in panel as a sign of life
|
|
if sender sending, connect us to his finished slot, declare us ready
|
|
for quit and wait for senderFinished
|
|
if not, Folder manager, go compact sent-mail and outbox
|
|
} (= call slotFinished())
|
|
|
|
void KMKernel::slotSenderFinished()
|
|
{
|
|
good, Folder manager go compact sent-mail and outbox
|
|
clean up stage1 (release folders and config, unregister from dcop)
|
|
-- another kmail may start now ---
|
|
qApp->quit();
|
|
}
|
|
*/
|
|
|
|
|
|
/********************************************************************/
|
|
/* Init, Exit, and handler methods */
|
|
/********************************************************************/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Open a composer for each message found in the dead.letter folder
|
|
void KMKernel::recoverDeadLetters()
|
|
{
|
|
const QString pathName = localDataPath();
|
|
QDir dir( pathName );
|
|
if ( !dir.exists( QLatin1String("autosave") ) )
|
|
return;
|
|
|
|
dir.cd( localDataPath() + QLatin1String("autosave") );
|
|
const QFileInfoList autoSaveFiles = dir.entryInfoList();
|
|
foreach( const QFileInfo &file, autoSaveFiles ) {
|
|
// Disregard the '.' and '..' folders
|
|
const QString filename = file.fileName();
|
|
if( filename == QLatin1String( "." ) ||
|
|
filename == QLatin1String( ".." )
|
|
|| file.isDir() )
|
|
continue;
|
|
kDebug() << "Opening autosave file:" << file.absoluteFilePath();
|
|
QFile autoSaveFile( file.absoluteFilePath() );
|
|
if( autoSaveFile.open( QIODevice::ReadOnly ) ) {
|
|
const KMime::Message::Ptr autoSaveMessage( new KMime::Message() );
|
|
const QByteArray msgData = autoSaveFile.readAll();
|
|
autoSaveMessage->setContent( msgData );
|
|
autoSaveMessage->parse();
|
|
|
|
// Show the a new composer dialog for the message
|
|
KMail::Composer * autoSaveWin = KMail::makeComposer();
|
|
autoSaveWin->setMessage( autoSaveMessage, false, false, false );
|
|
autoSaveWin->setAutoSaveFileName( filename );
|
|
autoSaveWin->show();
|
|
autoSaveFile.close();
|
|
} else {
|
|
KMessageBox::sorry( 0, i18n( "Failed to open autosave file at %1.\nReason: %2" ,
|
|
file.absoluteFilePath(), autoSaveFile.errorString() ),
|
|
i18n( "Opening Autosave File Failed" ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void KMKernel::akonadiStateChanged( Akonadi::ServerManager::State state )
|
|
{
|
|
kDebug() << "KMKernel has akonadi state changed to:" << int( state );
|
|
|
|
if( state == Akonadi::ServerManager::Running ) {
|
|
CommonKernel->initFolders();
|
|
}
|
|
}
|
|
static void kmCrashHandler( int sigId )
|
|
{
|
|
fprintf( stderr, "*** KMail got signal %d (Exiting)\n", sigId );
|
|
// try to cleanup all windows
|
|
if ( kmkernel ) {
|
|
kmkernel->dumpDeadLetters();
|
|
fprintf( stderr, "*** Dead letters dumped.\n" );
|
|
kmkernel->stopAgentInstance();
|
|
}
|
|
}
|
|
|
|
void KMKernel::init()
|
|
{
|
|
the_shuttingDown = false;
|
|
|
|
the_firstStart = GlobalSettings::self()->firstStart();
|
|
GlobalSettings::self()->setFirstStart( false );
|
|
the_previousVersion = GlobalSettings::self()->previousVersion();
|
|
GlobalSettings::self()->setPreviousVersion( QLatin1String(KDEPIM_VERSION) );
|
|
|
|
|
|
the_undoStack = new UndoStack(20);
|
|
|
|
the_msgSender = new MessageComposer::AkonadiSender;
|
|
// filterMgr->dump();
|
|
|
|
mBackgroundTasksTimer = new QTimer( this );
|
|
mBackgroundTasksTimer->setSingleShot( true );
|
|
connect( mBackgroundTasksTimer, SIGNAL(timeout()), this, SLOT(slotRunBackgroundTasks()) );
|
|
#ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
|
|
mBackgroundTasksTimer->start( 10000 ); // 10s, singleshot
|
|
#else
|
|
mBackgroundTasksTimer->start( 5 * 60000 ); // 5 minutes, singleshot
|
|
#endif
|
|
|
|
KCrash::setEmergencySaveFunction( kmCrashHandler );
|
|
|
|
kDebug() << "KMail init with akonadi server state:" << int( Akonadi::ServerManager::state() );
|
|
if( Akonadi::ServerManager::state() == Akonadi::ServerManager::Running ) {
|
|
CommonKernel->initFolders();
|
|
}
|
|
|
|
connect( Akonadi::ServerManager::self(), SIGNAL(stateChanged(Akonadi::ServerManager::State)), this, SLOT(akonadiStateChanged(Akonadi::ServerManager::State)) );
|
|
connect( folderCollectionMonitor(), SIGNAL(itemRemoved(Akonadi::Item)), the_undoStack, SLOT(msgDestroyed(Akonadi::Item)) );
|
|
}
|
|
|
|
bool KMKernel::doSessionManagement()
|
|
{
|
|
|
|
// Do session management
|
|
if (kapp->isSessionRestored()){
|
|
int n = 1;
|
|
while (KMMainWin::canBeRestored(n)){
|
|
//only restore main windows! (Matthias);
|
|
if (KMMainWin::classNameOfToplevel(n) == QLatin1String("KMMainWin"))
|
|
(new KMMainWin)->restoreDockedState(n);
|
|
++n;
|
|
}
|
|
return true; // we were restored by SM
|
|
}
|
|
return false; // no, we were not restored
|
|
}
|
|
|
|
void KMKernel::closeAllKMailWindows()
|
|
{
|
|
QList<KMainWindow*> windowsToDelete;
|
|
|
|
foreach ( KMainWindow* window, KMainWindow::memberList() ) {
|
|
if ( ::qobject_cast<KMMainWin *>(window) ||
|
|
::qobject_cast<KMail::SecondaryWindow *>(window) )
|
|
{
|
|
// close and delete the window
|
|
window->setAttribute(Qt::WA_DeleteOnClose);
|
|
window->close();
|
|
windowsToDelete.append( window );
|
|
}
|
|
}
|
|
|
|
// We delete all main windows here. Above we called close(), but that calls
|
|
// deleteLater() internally, therefore does not delete it immediately.
|
|
// This would lead to problems when closing Kontact when a composer window
|
|
// is open, because the destruction order is:
|
|
//
|
|
// 1. destructor of the Kontact mainwinow
|
|
// 2. delete all parts
|
|
// 3. the KMail part destructor calls KMKernel::cleanup(), which calls
|
|
// this function
|
|
// 4. delete all other mainwindows
|
|
//
|
|
// Deleting the composer windows here will make sure that step 4 will not delete
|
|
// any composer window, which would fail because the kernel is already deleted.
|
|
qDeleteAll( windowsToDelete );
|
|
windowsToDelete.clear();
|
|
}
|
|
|
|
void KMKernel::cleanup(void)
|
|
{
|
|
disconnect( Akonadi::AgentManager::self(), SIGNAL(instanceStatusChanged(Akonadi::AgentInstance)));
|
|
disconnect( Akonadi::AgentManager::self(), SIGNAL(instanceError(Akonadi::AgentInstance,QString)));
|
|
disconnect( Akonadi::AgentManager::self(), SIGNAL(instanceWarning(Akonadi::AgentInstance,QString)));
|
|
disconnect( Akonadi::AgentManager::self(), SIGNAL(instanceRemoved(Akonadi::AgentInstance)));
|
|
disconnect ( Solid::Networking::notifier(), SIGNAL(statusChanged(Solid::Networking::Status)));
|
|
disconnect( KPIM::ProgressManager::instance(), SIGNAL(progressItemCompleted(KPIM::ProgressItem*)));
|
|
disconnect( KPIM::ProgressManager::instance(), SIGNAL(progressItemCanceled(KPIM::ProgressItem*)));
|
|
|
|
dumpDeadLetters();
|
|
the_shuttingDown = true;
|
|
closeAllKMailWindows();
|
|
|
|
// Flush the cache of foldercollection objects. This results
|
|
// in configuration writes, so we need to do it early enough.
|
|
MailCommon::FolderCollection::clearCache();
|
|
|
|
// Write the config while all other managers are alive
|
|
delete the_msgSender;
|
|
the_msgSender = 0;
|
|
delete the_undoStack;
|
|
the_undoStack = 0;
|
|
|
|
KSharedConfig::Ptr config = KMKernel::config();
|
|
Akonadi::Collection trashCollection = CommonKernel->trashCollectionFolder();
|
|
if ( trashCollection.isValid() ) {
|
|
if ( GlobalSettings::self()->emptyTrashOnExit() ) {
|
|
Akonadi::CollectionStatisticsJob *jobStatistics = new Akonadi::CollectionStatisticsJob( trashCollection );
|
|
if ( jobStatistics->exec() ) {
|
|
if ( jobStatistics->statistics().count() > 0 ) {
|
|
mFolderCollectionMonitor->expunge( trashCollection, true /*sync*/ );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delete mConfigureDialog;
|
|
mConfigureDialog = 0;
|
|
// do not delete, because mWin may point to an existing window
|
|
// delete mWin;
|
|
mWin = 0;
|
|
|
|
if ( RecentAddresses::exists() )
|
|
RecentAddresses::self( config.data() )->save( config.data() );
|
|
}
|
|
|
|
void KMKernel::dumpDeadLetters()
|
|
{
|
|
if ( shuttingDown() )
|
|
return; //All documents should be saved before shutting down is set!
|
|
|
|
// make all composer windows autosave their contents
|
|
foreach ( KMainWindow* window, KMainWindow::memberList() ) {
|
|
if ( KMail::Composer * win = ::qobject_cast<KMail::Composer*>( window ) ) {
|
|
win->autoSaveMessage(true);
|
|
|
|
while ( win->isComposing() ) {
|
|
kWarning() << "Danger, using an event loop, this should no longer be happening!";
|
|
qApp->processEvents();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void KMKernel::action( bool mailto, bool check, const QString &to,
|
|
const QString &cc, const QString &bcc,
|
|
const QString &subj, const QString &body,
|
|
const KUrl &messageFile,
|
|
const KUrl::List &attachURLs,
|
|
const QStringList &customHeaders,
|
|
const QString &replyTo,
|
|
const QString &inReplyTo)
|
|
{
|
|
if ( mailto ) {
|
|
openComposer( to, cc, bcc, subj, body, 0,
|
|
messageFile.pathOrUrl(), attachURLs.toStringList(),
|
|
customHeaders, replyTo, inReplyTo );
|
|
}
|
|
else
|
|
openReader( check );
|
|
|
|
if ( check )
|
|
checkMail();
|
|
//Anything else?
|
|
}
|
|
|
|
void KMKernel::slotRequestConfigSync()
|
|
{
|
|
// ### FIXME: delay as promised in the kdoc of this function ;-)
|
|
slotSyncConfig();
|
|
}
|
|
|
|
void KMKernel::slotSyncConfig()
|
|
{
|
|
PimCommon::PimCommonSettings::self()->writeConfig();
|
|
MessageCore::GlobalSettings::self()->writeConfig();
|
|
MessageViewer::GlobalSettings::self()->writeConfig();
|
|
MessageComposer::MessageComposerSettings::self()->writeConfig();
|
|
TemplateParser::GlobalSettings::self()->writeConfig();
|
|
MessageList::Core::Settings::self()->writeConfig();
|
|
MailCommon::MailCommonSettings::self()->writeConfig();
|
|
GlobalSettings::self()->writeConfig();
|
|
KMKernel::config()->sync();
|
|
}
|
|
|
|
void KMKernel::updateConfig()
|
|
{
|
|
slotConfigChanged();
|
|
}
|
|
|
|
void KMKernel::slotShowConfigurationDialog()
|
|
{
|
|
if( KMKernel::getKMMainWidget() == 0 ) {
|
|
// ensure that there is a main widget available
|
|
// as parts of the configure dialog (identity) rely on this
|
|
// and this slot can be called when there is only a KMComposeWin showing
|
|
KMMainWin *win = new KMMainWin;
|
|
win->show();
|
|
|
|
}
|
|
|
|
if( !mConfigureDialog ) {
|
|
mConfigureDialog = new ConfigureDialog( 0, false );
|
|
mConfigureDialog->setObjectName( QLatin1String("configure") );
|
|
connect( mConfigureDialog, SIGNAL(configChanged()),
|
|
this, SLOT(slotConfigChanged()) );
|
|
}
|
|
|
|
// Save all current settings.
|
|
if( getKMMainWidget() )
|
|
getKMMainWidget()->writeReaderConfig();
|
|
|
|
if( mConfigureDialog->isHidden() ) {
|
|
mConfigureDialog->show();
|
|
} else {
|
|
mConfigureDialog->raise();
|
|
}
|
|
}
|
|
|
|
void KMKernel::slotConfigChanged()
|
|
{
|
|
CodecManager::self()->updatePreferredCharsets();
|
|
emit configChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
//static
|
|
QString KMKernel::localDataPath()
|
|
{
|
|
return KStandardDirs::locateLocal( "data", QLatin1String("kmail2/") );
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
bool KMKernel::haveSystemTrayApplet() const
|
|
{
|
|
return (mSystemTray!=0);
|
|
}
|
|
|
|
void KMKernel::updateSystemTray()
|
|
{
|
|
if ( mSystemTray && !the_shuttingDown ) {
|
|
mSystemTray->updateSystemTray();
|
|
}
|
|
}
|
|
|
|
KPIMIdentities::IdentityManager * KMKernel::identityManager() {
|
|
if ( !mIdentityManager ) {
|
|
kDebug();
|
|
mIdentityManager = new KPIMIdentities::IdentityManager( false, this, "mIdentityManager" );
|
|
}
|
|
return mIdentityManager;
|
|
}
|
|
|
|
KMainWindow* KMKernel::mainWin()
|
|
{
|
|
// First look for a KMMainWin.
|
|
foreach ( KMainWindow* window, KMainWindow::memberList() )
|
|
if ( ::qobject_cast<KMMainWin *>(window) )
|
|
return window;
|
|
|
|
// There is no KMMainWin. Use any other KMainWindow instead (e.g. in
|
|
// case we are running inside Kontact) because we anyway only need
|
|
// it for modal message boxes and for KNotify events.
|
|
if ( !KMainWindow::memberList().isEmpty() ) {
|
|
KMainWindow *kmWin = KMainWindow::memberList().first();
|
|
if ( kmWin )
|
|
return kmWin;
|
|
}
|
|
|
|
// There's not a single KMainWindow. Create a KMMainWin.
|
|
// This could happen if we want to pop up an error message
|
|
// while we are still doing the startup wizard and no other
|
|
// KMainWindow is running.
|
|
mWin = new KMMainWin;
|
|
return mWin;
|
|
}
|
|
|
|
|
|
KMKernel* KMKernel::self()
|
|
{
|
|
return mySelf;
|
|
}
|
|
|
|
KSharedConfig::Ptr KMKernel::config()
|
|
{
|
|
assert( mySelf );
|
|
if ( !mySelf->mConfig )
|
|
{
|
|
mySelf->mConfig = KSharedConfig::openConfig( QLatin1String("kmail2rc") );
|
|
// Check that all updates have been run on the config file:
|
|
KMail::checkConfigUpdates();
|
|
MessageList::Core::Settings::self()->setSharedConfig( mySelf->mConfig );
|
|
MessageList::Core::Settings::self()->readConfig();
|
|
TemplateParser::GlobalSettings::self()->setSharedConfig( mySelf->mConfig );
|
|
TemplateParser::GlobalSettings::self()->readConfig();
|
|
MessageComposer::MessageComposerSettings::self()->setSharedConfig( mySelf->mConfig );
|
|
MessageComposer::MessageComposerSettings::self()->readConfig();
|
|
MessageCore::GlobalSettings::self()->setSharedConfig( mySelf->mConfig );
|
|
MessageCore::GlobalSettings::self()->readConfig();
|
|
MessageViewer::GlobalSettings::self()->setSharedConfig( mySelf->mConfig );
|
|
MessageViewer::GlobalSettings::self()->readConfig();
|
|
MailCommon::MailCommonSettings::self()->setSharedConfig( mySelf->mConfig );
|
|
MailCommon::MailCommonSettings::self()->readConfig();
|
|
PimCommon::PimCommonSettings::self()->setSharedConfig( mySelf->mConfig );
|
|
PimCommon::PimCommonSettings::self()->readConfig();
|
|
}
|
|
return mySelf->mConfig;
|
|
}
|
|
|
|
void KMKernel::syncConfig()
|
|
{
|
|
slotRequestConfigSync();
|
|
}
|
|
|
|
|
|
void KMKernel::selectCollectionFromId( const Akonadi::Collection::Id id)
|
|
{
|
|
KMMainWidget *widget = getKMMainWidget();
|
|
Q_ASSERT( widget );
|
|
if ( !widget )
|
|
return;
|
|
|
|
Akonadi::Collection colFolder = CommonKernel->collectionFromId( id );
|
|
|
|
if( colFolder.isValid() )
|
|
widget->slotSelectCollectionFolder( colFolder );
|
|
}
|
|
|
|
bool KMKernel::selectFolder( const QString &folder )
|
|
{
|
|
KMMainWidget *widget = getKMMainWidget();
|
|
Q_ASSERT( widget );
|
|
if ( !widget )
|
|
return false;
|
|
|
|
const Akonadi::Collection colFolder = CommonKernel->collectionFromId( folder.toLongLong() );
|
|
|
|
if( colFolder.isValid() ) {
|
|
widget->slotSelectCollectionFolder( colFolder );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
KMMainWidget *KMKernel::getKMMainWidget()
|
|
{
|
|
//This could definitely use a speadup
|
|
QWidgetList l = QApplication::topLevelWidgets();
|
|
QWidget *wid;
|
|
|
|
Q_FOREACH( wid, l ) {
|
|
QList<KMMainWidget*> l2 = wid->window()->findChildren<KMMainWidget*>();
|
|
if ( !l2.isEmpty() && l2.first() )
|
|
return l2.first();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void KMKernel::slotRunBackgroundTasks() // called regularly by timer
|
|
{
|
|
// Hidden KConfig keys. Not meant to be used, but a nice fallback in case
|
|
// a stable kmail release goes out with a nasty bug in CompactionJob...
|
|
if ( GlobalSettings::self()->autoExpiring() ) {
|
|
mFolderCollectionMonitor->expireAllFolders( false /*scheduled, not immediate*/, entityTreeModel() );
|
|
}
|
|
|
|
#ifdef DEBUG_SCHEDULER // for debugging, see jobscheduler.h
|
|
mBackgroundTasksTimer->start( 60 * 1000 ); // check again in 1 minute
|
|
#else
|
|
mBackgroundTasksTimer->start( 4 * 60 * 60 * 1000 ); // check again in 4 hours
|
|
#endif
|
|
|
|
}
|
|
|
|
static Akonadi::Collection::List collect_collections( const QAbstractItemModel *model,
|
|
const QModelIndex &parent )
|
|
{
|
|
Akonadi::Collection::List collections;
|
|
const int numberOfCollection( model->rowCount( parent ) );
|
|
for ( int i = 0; i < numberOfCollection; ++i ) {
|
|
const QModelIndex child = model->index( i, 0, parent );
|
|
Akonadi::Collection collection =
|
|
model->data( child, Akonadi::EntityTreeModel::CollectionRole ).value<Akonadi::Collection>();
|
|
if ( collection.isValid() ) {
|
|
collections << collection;
|
|
}
|
|
collections += collect_collections( model, child );
|
|
}
|
|
return collections;
|
|
}
|
|
|
|
Akonadi::Collection::List KMKernel::allFolders() const
|
|
{
|
|
return collect_collections( collectionModel(), QModelIndex() );
|
|
}
|
|
|
|
void KMKernel::expireAllFoldersNow() // called by the GUI
|
|
{
|
|
mFolderCollectionMonitor->expireAllFolders( true /*immediate*/, entityTreeModel() );
|
|
}
|
|
|
|
bool KMKernel::canQueryClose()
|
|
{
|
|
if ( KMMainWidget::mainWidgetList() &&
|
|
KMMainWidget::mainWidgetList()->count() > 1 )
|
|
return true;
|
|
if ( !mSystemTray || GlobalSettings::closeDespiteSystemTray() )
|
|
return true;
|
|
if ( mSystemTray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowAlways ) {
|
|
mSystemTray->hideKMail();
|
|
return false;
|
|
} else if ( ( mSystemTray->mode() == GlobalSettings::EnumSystemTrayPolicy::ShowOnUnread ) ) {
|
|
if( mSystemTray->hasUnreadMail() )
|
|
mSystemTray->setStatus( KStatusNotifierItem::Active );
|
|
mSystemTray->hideKMail();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QSharedPointer<FolderCollection> KMKernel::currentFolderCollection()
|
|
{
|
|
KMMainWidget *widget = getKMMainWidget();
|
|
QSharedPointer<FolderCollection> folder;
|
|
if ( widget ) {
|
|
folder = widget->currentFolder();
|
|
}
|
|
return folder;
|
|
}
|
|
|
|
// can't be inline, since KMSender isn't known to implement
|
|
// KMail::MessageSender outside this .cpp file
|
|
MessageComposer::MessageSender * KMKernel::msgSender()
|
|
{
|
|
return the_msgSender;
|
|
}
|
|
|
|
void KMKernel::transportRemoved(int id, const QString & name)
|
|
{
|
|
Q_UNUSED( id );
|
|
|
|
// reset all identities using the deleted transport
|
|
QStringList changedIdents;
|
|
KPIMIdentities::IdentityManager * im = identityManager();
|
|
KPIMIdentities::IdentityManager::Iterator end = im->modifyEnd();
|
|
for ( KPIMIdentities::IdentityManager::Iterator it = im->modifyBegin(); it != end; ++it ) {
|
|
if ( name == (*it).transport() ) {
|
|
(*it).setTransport( QString() );
|
|
changedIdents += (*it).identityName();
|
|
}
|
|
}
|
|
|
|
// if the deleted transport is the currently used transport reset it to default
|
|
const QString& currentTransport = GlobalSettings::self()->currentTransport();
|
|
if ( name == currentTransport )
|
|
GlobalSettings::self()->setCurrentTransport( QString() );
|
|
|
|
if ( !changedIdents.isEmpty() ) {
|
|
QString information = i18np( "This identity has been changed to use the default transport:",
|
|
"These %1 identities have been changed to use the default transport:",
|
|
changedIdents.count() );
|
|
//Don't set parent otherwise we will swith to current KMail and we configure it. So not good
|
|
KMessageBox::informationList( 0, information, changedIdents );
|
|
im->commit();
|
|
}
|
|
}
|
|
|
|
void KMKernel::transportRenamed(int id, const QString & oldName, const QString & newName)
|
|
{
|
|
Q_UNUSED( id );
|
|
|
|
QStringList changedIdents;
|
|
KPIMIdentities::IdentityManager * im = identityManager();
|
|
KPIMIdentities::IdentityManager::Iterator end = im->modifyEnd();
|
|
for ( KPIMIdentities::IdentityManager::Iterator it = im->modifyBegin(); it != end; ++it ) {
|
|
if ( oldName == (*it).transport() ) {
|
|
(*it).setTransport( newName );
|
|
changedIdents << (*it).identityName();
|
|
}
|
|
}
|
|
|
|
if ( !changedIdents.isEmpty() ) {
|
|
const QString information =
|
|
i18np( "This identity has been changed to use the modified transport:",
|
|
"These %1 identities have been changed to use the modified transport:",
|
|
changedIdents.count() );
|
|
//Don't set parent otherwise we will swith to current KMail and we configure it. So not good
|
|
KMessageBox::informationList( 0, information, changedIdents );
|
|
im->commit();
|
|
}
|
|
}
|
|
|
|
void KMKernel::itemDispatchStarted()
|
|
{
|
|
// Watch progress of the MDA.
|
|
KPIM::ProgressManager::createProgressItem( 0,
|
|
MailTransport::DispatcherInterface().dispatcherInstance(),
|
|
QString::fromLatin1( "Sender" ),
|
|
i18n( "Sending messages" ),
|
|
i18n( "Initiating sending process..." ),
|
|
true );
|
|
}
|
|
|
|
void KMKernel::instanceStatusChanged( const Akonadi::AgentInstance &instance )
|
|
{
|
|
if (instance.identifier() == QLatin1String( "akonadi_mailfilter_agent" ) ) {
|
|
// Creating a progress item twice is ok, it will simply return the already existing
|
|
// item
|
|
KPIM::ProgressItem *progress = KPIM::ProgressManager::createProgressItem( 0, instance,
|
|
instance.identifier(), instance.name(), instance.statusMessage(),
|
|
false, KPIM::ProgressItem::Encrypted );
|
|
progress->setProperty( "AgentIdentifier", instance.identifier() );
|
|
return;
|
|
}
|
|
if ( MailCommon::Util::agentInstances(true).contains( instance ) ) {
|
|
if ( instance.status() == Akonadi::AgentInstance::Running ) {
|
|
|
|
if ( mResourcesBeingChecked.isEmpty() ) {
|
|
kDebug() << "A Resource started to synchronize, starting a mail check.";
|
|
emit startCheckMail();
|
|
}
|
|
|
|
const QString identifier(instance.identifier());
|
|
if ( !mResourcesBeingChecked.contains( identifier ) ) {
|
|
mResourcesBeingChecked.append( identifier );
|
|
}
|
|
|
|
KPIM::ProgressItem::CryptoStatus cryptoStatus = KPIM::ProgressItem::Unencrypted;
|
|
if(mResourceCryptoSettingCache.contains(identifier)) {
|
|
cryptoStatus = mResourceCryptoSettingCache.value(identifier);
|
|
} else {
|
|
if ( PimCommon::Util::isImapResource(identifier) ) {
|
|
OrgKdeAkonadiImapSettingsInterface *iface = PimCommon::Util::createImapSettingsInterface( identifier );
|
|
if ( iface->isValid() ) {
|
|
const QString imapSafety = iface->safety();
|
|
if (( imapSafety == QLatin1String( "SSL" ) || imapSafety == QLatin1String( "STARTTLS" ) ))
|
|
cryptoStatus = KPIM::ProgressItem::Encrypted;
|
|
|
|
mResourceCryptoSettingCache.insert(identifier,cryptoStatus);
|
|
}
|
|
delete iface;
|
|
} else if ( identifier.contains( POP3_RESOURCE_IDENTIFIER ) ) {
|
|
OrgKdeAkonadiPOP3SettingsInterface *iface = MailCommon::Util::createPop3SettingsInterface( identifier );
|
|
if ( iface->isValid() ) {
|
|
if (( iface->useSSL() || iface->useTLS() ))
|
|
cryptoStatus = KPIM::ProgressItem::Encrypted;
|
|
mResourceCryptoSettingCache.insert(identifier, cryptoStatus);
|
|
}
|
|
delete iface;
|
|
}
|
|
}
|
|
|
|
|
|
// Creating a progress item twice is ok, it will simply return the already existing
|
|
// item
|
|
KPIM::ProgressItem *progress = KPIM::ProgressManager::createProgressItem( 0, instance,
|
|
instance.identifier(), instance.name(), instance.statusMessage(),
|
|
true, cryptoStatus );
|
|
progress->setProperty( "AgentIdentifier", instance.identifier() );
|
|
} else if ( instance.status() == Akonadi::AgentInstance::Broken ) {
|
|
agentInstanceBroken( instance );
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMKernel::agentInstanceBroken( const Akonadi::AgentInstance &instance )
|
|
{
|
|
const QString summary = i18n( "Resource %1 is broken.", instance.name() );
|
|
if( xmlGuiInstance().isValid() ) {
|
|
KNotification::event( QLatin1String("akonadi-resource-broken"),
|
|
summary,
|
|
QPixmap(),
|
|
0,
|
|
KNotification::CloseOnTimeout,
|
|
xmlGuiInstance() );
|
|
} else {
|
|
KNotification::event( QLatin1String("akonadi-resource-broken"),
|
|
summary,
|
|
QPixmap(),
|
|
0,
|
|
KNotification::CloseOnTimeout );
|
|
}
|
|
|
|
}
|
|
|
|
void KMKernel::slotProgressItemCompletedOrCanceled( KPIM::ProgressItem *item )
|
|
{
|
|
const QString identifier = item->property( "AgentIdentifier" ).toString();
|
|
const Akonadi::AgentInstance agent = Akonadi::AgentManager::self()->instance( identifier );
|
|
if ( agent.isValid() ) {
|
|
mResourcesBeingChecked.removeAll( identifier );
|
|
if ( mResourcesBeingChecked.isEmpty() ) {
|
|
kDebug() << "Last resource finished syncing, mail check done";
|
|
emit endCheckMail();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMKernel::updatedTemplates()
|
|
{
|
|
emit customTemplatesChanged();
|
|
}
|
|
|
|
|
|
bool KMKernel::isImapFolder( const Akonadi::Collection &col, bool &isOnline ) const
|
|
{
|
|
const Akonadi::AgentInstance agentInstance = Akonadi::AgentManager::self()->instance( col.resource() );
|
|
isOnline = agentInstance.isOnline();
|
|
|
|
return PimCommon::Util::isImapResource(agentInstance.type().identifier());
|
|
}
|
|
|
|
|
|
void KMKernel::stopAgentInstance()
|
|
{
|
|
const QString resourceGroupPattern( QLatin1String("Resource %1") );
|
|
|
|
const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
|
|
foreach( Akonadi::AgentInstance type, lst ) {
|
|
const QString identifier = type.identifier();
|
|
KConfigGroup group( KMKernel::config(), resourceGroupPattern.arg( identifier ) );
|
|
|
|
// Keep sync in ConfigureDialog, don't forget to change there.
|
|
if ( group.readEntry( "OfflineOnShutdown", identifier.startsWith(QLatin1String("akonadi_pop3_resource")) ? true : false ) )
|
|
type.setIsOnline( false );
|
|
}
|
|
}
|
|
|
|
void KMKernel::slotCollectionRemoved(const Akonadi::Collection &col)
|
|
{
|
|
KConfigGroup group( KMKernel::config(), MailCommon::FolderCollection::configGroupName( col ) );
|
|
group.deleteGroup();
|
|
group.sync();
|
|
const QString colStr = QString::number( col.id() );
|
|
TemplateParser::Util::deleteTemplate( colStr );
|
|
MessageList::Util::deleteConfig( colStr );
|
|
}
|
|
|
|
void KMKernel::slotDeleteIdentity( uint identity)
|
|
{
|
|
TemplateParser::Util::deleteTemplate( QString::fromLatin1( "IDENTITY_%1" ).arg( identity ) );
|
|
}
|
|
|
|
bool KMKernel::showPopupAfterDnD()
|
|
{
|
|
return GlobalSettings::self()->showPopupAfterDnD();
|
|
}
|
|
|
|
bool KMKernel::excludeImportantMailFromExpiry()
|
|
{
|
|
return GlobalSettings::self()->excludeImportantMailFromExpiry();
|
|
}
|
|
|
|
qreal KMKernel::closeToQuotaThreshold()
|
|
{
|
|
return GlobalSettings::self()->closeToQuotaThreshold();
|
|
}
|
|
|
|
Akonadi::Entity::Id KMKernel::lastSelectedFolder()
|
|
{
|
|
return GlobalSettings::self()->lastSelectedFolder();
|
|
}
|
|
|
|
void KMKernel::setLastSelectedFolder(const Akonadi::Entity::Id& col)
|
|
{
|
|
GlobalSettings::self()->setLastSelectedFolder( col );
|
|
}
|
|
|
|
QStringList KMKernel::customTemplates()
|
|
{
|
|
return GlobalSettingsBase::self()->customTemplates();
|
|
}
|
|
|
|
void KMKernel::openFilterDialog(bool createDummyFilter)
|
|
{
|
|
if ( !mFilterEditDialog ) {
|
|
mFilterEditDialog = new MailCommon::KMFilterDialog( getKMMainWidget()->actionCollections(), 0, createDummyFilter );
|
|
mFilterEditDialog->setObjectName( QLatin1String("filterdialog") );
|
|
}
|
|
mFilterEditDialog->show();
|
|
mFilterEditDialog->raise();
|
|
mFilterEditDialog->activateWindow();
|
|
}
|
|
|
|
void KMKernel::createFilter(const QByteArray& field, const QString& value)
|
|
{
|
|
mFilterEditDialog->createFilter( field, value );
|
|
|
|
}
|
|
|
|
|
|
void KMKernel::checkFolderFromResources( const Akonadi::Collection::List &collectionList )
|
|
{
|
|
const Akonadi::AgentInstance::List lst = MailCommon::Util::agentInstances();
|
|
foreach( const Akonadi::AgentInstance& type, lst ) {
|
|
if ( type.status() == Akonadi::AgentInstance::Broken )
|
|
continue;
|
|
if ( PimCommon::Util::isImapResource(type.identifier()) ) {
|
|
OrgKdeAkonadiImapSettingsInterface *iface = PimCommon::Util::createImapSettingsInterface( type.identifier() );
|
|
if ( iface->isValid() ) {
|
|
foreach( const Akonadi::Collection& collection, collectionList ) {
|
|
const Akonadi::Collection::Id collectionId = collection.id();
|
|
if ( iface->trashCollection() == collectionId ) {
|
|
//Use default trash
|
|
iface->setTrashCollection( CommonKernel->trashCollectionFolder().id() );
|
|
iface->writeConfig();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
delete iface;
|
|
}
|
|
else if ( type.identifier().contains( POP3_RESOURCE_IDENTIFIER ) ) {
|
|
OrgKdeAkonadiPOP3SettingsInterface *iface = MailCommon::Util::createPop3SettingsInterface( type.identifier() );
|
|
if ( iface->isValid() ) {
|
|
foreach( const Akonadi::Collection& collection, collectionList ) {
|
|
const Akonadi::Collection::Id collectionId = collection.id();
|
|
if ( iface->targetCollection() == collectionId ) {
|
|
//Use default inbox
|
|
iface->setTargetCollection( CommonKernel->inboxCollectionFolder().id() );
|
|
iface->writeConfig();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
delete iface;
|
|
}
|
|
}
|
|
}
|
|
|
|
const QAbstractItemModel* KMKernel::treeviewModelSelection()
|
|
{
|
|
if ( getKMMainWidget() )
|
|
return getKMMainWidget()->folderTreeView()->selectionModel()->model();
|
|
else
|
|
return entityTreeModel();
|
|
}
|
|
|
|
void KMKernel::slotInstanceWarning(const Akonadi::AgentInstance &instance , const QString &message)
|
|
{
|
|
const QString summary = i18nc( "<source>: <error message>", "%1: %2", instance.name(), message );
|
|
if( xmlGuiInstance().isValid() ) {
|
|
KNotification::event( QLatin1String("akonadi-instance-warning"),
|
|
summary,
|
|
QPixmap(),
|
|
0,
|
|
KNotification::CloseOnTimeout,
|
|
xmlGuiInstance() );
|
|
} else {
|
|
KNotification::event( QLatin1String("akonadi-instance-warning"),
|
|
summary,
|
|
QPixmap(),
|
|
0,
|
|
KNotification::CloseOnTimeout );
|
|
}
|
|
}
|
|
|
|
void KMKernel::slotInstanceError(const Akonadi::AgentInstance &instance, const QString &message)
|
|
{
|
|
const QString summary = i18nc( "<source>: <error message>", "%1: %2", instance.name(), message );
|
|
if( xmlGuiInstance().isValid() ) {
|
|
KNotification::event( QLatin1String("akonadi-instance-error"),
|
|
summary,
|
|
QPixmap(),
|
|
0,
|
|
KNotification::CloseOnTimeout,
|
|
xmlGuiInstance() );
|
|
} else {
|
|
KNotification::event( QLatin1String("akonadi-instance-error"),
|
|
summary,
|
|
QPixmap(),
|
|
0,
|
|
KNotification::CloseOnTimeout );
|
|
}
|
|
}
|
|
|
|
|
|
void KMKernel::slotInstanceRemoved(const Akonadi::AgentInstance& instance)
|
|
{
|
|
const QString identifier(instance.identifier());
|
|
const QString resourceGroup = QString::fromLatin1( "Resource %1" ).arg( identifier );
|
|
if ( KMKernel::config()->hasGroup( resourceGroup ) ) {
|
|
KConfigGroup group( KMKernel::config(), resourceGroup );
|
|
group.deleteGroup();
|
|
group.sync();
|
|
}
|
|
if(mResourceCryptoSettingCache.contains(identifier)) {
|
|
mResourceCryptoSettingCache.remove(identifier);
|
|
}
|
|
mFolderArchiveManager->slotInstanceRemoved(instance);
|
|
}
|
|
|
|
void KMKernel::savePaneSelection()
|
|
{
|
|
KMMainWidget *widget = getKMMainWidget();
|
|
if ( widget ) {
|
|
widget->savePaneSelection();
|
|
}
|
|
}
|
|
|
|
void KMKernel::updatePaneTagComboBox()
|
|
{
|
|
KMMainWidget *widget = getKMMainWidget();
|
|
if ( widget ) {
|
|
widget->updatePaneTagComboBox();
|
|
}
|
|
}
|
|
|
|
void KMKernel::resourceGoOnLine()
|
|
{
|
|
KMMainWidget *widget = getKMMainWidget();
|
|
if ( widget ) {
|
|
if(widget->currentFolder()) {
|
|
Akonadi::Collection collection = widget->currentFolder()->collection();
|
|
Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance( collection.resource() );
|
|
instance.setIsOnline( true );
|
|
widget->clearViewer();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMKernel::makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode mode)
|
|
{
|
|
switch(mode) {
|
|
case MessageViewer::Viewer::AllResources:
|
|
resumeNetworkJobs();
|
|
break;
|
|
case MessageViewer::Viewer::SelectedResource:
|
|
resourceGoOnLine();
|
|
break;
|
|
}
|
|
}
|
|
|
|
PimCommon::AutoCorrection *KMKernel::composerAutoCorrection()
|
|
{
|
|
return mAutoCorrection;
|
|
}
|
|
|
|
void KMKernel::toggleSystemTray()
|
|
{
|
|
KMMainWidget *widget = getKMMainWidget();
|
|
if ( widget ) {
|
|
if ( !mSystemTray && GlobalSettings::self()->systemTrayEnabled() ) {
|
|
mSystemTray = new KMail::KMSystemTray(widget);
|
|
} else if ( mSystemTray && !GlobalSettings::self()->systemTrayEnabled() ) {
|
|
// Get rid of system tray on user's request
|
|
kDebug() << "deleting systray";
|
|
delete mSystemTray;
|
|
mSystemTray = 0;
|
|
}
|
|
|
|
// Set mode of systemtray. If mode has changed, tray will handle this.
|
|
if ( mSystemTray ) {
|
|
mSystemTray->setMode( GlobalSettings::self()->systemTrayPolicy() );
|
|
mSystemTray->setShowUnreadCount( GlobalSettings::self()->systemTrayShowUnread() );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void KMKernel::showFolder(const QString &collectionId)
|
|
{
|
|
if (!collectionId.isEmpty()) {
|
|
const Akonadi::Collection::Id id = collectionId.toLongLong();
|
|
selectCollectionFromId(id);
|
|
}
|
|
}
|
|
|
|
void KMKernel::reloadFolderArchiveConfig()
|
|
{
|
|
mFolderArchiveManager->reloadConfig();
|
|
}
|
|
|
|
void KMKernel::slotCollectionChanged(const Akonadi::Collection &, const QSet<QByteArray> &set)
|
|
{
|
|
if(set.contains("newmailnotifierattribute")) {
|
|
if ( mSystemTray ) {
|
|
mSystemTray->updateSystemTray();
|
|
}
|
|
}
|
|
}
|
|
|
|
FolderArchiveManager *KMKernel::folderArchiveManager() const
|
|
{
|
|
return mFolderArchiveManager;
|
|
}
|
|
|
|
PimCommon::StorageServiceManager *KMKernel::storageServiceManager() const
|
|
{
|
|
return mStorageManager;
|
|
}
|
|
|
|
bool KMKernel::allowToDebugBalooSupport() const
|
|
{
|
|
return mDebugBaloo;
|
|
}
|