mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 19:02:51 +00:00
887 lines
29 KiB
C++
887 lines
29 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2006 by Tobias Koenig <tokoe@kde.org> *
|
|
* Copyright (c) 2007 Volker Krause <vkrause@kde.org> *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Library General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of the *
|
|
* License, or (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
***************************************************************************/
|
|
|
|
#include "agentmanager.h"
|
|
|
|
#include "agentmanageradaptor.h"
|
|
#include "agentmanagerinternaladaptor.h"
|
|
#include "agentprocessinstance.h"
|
|
#include "agentserverinterface.h"
|
|
#include "agentthreadinstance.h"
|
|
#include "akdebug.h"
|
|
#include "libs/protocol_p.h"
|
|
#include "libs/xdgbasedirs_p.h"
|
|
#include "preprocessor_manager.h"
|
|
#include "processcontrol.h"
|
|
#include "resource_manager.h"
|
|
#include "serverinterface.h"
|
|
|
|
#include <akapplication.h>
|
|
#include <akdbus.h>
|
|
#include <akstandarddirs.h>
|
|
|
|
#include <QtCore/QCoreApplication>
|
|
#include <QtCore/QDebug>
|
|
#include <QtCore/QDir>
|
|
#ifndef QT_NO_DEBUG
|
|
#include <QtCore/QFileSystemWatcher>
|
|
#endif
|
|
#include <QtCore/QSettings>
|
|
#include <QtDBus/QDBusConnection>
|
|
#include <QtDBus/QDBusError>
|
|
|
|
#include <boost/scoped_ptr.hpp>
|
|
|
|
using Akonadi::ProcessControl;
|
|
|
|
#if defined(Q_WS_MAEMO_5)
|
|
static bool enableAgentServerDefault = true;
|
|
#else
|
|
static bool enableAgentServerDefault = false;
|
|
#endif
|
|
|
|
AgentManager::AgentManager( QObject *parent )
|
|
: QObject( parent )
|
|
, mAgentServer( 0 )
|
|
#ifndef QT_NO_DEBUG
|
|
, mAgentWatcher( new QFileSystemWatcher( this ) )
|
|
#endif
|
|
{
|
|
new AgentManagerAdaptor( this );
|
|
new AgentManagerInternalAdaptor( this );
|
|
QDBusConnection::sessionBus().registerObject( QLatin1String( "/AgentManager" ), this );
|
|
|
|
connect( QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
|
|
this, SLOT(serviceOwnerChanged(QString,QString,QString)) );
|
|
|
|
if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( AkDBus::serviceName( AkDBus::Server ) ) ) {
|
|
akFatal() << "akonadiserver already running!";
|
|
}
|
|
|
|
const QSettings settings( AkStandardDirs::agentConfigFile( Akonadi::XdgBaseDirs::ReadOnly ), QSettings::IniFormat );
|
|
mAgentServerEnabled = settings.value( QLatin1String( "AgentServer/Enabled" ), enableAgentServerDefault ).toBool();
|
|
|
|
QStringList serviceArgs;
|
|
if ( AkApplication::hasInstanceIdentifier() ) {
|
|
serviceArgs << QLatin1String( "--instance" ) << AkApplication::instanceIdentifier();
|
|
}
|
|
|
|
mStorageController = new Akonadi::ProcessControl;
|
|
mStorageController->setShutdownTimeout( 15 * 1000 ); // the server needs more time for shutdown if we are using an internal mysqld
|
|
connect( mStorageController, SIGNAL(unableToStart()), SLOT(serverFailure()) );
|
|
mStorageController->start( QLatin1String( "akonadiserver" ), serviceArgs, Akonadi::ProcessControl::RestartOnCrash );
|
|
|
|
if ( mAgentServerEnabled ) {
|
|
mAgentServer = new Akonadi::ProcessControl;
|
|
connect( mAgentServer, SIGNAL(unableToStart()), SLOT(agentServerFailure()) );
|
|
mAgentServer->start( QLatin1String( "akonadi_agent_server" ), serviceArgs, Akonadi::ProcessControl::RestartOnCrash );
|
|
}
|
|
|
|
#ifndef QT_NO_DEBUG
|
|
connect( mAgentWatcher, SIGNAL(fileChanged(QString)), SLOT(agentExeChanged(QString)) );
|
|
#endif
|
|
}
|
|
|
|
void AgentManager::continueStartup()
|
|
{
|
|
// prevent multiple calls in case the server has to be restarted
|
|
static bool first = true;
|
|
if ( !first ) {
|
|
return;
|
|
}
|
|
|
|
first = false;
|
|
|
|
readPluginInfos();
|
|
Q_FOREACH ( const AgentType &info, mAgents ) {
|
|
Q_EMIT agentTypeAdded( info.identifier );
|
|
}
|
|
|
|
const QStringList pathList = pluginInfoPathList();
|
|
|
|
#ifndef QT_NO_DEBUG
|
|
Q_FOREACH ( const QString &path, pathList ) {
|
|
QFileSystemWatcher *watcher = new QFileSystemWatcher( this );
|
|
watcher->addPath( path );
|
|
|
|
connect( watcher, SIGNAL(directoryChanged(QString)),
|
|
this, SLOT(updatePluginInfos()) );
|
|
}
|
|
#endif
|
|
|
|
load();
|
|
Q_FOREACH ( const AgentType &info, mAgents ) {
|
|
ensureAutoStart( info );
|
|
}
|
|
|
|
// register the real service name once everything is up an running
|
|
if ( !QDBusConnection::sessionBus().registerService( AkDBus::serviceName( AkDBus::Control ) ) ) {
|
|
// besides a race with an older Akonadi server I have no idea how we could possibly get here...
|
|
akFatal() << "Unable to register service as" << AkDBus::serviceName( AkDBus::Control )
|
|
<< "despite having the lock. Error was:" << QDBusConnection::sessionBus().lastError().message();
|
|
}
|
|
akDebug() << "Akonadi server is now operational.";
|
|
}
|
|
|
|
AgentManager::~AgentManager()
|
|
{
|
|
cleanup();
|
|
}
|
|
|
|
void AgentManager::cleanup()
|
|
{
|
|
Q_FOREACH ( const AgentInstance::Ptr &instance, mAgentInstances ) {
|
|
instance->quit();
|
|
}
|
|
|
|
mAgentInstances.clear();
|
|
|
|
mStorageController->setCrashPolicy( ProcessControl::StopOnCrash );
|
|
org::freedesktop::Akonadi::Server *serverIface =
|
|
new org::freedesktop::Akonadi::Server( AkDBus::serviceName( AkDBus::Server ), QLatin1String( "/Server" ),
|
|
QDBusConnection::sessionBus(), this );
|
|
serverIface->quit();
|
|
|
|
if ( mAgentServer ) {
|
|
mAgentServer->setCrashPolicy( ProcessControl::StopOnCrash );
|
|
org::freedesktop::Akonadi::AgentServer *agentServerIface =
|
|
new org::freedesktop::Akonadi::AgentServer( AkDBus::serviceName( AkDBus::AgentServer ),
|
|
QLatin1String( "/AgentServer" ), QDBusConnection::sessionBus(), this );
|
|
agentServerIface->quit();
|
|
}
|
|
|
|
delete mStorageController;
|
|
mStorageController = 0;
|
|
|
|
delete mAgentServer;
|
|
mAgentServer = 0;
|
|
}
|
|
|
|
QStringList AgentManager::agentTypes() const
|
|
{
|
|
return mAgents.keys();
|
|
}
|
|
|
|
QString AgentManager::agentName( const QString &identifier, const QString &language ) const
|
|
{
|
|
if ( !checkAgentExists( identifier ) ) {
|
|
return QString();
|
|
}
|
|
|
|
const QString name = mAgents.value( identifier ).name.value( language );
|
|
return name.isEmpty() ? mAgents.value( identifier ).name.value( QLatin1String( "en_US" ) ) : name;
|
|
}
|
|
|
|
QString AgentManager::agentComment( const QString &identifier, const QString &language ) const
|
|
{
|
|
if ( !checkAgentExists( identifier ) ) {
|
|
return QString();
|
|
}
|
|
|
|
const QString comment = mAgents.value( identifier ).comment.value( language );
|
|
return comment.isEmpty() ? mAgents.value( identifier ).comment.value( QLatin1String( "en_US" ) ) : comment;
|
|
}
|
|
|
|
QString AgentManager::agentIcon( const QString &identifier ) const
|
|
{
|
|
if ( !checkAgentExists( identifier ) ) {
|
|
return QString();
|
|
}
|
|
|
|
const AgentType info = mAgents.value( identifier );
|
|
if ( !info.icon.isEmpty() ) {
|
|
return info.icon;
|
|
}
|
|
|
|
return QLatin1String( "application-x-executable" );
|
|
}
|
|
|
|
QStringList AgentManager::agentMimeTypes( const QString &identifier ) const
|
|
{
|
|
if ( !checkAgentExists( identifier ) ) {
|
|
return QStringList();
|
|
}
|
|
|
|
return mAgents.value( identifier ).mimeTypes;
|
|
}
|
|
|
|
QStringList AgentManager::agentCapabilities( const QString &identifier ) const
|
|
{
|
|
if ( !checkAgentExists( identifier ) ) {
|
|
return QStringList();
|
|
}
|
|
return mAgents.value( identifier ).capabilities;
|
|
}
|
|
|
|
QVariantMap AgentManager::agentCustomProperties( const QString &identifier ) const
|
|
{
|
|
if ( !checkAgentExists( identifier ) ) {
|
|
return QVariantMap();
|
|
}
|
|
|
|
return mAgents.value( identifier ).custom;
|
|
}
|
|
|
|
AgentInstance::Ptr AgentManager::createAgentInstance( const AgentType &info )
|
|
{
|
|
switch ( info.launchMethod ) {
|
|
case AgentType::Server:
|
|
return AgentInstance::Ptr( new Akonadi::AgentThreadInstance( this ) );
|
|
case AgentType::Launcher: // Fall through
|
|
case AgentType::Process:
|
|
return AgentInstance::Ptr( new Akonadi::AgentProcessInstance( this ) );
|
|
default:
|
|
Q_ASSERT_X( false, "AgentManger::createAgentInstance", "Unhandled AgentType::LaunchMethod case" );
|
|
}
|
|
|
|
return AgentInstance::Ptr();
|
|
}
|
|
|
|
QString AgentManager::createAgentInstance( const QString &identifier )
|
|
{
|
|
if ( !checkAgentExists( identifier ) ) {
|
|
return QString();
|
|
}
|
|
|
|
const AgentType agentInfo = mAgents.value( identifier );
|
|
mAgents[identifier].instanceCounter++;
|
|
|
|
const AgentInstance::Ptr instance = createAgentInstance( agentInfo );
|
|
if ( agentInfo.capabilities.contains( AgentType::CapabilityUnique ) ) {
|
|
instance->setIdentifier( identifier );
|
|
} else {
|
|
instance->setIdentifier( QString::fromLatin1( "%1_%2" ).arg( identifier, QString::number( agentInfo.instanceCounter ) ) );
|
|
}
|
|
|
|
if ( mAgentInstances.contains( instance->identifier() ) ) {
|
|
akError() << Q_FUNC_INFO << "Cannot create another instance of agent" << identifier;
|
|
return QString();
|
|
}
|
|
|
|
// Return from this dbus call before we do the next. Otherwise dbus brakes for
|
|
// this process.
|
|
if ( calledFromDBus() ) {
|
|
connection().send( message().createReply( instance->identifier() ) );
|
|
}
|
|
|
|
if ( !instance->start( agentInfo ) ) {
|
|
return QString();
|
|
}
|
|
|
|
mAgentInstances.insert( instance->identifier(), instance );
|
|
registerAgentAtServer( instance->identifier(), agentInfo );
|
|
save();
|
|
|
|
return instance->identifier();
|
|
}
|
|
|
|
void AgentManager::removeAgentInstance( const QString &identifier )
|
|
{
|
|
if ( !mAgentInstances.contains( identifier ) ) {
|
|
akError() << Q_FUNC_INFO << "Agent instance with identifier" << identifier << "does not exist";
|
|
return;
|
|
}
|
|
|
|
const AgentInstance::Ptr instance = mAgentInstances.value( identifier );
|
|
if ( instance->hasAgentInterface() ) {
|
|
instance->cleanup();
|
|
} else {
|
|
akError() << Q_FUNC_INFO << "Agent instance" << identifier << "has no interface!";
|
|
}
|
|
|
|
mAgentInstances.remove( identifier );
|
|
|
|
save();
|
|
|
|
org::freedesktop::Akonadi::ResourceManager resmanager( AkDBus::serviceName( AkDBus::Server ), QLatin1String( "/ResourceManager" ), QDBusConnection::sessionBus(), this );
|
|
resmanager.removeResourceInstance( instance->identifier() );
|
|
|
|
// Kill the preprocessor instance, if any.
|
|
org::freedesktop::Akonadi::PreprocessorManager preProcessorManager(
|
|
AkDBus::serviceName( AkDBus::Server ),
|
|
QLatin1String( "/PreprocessorManager" ),
|
|
QDBusConnection::sessionBus(),
|
|
this );
|
|
|
|
preProcessorManager.unregisterInstance( instance->identifier() );
|
|
|
|
if ( instance->hasAgentInterface() ) {
|
|
akDebug() << "AgentManager::removeAgentInstance: calling instance->quit()";
|
|
instance->quit();
|
|
} else {
|
|
akError() << Q_FUNC_INFO << "Agent instance" << identifier << "has no interface!";
|
|
}
|
|
|
|
Q_EMIT agentInstanceRemoved( identifier );
|
|
}
|
|
|
|
QString AgentManager::agentInstanceType( const QString &identifier )
|
|
{
|
|
if ( !mAgentInstances.contains( identifier ) ) {
|
|
akError() << Q_FUNC_INFO << "Agent instance with identifier" << identifier << "does not exist";
|
|
return QString();
|
|
}
|
|
|
|
return mAgentInstances.value( identifier )->agentType();
|
|
}
|
|
|
|
QStringList AgentManager::agentInstances() const
|
|
{
|
|
return mAgentInstances.keys();
|
|
}
|
|
|
|
int AgentManager::agentInstanceStatus( const QString &identifier ) const
|
|
{
|
|
if ( !checkInstance( identifier ) ) {
|
|
return 2;
|
|
}
|
|
|
|
return mAgentInstances.value( identifier )->status();
|
|
}
|
|
|
|
QString AgentManager::agentInstanceStatusMessage( const QString &identifier ) const
|
|
{
|
|
if ( !checkInstance( identifier ) ) {
|
|
return QString();
|
|
}
|
|
|
|
return mAgentInstances.value( identifier )->statusMessage();
|
|
}
|
|
|
|
uint AgentManager::agentInstanceProgress( const QString &identifier ) const
|
|
{
|
|
if ( !checkInstance( identifier ) ) {
|
|
return 0;
|
|
}
|
|
|
|
return mAgentInstances.value( identifier )->progress();
|
|
}
|
|
|
|
QString AgentManager::agentInstanceProgressMessage( const QString &identifier ) const
|
|
{
|
|
Q_UNUSED( identifier );
|
|
|
|
return QString();
|
|
}
|
|
|
|
void AgentManager::agentInstanceConfigure( const QString &identifier, qlonglong windowId )
|
|
{
|
|
if ( !checkAgentInterfaces( identifier, QLatin1String( "agentInstanceConfigure" ) ) ) {
|
|
return;
|
|
}
|
|
|
|
mAgentInstances.value( identifier )->configure( windowId );
|
|
}
|
|
|
|
bool AgentManager::agentInstanceOnline( const QString &identifier )
|
|
{
|
|
if ( !checkInstance( identifier ) ) {
|
|
return false;
|
|
}
|
|
|
|
return mAgentInstances.value( identifier )->isOnline();
|
|
}
|
|
|
|
void AgentManager::setAgentInstanceOnline( const QString &identifier, bool state )
|
|
{
|
|
if ( !checkAgentInterfaces( identifier, QLatin1String( "setAgentInstanceOnline" ) ) ) {
|
|
return;
|
|
}
|
|
|
|
mAgentInstances.value( identifier )->statusInterface()->setOnline( state );
|
|
}
|
|
|
|
// resource specific methods //
|
|
void AgentManager::setAgentInstanceName( const QString &identifier, const QString &name )
|
|
{
|
|
if ( !checkResourceInterface( identifier, QLatin1String( "setAgentInstanceName" ) ) ) {
|
|
return;
|
|
}
|
|
|
|
mAgentInstances.value( identifier )->resourceInterface()->setName( name );
|
|
}
|
|
|
|
QString AgentManager::agentInstanceName( const QString &identifier, const QString &language ) const
|
|
{
|
|
if ( !checkInstance( identifier ) ) {
|
|
return QString();
|
|
}
|
|
|
|
const AgentInstance::Ptr instance = mAgentInstances.value( identifier );
|
|
if ( !instance->resourceName().isEmpty() ) {
|
|
return instance->resourceName();
|
|
}
|
|
|
|
if ( !checkAgentExists( instance->agentType() ) ) {
|
|
return QString();
|
|
}
|
|
|
|
const QString name = mAgents.value( instance->agentType() ).name.value( language );
|
|
return name.isEmpty() ? mAgents.value( instance->agentType() ).name.value( QLatin1String( "en_US" ) ) : name;
|
|
}
|
|
|
|
void AgentManager::agentInstanceSynchronize( const QString &identifier )
|
|
{
|
|
if ( !checkResourceInterface( identifier, QLatin1String( "agentInstanceSynchronize" ) ) ) {
|
|
return;
|
|
}
|
|
|
|
mAgentInstances.value( identifier )->resourceInterface()->synchronize();
|
|
}
|
|
|
|
void AgentManager::agentInstanceSynchronizeCollectionTree( const QString &identifier )
|
|
{
|
|
if ( !checkResourceInterface( identifier, QLatin1String( "agentInstanceSynchronizeCollectionTree" ) ) ) {
|
|
return;
|
|
}
|
|
|
|
mAgentInstances.value( identifier )->resourceInterface()->synchronizeCollectionTree();
|
|
}
|
|
|
|
void AgentManager::agentInstanceSynchronizeCollection( const QString &identifier, qint64 collection )
|
|
{
|
|
agentInstanceSynchronizeCollection( identifier, collection, false );
|
|
}
|
|
|
|
void AgentManager::agentInstanceSynchronizeCollection( const QString &identifier, qint64 collection, bool recursive )
|
|
{
|
|
if ( !checkResourceInterface( identifier, QLatin1String( "agentInstanceSynchronizeCollection" ) ) ) {
|
|
return;
|
|
}
|
|
|
|
mAgentInstances.value( identifier )->resourceInterface()->synchronizeCollection( collection, recursive );
|
|
}
|
|
|
|
void AgentManager::restartAgentInstance( const QString &identifier )
|
|
{
|
|
if ( !checkInstance( identifier ) ) {
|
|
return;
|
|
}
|
|
|
|
mAgentInstances.value( identifier )->restartWhenIdle();
|
|
}
|
|
|
|
void AgentManager::updatePluginInfos()
|
|
{
|
|
const QHash<QString, AgentType> oldInfos = mAgents;
|
|
readPluginInfos();
|
|
|
|
Q_FOREACH ( const AgentType &oldInfo, oldInfos ) {
|
|
if ( !mAgents.contains( oldInfo.identifier ) ) {
|
|
Q_EMIT agentTypeRemoved( oldInfo.identifier );
|
|
}
|
|
}
|
|
|
|
Q_FOREACH ( const AgentType &newInfo, mAgents ) {
|
|
if ( !oldInfos.contains( newInfo.identifier ) ) {
|
|
Q_EMIT agentTypeAdded( newInfo.identifier );
|
|
ensureAutoStart( newInfo );
|
|
}
|
|
}
|
|
}
|
|
|
|
void AgentManager::readPluginInfos()
|
|
{
|
|
#ifndef QT_NO_DEBUG
|
|
if ( !mAgentWatcher->files().isEmpty() ) {
|
|
mAgentWatcher->removePaths( mAgentWatcher->files() );
|
|
}
|
|
#endif
|
|
mAgents.clear();
|
|
|
|
const QStringList pathList = pluginInfoPathList();
|
|
|
|
Q_FOREACH ( const QString &path, pathList ) {
|
|
const QDir directory( path, QLatin1String( "*.desktop" ) );
|
|
readPluginInfos( directory );
|
|
}
|
|
}
|
|
|
|
void AgentManager::readPluginInfos( const QDir &directory )
|
|
{
|
|
const QStringList files = directory.entryList();
|
|
akDebug() << "PLUGINS: " << directory.canonicalPath();
|
|
akDebug() << "PLUGINS: " << files;
|
|
|
|
for ( int i = 0; i < files.count(); ++i ) {
|
|
const QString fileName = directory.absoluteFilePath( files[i] );
|
|
|
|
AgentType agentInfo;
|
|
if ( agentInfo.load( fileName, this ) ) {
|
|
if ( mAgents.contains( agentInfo.identifier ) ) {
|
|
akError() << Q_FUNC_INFO << "Duplicated agent identifier" << agentInfo.identifier << "from file" << fileName;
|
|
continue;
|
|
}
|
|
|
|
const QString disableAutostart = getEnv( "AKONADI_DISABLE_AGENT_AUTOSTART" );
|
|
if ( !disableAutostart.isEmpty() ) {
|
|
akDebug() << "Autostarting of agents is disabled.";
|
|
agentInfo.capabilities.removeOne( AgentType::CapabilityAutostart );
|
|
}
|
|
|
|
if ( !mAgentServerEnabled && agentInfo.launchMethod == AgentType::Server ) {
|
|
agentInfo.launchMethod = AgentType::Launcher;
|
|
}
|
|
|
|
if ( agentInfo.launchMethod == AgentType::Process ) {
|
|
const QString executable = Akonadi::XdgBaseDirs::findExecutableFile( agentInfo.exec );
|
|
if ( executable.isEmpty() ) {
|
|
akError() << "Executable" << agentInfo.exec << "for agent" << agentInfo.identifier << "could not be found!";
|
|
continue;
|
|
}
|
|
#ifndef QT_NO_DEBUG
|
|
if ( !mAgentWatcher->files().contains( executable ) ) {
|
|
mAgentWatcher->addPath( executable );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
akDebug() << "PLUGINS inserting: " << agentInfo.identifier << agentInfo.instanceCounter << agentInfo.capabilities;
|
|
mAgents.insert( agentInfo.identifier, agentInfo );
|
|
}
|
|
}
|
|
}
|
|
|
|
QStringList AgentManager::pluginInfoPathList()
|
|
{
|
|
return Akonadi::XdgBaseDirs::findAllResourceDirs( "data", QLatin1String( "akonadi/agents" ) );
|
|
}
|
|
|
|
void AgentManager::load()
|
|
{
|
|
org::freedesktop::Akonadi::ResourceManager resmanager( AkDBus::serviceName( AkDBus::Server ), QLatin1String( "/ResourceManager" ), QDBusConnection::sessionBus(), this );
|
|
const QStringList knownResources = resmanager.resourceInstances();
|
|
|
|
QSettings file( AkStandardDirs::agentConfigFile( Akonadi::XdgBaseDirs::ReadOnly ), QSettings::IniFormat );
|
|
file.beginGroup( QLatin1String( "Instances" ) );
|
|
const QStringList entries = file.childGroups();
|
|
for ( int i = 0; i < entries.count(); ++i ) {
|
|
const QString instanceIdentifier = entries[i];
|
|
|
|
if ( mAgentInstances.contains( instanceIdentifier ) ) {
|
|
akError() << Q_FUNC_INFO << "Duplicated instance identifier" << instanceIdentifier << "found in agentsrc";
|
|
continue;
|
|
}
|
|
|
|
file.beginGroup( entries[i] );
|
|
|
|
const QString agentType = file.value( QLatin1String( "AgentType" ) ).toString();
|
|
if ( !mAgents.contains( agentType ) ) {
|
|
akError() << Q_FUNC_INFO << "Reference to unknown agent type" << agentType << "in agentsrc";
|
|
file.endGroup();
|
|
continue;
|
|
}
|
|
const AgentType type = mAgents.value( agentType );
|
|
|
|
// recover if the db has been deleted in the meantime or got otherwise corrupted
|
|
if ( !knownResources.contains( instanceIdentifier ) && type.capabilities.contains( AgentType::CapabilityResource ) ) {
|
|
akDebug() << "Recovering instance" << instanceIdentifier << "after database loss";
|
|
registerAgentAtServer( instanceIdentifier, type );
|
|
}
|
|
|
|
const AgentInstance::Ptr instance = createAgentInstance( type );
|
|
instance->setIdentifier( instanceIdentifier );
|
|
if ( instance->start( type ) ) {
|
|
mAgentInstances.insert( instanceIdentifier, instance );
|
|
}
|
|
|
|
file.endGroup();
|
|
}
|
|
|
|
file.endGroup();
|
|
}
|
|
|
|
void AgentManager::save()
|
|
{
|
|
QSettings file( AkStandardDirs::agentConfigFile( Akonadi::XdgBaseDirs::WriteOnly ), QSettings::IniFormat );
|
|
|
|
Q_FOREACH ( const AgentType &info, mAgents ) {
|
|
info.save( &file );
|
|
}
|
|
|
|
file.beginGroup( QLatin1String( "Instances" ) );
|
|
file.remove( QString() );
|
|
Q_FOREACH ( const AgentInstance::Ptr &instance, mAgentInstances ) {
|
|
file.beginGroup( instance->identifier() );
|
|
file.setValue( QLatin1String( "AgentType" ), instance->agentType() );
|
|
file.endGroup();
|
|
}
|
|
|
|
file.endGroup();
|
|
|
|
file.sync();
|
|
}
|
|
|
|
void AgentManager::serviceOwnerChanged( const QString &name, const QString &oldOwner, const QString &newOwner )
|
|
{
|
|
Q_UNUSED( oldOwner );
|
|
// This is called by the D-Bus server when a service comes up, goes down or changes ownership for some reason
|
|
// and this is where we "hook up" our different Agent interfaces.
|
|
|
|
//akDebug() << "Service " << name << " owner changed from " << oldOwner << " to " << newOwner;
|
|
|
|
if ( ( name == AkDBus::serviceName( AkDBus::Server ) || name == AkDBus::serviceName( AkDBus::AgentServer ) ) && !newOwner.isEmpty() ) {
|
|
if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( AkDBus::serviceName( AkDBus::Server ) )
|
|
&& ( !mAgentServer || QDBusConnection::sessionBus().interface()->isServiceRegistered( AkDBus::serviceName( AkDBus::AgentServer ) ) ) ) {
|
|
// server is operational, start agents
|
|
continueStartup();
|
|
}
|
|
}
|
|
|
|
AkDBus::AgentType agentType = AkDBus::Unknown;
|
|
const QString agentIdentifier = AkDBus::parseAgentServiceName( name, agentType );
|
|
switch ( agentType ) {
|
|
case AkDBus::Agent:
|
|
{
|
|
// An agent service went up or down
|
|
if ( newOwner.isEmpty() ) {
|
|
return; // It went down: we don't care here.
|
|
}
|
|
|
|
if ( !mAgentInstances.contains( agentIdentifier ) ) {
|
|
return;
|
|
}
|
|
|
|
const AgentInstance::Ptr instance = mAgentInstances.value( agentIdentifier );
|
|
const bool restarting = instance->hasAgentInterface();
|
|
if ( !instance->obtainAgentInterface() ) {
|
|
return;
|
|
}
|
|
|
|
if ( !restarting ) {
|
|
Q_EMIT agentInstanceAdded( agentIdentifier );
|
|
}
|
|
|
|
break;
|
|
}
|
|
case AkDBus::Resource:
|
|
{
|
|
// A resource service went up or down
|
|
if ( newOwner.isEmpty() ) {
|
|
return; // It went down: we don't care here.
|
|
}
|
|
|
|
if ( !mAgentInstances.contains( agentIdentifier ) ) {
|
|
return;
|
|
}
|
|
|
|
mAgentInstances.value( agentIdentifier )->obtainResourceInterface();
|
|
|
|
break;
|
|
}
|
|
case AkDBus::Preprocessor:
|
|
{
|
|
// A preprocessor service went up or down
|
|
|
|
// If the preprocessor is going up then the org.freedesktop.Akonadi.Agent.* interface
|
|
// should be already up (as it's registered before the preprocessor one).
|
|
// So if we don't know about the preprocessor as agent instance
|
|
// then it's not our preprocessor.
|
|
|
|
// If the preprocessor is going down then either the agent interface already
|
|
// went down (and it has been already unregistered on the manager side)
|
|
// or it's still registered as agent and WE have to unregister it.
|
|
// The order of interface deletions depends on Qt but we handle both cases.
|
|
|
|
// Check if we "know" about it.
|
|
akDebug() << "Preprocessor " << agentIdentifier << " is going up or down...";
|
|
|
|
if ( !mAgentInstances.contains( agentIdentifier ) ) {
|
|
akDebug() << "But it isn't registered as agent... not mine (anymore?)";
|
|
return; // not our agent (?)
|
|
}
|
|
|
|
org::freedesktop::Akonadi::PreprocessorManager preProcessorManager(
|
|
AkDBus::serviceName( AkDBus::Server ),
|
|
QLatin1String( "/PreprocessorManager" ),
|
|
QDBusConnection::sessionBus(),
|
|
this );
|
|
|
|
if ( !preProcessorManager.isValid() ) {
|
|
akError() << Q_FUNC_INFO << "Could not connect to PreprocessorManager via D-Bus:" << preProcessorManager.lastError().message();
|
|
} else {
|
|
if ( newOwner.isEmpty() ) {
|
|
// The preprocessor went down. Unregister it on server side.
|
|
|
|
preProcessorManager.unregisterInstance( agentIdentifier );
|
|
|
|
} else {
|
|
|
|
// The preprocessor went up. Register it on server side.
|
|
|
|
if ( !mAgentInstances.value( agentIdentifier )->obtainPreprocessorInterface() ) {
|
|
// Hm.. couldn't hook up its preprocessor interface..
|
|
// Make sure we don't have it in the preprocessor chain
|
|
qWarning() << "Couldn't obtain preprocessor interface for instance" << agentIdentifier;
|
|
|
|
preProcessorManager.unregisterInstance( agentIdentifier );
|
|
return;
|
|
}
|
|
|
|
akDebug() << "Registering preprocessor instance" << agentIdentifier;
|
|
|
|
// Add to the preprocessor chain
|
|
preProcessorManager.registerInstance( agentIdentifier );
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
bool AgentManager::checkInstance( const QString &identifier ) const
|
|
{
|
|
if ( !mAgentInstances.contains( identifier ) ) {
|
|
qWarning() << "Agent instance with identifier " << identifier << " does not exist";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AgentManager::checkResourceInterface( const QString &identifier, const QString &method ) const
|
|
{
|
|
if ( !checkInstance( identifier ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !mAgents[mAgentInstances[identifier]->agentType()].capabilities.contains( QLatin1String( "Resource" ) ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !mAgentInstances[identifier]->hasResourceInterface() ) {
|
|
qWarning() << QLatin1String( "AgentManager::" ) + method << " Agent instance "
|
|
<< identifier << " has no resource interface!";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AgentManager::checkAgentExists( const QString &identifier ) const
|
|
{
|
|
if ( !mAgents.contains( identifier ) ) {
|
|
qWarning() << "Agent instance " << identifier << " does not exist.";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AgentManager::checkAgentInterfaces( const QString &identifier, const QString &method ) const
|
|
{
|
|
if ( !checkInstance( identifier ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !mAgentInstances.value( identifier )->hasAgentInterface() ) {
|
|
qWarning() << "Agent instance (" << method << ") " << identifier << " has no agent interface.";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void AgentManager::ensureAutoStart( const AgentType &info )
|
|
{
|
|
if ( !info.capabilities.contains( AgentType::CapabilityAutostart ) ) {
|
|
return; // no an autostart agent
|
|
}
|
|
|
|
org::freedesktop::Akonadi::AgentServer agentServer( AkDBus::serviceName( AkDBus::AgentServer ),
|
|
QLatin1String( "/AgentServer" ), QDBusConnection::sessionBus(), this );
|
|
|
|
if ( mAgentInstances.contains( info.identifier ) ||
|
|
( agentServer.isValid() && agentServer.started( info.identifier ) ) ) {
|
|
return; // already running
|
|
}
|
|
|
|
const AgentInstance::Ptr instance = createAgentInstance( info );
|
|
instance->setIdentifier( info.identifier );
|
|
if ( instance->start( info ) ) {
|
|
mAgentInstances.insert( instance->identifier(), instance );
|
|
registerAgentAtServer( instance->identifier(), info );
|
|
save();
|
|
}
|
|
}
|
|
|
|
void AgentManager::agentExeChanged( const QString &fileName )
|
|
{
|
|
if ( !QFile::exists( fileName ) ) {
|
|
return;
|
|
}
|
|
|
|
Q_FOREACH ( const AgentType &type, mAgents ) {
|
|
if ( fileName.endsWith( type.exec ) ) {
|
|
Q_FOREACH ( const AgentInstance::Ptr &instance, mAgentInstances ) {
|
|
if ( instance->agentType() == type.identifier ) {
|
|
instance->restartWhenIdle();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AgentManager::registerAgentAtServer( const QString &agentIdentifier, const AgentType &type )
|
|
{
|
|
if ( type.capabilities.contains( AgentType::CapabilityResource ) ) {
|
|
boost::scoped_ptr<org::freedesktop::Akonadi::ResourceManager> resmanager(
|
|
new org::freedesktop::Akonadi::ResourceManager( AkDBus::serviceName( AkDBus::Server ),
|
|
QLatin1String( "/ResourceManager" ),
|
|
QDBusConnection::sessionBus(), this ) );
|
|
resmanager->addResourceInstance( agentIdentifier, type.capabilities );
|
|
}
|
|
}
|
|
|
|
void AgentManager::addSearch( const QString &query, const QString &queryLanguage, qint64 resultCollectionId )
|
|
{
|
|
akDebug() << "AgentManager::addSearch" << query << queryLanguage << resultCollectionId;
|
|
Q_FOREACH ( const AgentInstance::Ptr &instance, mAgentInstances ) {
|
|
const AgentType type = mAgents.value( instance->agentType() );
|
|
if ( type.capabilities.contains( AgentType::CapabilitySearch ) && instance->searchInterface() ) {
|
|
instance->searchInterface()->addSearch( query, queryLanguage, resultCollectionId );
|
|
}
|
|
}
|
|
}
|
|
|
|
void AgentManager::removeSearch( quint64 resultCollectionId )
|
|
{
|
|
akDebug() << "AgentManager::removeSearch" << resultCollectionId;
|
|
Q_FOREACH ( const AgentInstance::Ptr &instance, mAgentInstances ) {
|
|
const AgentType type = mAgents.value( instance->agentType() );
|
|
if ( type.capabilities.contains( AgentType::CapabilitySearch ) && instance->searchInterface() ) {
|
|
instance->searchInterface()->removeSearch( resultCollectionId );
|
|
}
|
|
}
|
|
}
|
|
|
|
void AgentManager::agentServerFailure()
|
|
{
|
|
akError() << "Failed to start AgentServer!";
|
|
// if ( requiresAgentServer )
|
|
// QCoreApplication::instance()->exit( 255 );
|
|
}
|
|
|
|
void AgentManager::serverFailure()
|
|
{
|
|
QCoreApplication::instance()->exit( 255 );
|
|
}
|