kde-playground/akonadi/server/control/agentmanager.cpp

888 lines
29 KiB
C++
Raw Normal View History

2015-09-23 09:37:02 +00:00
/***************************************************************************
* 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 );
}