diff --git a/licq/include/licq/plugin/CMakeLists.txt b/licq/include/licq/plugin/CMakeLists.txt index 29871cde3..a6c27ccd6 100644 --- a/licq/include/licq/plugin/CMakeLists.txt +++ b/licq/include/licq/plugin/CMakeLists.txt @@ -2,14 +2,17 @@ set(licq_HEADERS generalplugin.h generalpluginfactory.h generalpluginhelper.h + generalplugininstance.h generalplugininterface.h plugin.h pluginfactory.h + plugininstance.h plugininterface.h pluginmanager.h protocolplugin.h protocolpluginfactory.h protocolpluginhelper.h + protocolplugininstance.h protocolplugininterface.h ) diff --git a/licq/include/licq/plugin/generalplugin.h b/licq/include/licq/plugin/generalplugin.h index cb8b9f175..a4c8e71da 100644 --- a/licq/include/licq/plugin/generalplugin.h +++ b/licq/include/licq/plugin/generalplugin.h @@ -20,6 +20,7 @@ #ifndef LICQ_GENERALPLUGIN_H #define LICQ_GENERALPLUGIN_H +#include "generalplugininstance.h" #include "plugin.h" namespace Licq @@ -44,14 +45,9 @@ class GeneralPlugin : public virtual Plugin /// to BASE_DIR virtual std::string configFile() const = 0; - /// Get the plugin's status. - virtual bool isEnabled() const = 0; - - /// Ask the plugin to enable itself - virtual void enable() = 0; - - /// Ask the plugin to disable itself - virtual void disable() = 0; + /// Get the plugin instance for this plugin. May be NULL if the instance has + /// exited. + virtual GeneralPluginInstance::Ptr instance() const = 0; protected: /// Destructor diff --git a/licq/include/licq/plugin/generalplugininstance.h b/licq/include/licq/plugin/generalplugininstance.h new file mode 100644 index 000000000..11062d056 --- /dev/null +++ b/licq/include/licq/plugin/generalplugininstance.h @@ -0,0 +1,59 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LICQ_GENERALPLUGININSTANCE_H +#define LICQ_GENERALPLUGININSTANCE_H + +#include "plugininstance.h" + +namespace Licq +{ + +class GeneralPlugin; + +/** + * Represents an instance of a loaded general plugin. + */ +class GeneralPluginInstance : public virtual PluginInstance +{ +public: + typedef boost::shared_ptr Ptr; + + /// Get the plugin for this instance + virtual boost::shared_ptr plugin() const = 0; + + /// Get the plugin's status. + virtual bool isEnabled() const = 0; + + /// Ask the plugin to enable itself + virtual void enable() = 0; + + /// Ask the plugin to disable itself + virtual void disable() = 0; + +protected: + virtual ~GeneralPluginInstance() { /* Empty */ } +}; + +} // namespace Licq + +#endif diff --git a/licq/include/licq/plugin/plugin.h b/licq/include/licq/plugin/plugin.h index 7fd0e5fb7..58852b3b5 100644 --- a/licq/include/licq/plugin/plugin.h +++ b/licq/include/licq/plugin/plugin.h @@ -20,8 +20,6 @@ #ifndef LICQ_PLUGIN_H #define LICQ_PLUGIN_H -#include "plugininterface.h" - #include #include #include @@ -35,12 +33,9 @@ namespace Licq class Plugin : private boost::noncopyable { public: - /// A smart pointer to a Plugin instance + /// A smart pointer to a Plugin typedef boost::shared_ptr Ptr; - /// Get the plugin's unique id. - virtual int id() const = 0; - /// Get the plugin's name. virtual std::string name() const = 0; @@ -53,48 +48,8 @@ class Plugin : private boost::noncopyable protected: /// Destructor virtual ~Plugin() { } - - virtual boost::shared_ptr internalInterface() = 0; - template friend boost::shared_ptr plugin_internal_cast(Ptr); }; -/** - * Function to cast a plugin to a plugin specific interface to get access to - * methods that only apply for a specific plugin. To e.g. get access to ICQ - * specific methods, do: - * @code - * Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - * Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); - * if (icq) - * icq->icqSendSms(...); - * @endcode - */ -template -inline boost::shared_ptr plugin_internal_cast(Plugin::Ptr plugin) -{ - return plugin - ? boost::dynamic_pointer_cast(plugin->internalInterface()) - : boost::shared_ptr(); -} - -// plugin_internal_cast<>() is not supposed to be used to cast to -// PluginInterface, GeneralPluginInterface or ProtocolPluginInterface; only to -// plugin specific interfaces. - -template <> inline boost::shared_ptr -plugin_internal_cast(Plugin::Ptr); - -class GeneralPluginInterface; -template <> boost::shared_ptr -plugin_internal_cast(Plugin::Ptr); - -class ProtocolPluginInterface; -template <> boost::shared_ptr -plugin_internal_cast(Plugin::Ptr); - } // namespace Licq -// Make available in global namespace -using Licq::plugin_internal_cast; - #endif diff --git a/licq/include/licq/plugin/plugininstance.h b/licq/include/licq/plugin/plugininstance.h new file mode 100644 index 000000000..a878c5f99 --- /dev/null +++ b/licq/include/licq/plugin/plugininstance.h @@ -0,0 +1,92 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LICQ_PLUGININSTANCE_H +#define LICQ_PLUGININSTANCE_H + +#include "plugininterface.h" + +#include +#include + +namespace Licq +{ + +/** + * Represents an instance of a loaded plugin. + */ +class PluginInstance : private boost::noncopyable +{ +public: + /// A smart pointer to a Plugin instance + typedef boost::shared_ptr Ptr; + + /// Get the instance's unique id. + virtual int id() const = 0; + +protected: + virtual ~PluginInstance() { } + + virtual boost::shared_ptr internalInterface() = 0; + template friend boost::shared_ptr plugin_internal_cast(Ptr); +}; + +/** + * Function to cast a plugin instance to a plugin specific interface to get + * access to methods that only apply for a specific plugin. To e.g. get access + * to ICQ specific methods, do: + * @code + * Licq::IcqProtocol::Ptr icq = plugin_internal_cast( + * Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); + * if (icq) + * icq->icqSendSms(...); + * @endcode + */ +template +inline boost::shared_ptr plugin_internal_cast(PluginInstance::Ptr plugin) +{ + return plugin + ? boost::dynamic_pointer_cast(plugin->internalInterface()) + : boost::shared_ptr(); +} + +// plugin_internal_cast<>() is not supposed to be used to cast to +// PluginInterface, GeneralPluginInterface or ProtocolPluginInterface; only to +// plugin specific interfaces. + +template <> inline boost::shared_ptr +plugin_internal_cast(PluginInstance::Ptr); + +class GeneralPluginInterface; +template <> boost::shared_ptr +plugin_internal_cast(PluginInstance::Ptr); + +class ProtocolPluginInterface; +template <> boost::shared_ptr +plugin_internal_cast(PluginInstance::Ptr); + +} // namespace Licq + +// Make available in global namespace +using Licq::plugin_internal_cast; + +#endif diff --git a/licq/include/licq/plugin/pluginmanager.h b/licq/include/licq/plugin/pluginmanager.h index ccc96f57d..3bc6d8747 100644 --- a/licq/include/licq/plugin/pluginmanager.h +++ b/licq/include/licq/plugin/pluginmanager.h @@ -26,13 +26,14 @@ #include "generalplugin.h" #include "protocolplugin.h" - +#include "protocolplugininstance.h" namespace Licq { class Event; class PluginSignal; class ProtocolSignal; +class USerId; typedef std::list StringList; @@ -104,6 +105,29 @@ class PluginManager : private boost::noncopyable virtual ProtocolPlugin::Ptr getProtocolPlugin(unsigned long protocolId) const = 0; + /** + * Get the protocol instance that is used for the given owner id. + * + * @param ownerId Owner to get protocol instance for. + * @return Pointer to the ProtocolPlugin (if found) or an empty pointer if + * owner is invalid. + */ + virtual ProtocolPluginInstance::Ptr + getProtocolInstance(const UserId& ownerId) const = 0; + + /** + * Get a protocol instance that is used for the given protocol id. + * + * This method should only be used when it doesn't matter witch protocol + * instance is returned, or if the protocol only supports one instance. + * + * @param protocolId Protocol id to get protocol instance for. + * @return Pointer to the ProtocolPlugin (if found) or an empty pointer if + * protocol id is unknown. + */ + virtual ProtocolPluginInstance::Ptr + getProtocolInstance(unsigned long protocolId) const = 0; + /** * Load and start the general plugin @a name. * diff --git a/licq/include/licq/plugin/protocolplugin.h b/licq/include/licq/plugin/protocolplugin.h index 472c24a55..4b886dd22 100644 --- a/licq/include/licq/plugin/protocolplugin.h +++ b/licq/include/licq/plugin/protocolplugin.h @@ -21,6 +21,9 @@ #define LICQ_PROTOCOLPLUGIN_H #include "plugin.h" +#include "protocolplugininstance.h" + +#include namespace Licq { @@ -31,6 +34,8 @@ namespace Licq class ProtocolPlugin : public virtual Plugin { public: + typedef std::vector Instances; + enum Capabilities { CanSendMsg = 1<<0, @@ -62,6 +67,9 @@ class ProtocolPlugin : public virtual Plugin */ virtual unsigned long capabilities() const = 0; + /// Get all instances that are active for this protocol + virtual Instances instances() const = 0; + protected: /// Destructor virtual ~ProtocolPlugin() { } diff --git a/licq/include/licq/plugin/protocolplugininstance.h b/licq/include/licq/plugin/protocolplugininstance.h new file mode 100644 index 000000000..fd0532324 --- /dev/null +++ b/licq/include/licq/plugin/protocolplugininstance.h @@ -0,0 +1,54 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LICQ_PROTOCOLPLUGININSTANCE_H +#define LICQ_PROTOCOLPLUGININSTANCE_H + +#include "plugininstance.h" + +namespace Licq +{ + +class ProtocolPlugin; +class UserId; + +/** + * Represents an instance of a loaded protocol plugin. + */ +class ProtocolPluginInstance : public virtual PluginInstance +{ +public: + typedef boost::shared_ptr Ptr; + + /// Get the plugin for this instance + virtual boost::shared_ptr plugin() const = 0; + + /// Get the owner ID that is associated with this protocol instance. + virtual const UserId& ownerId() const = 0; + +protected: + virtual ~ProtocolPluginInstance() { } +}; + +} // namespace Licq + +#endif diff --git a/licq/src/CMakeLists.txt b/licq/src/CMakeLists.txt index be75e4c09..bb707c453 100644 --- a/licq/src/CMakeLists.txt +++ b/licq/src/CMakeLists.txt @@ -12,10 +12,13 @@ set(tested_SRCS plugin/generalplugin.cpp plugin/generalpluginhelper.cpp + plugin/generalplugininstance.cpp plugin/plugin.cpp + plugin/plugininstance.cpp plugin/pluginthread.cpp plugin/protocolplugin.cpp plugin/protocolpluginhelper.cpp + plugin/protocolplugininstance.cpp thread/condition.cpp thread/mutexlocker.cpp diff --git a/licq/src/fifo.cpp b/licq/src/fifo.cpp index 6689cbdfb..b230738e9 100644 --- a/licq/src/fifo.cpp +++ b/licq/src/fifo.cpp @@ -383,7 +383,7 @@ static int fifo_sms(int argc, const char *const *argv) } Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(userId.ownerId())); if (!icq) return -1; @@ -421,7 +421,7 @@ static int fifo_sms_number(int argc, const char *const *argv) } Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(ownerId)); if (!icq) return -1; @@ -532,9 +532,6 @@ static int fifo_setpicture(int argc, const char* const* argv) } } - Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); - Licq::OwnerListGuard ownerList(protocolId); BOOST_FOREACH(Licq::Owner* owner, **ownerList) { @@ -547,6 +544,10 @@ static int fifo_setpicture(int argc, const char* const* argv) o->save(Licq::Owner::SavePictureInfo); } Licq::gUserManager.notifyUserUpdated(owner->id(), Licq::PluginSignal::UserPicture); + + Licq::IcqProtocol::Ptr icq = plugin_internal_cast( + Licq::gPluginManager.getProtocolInstance(owner->id())); + if (owner->id().protocolId() == LICQ_PPID && icq) { icq->icqUpdateInfoTimestamp( @@ -628,7 +629,7 @@ static int fifo_plugin_list(int /* argc */, const char* const* /* argv */) BOOST_FOREACH(Licq::GeneralPlugin::Ptr plugin, plugins) { - gLog.info("[%3d] %s\n", plugin->id(), plugin->name().c_str()); + gLog.info("%s\n", plugin->name().c_str()); } return 0; } @@ -678,7 +679,7 @@ static int fifo_proto_plugin_list(int /* argc */, const char* const* /* argv */) BOOST_FOREACH(Licq::ProtocolPlugin::Ptr plugin, plugins) { - gLog.info("[%3d] %s\n", plugin->id(), plugin->name().c_str()); + gLog.info("%s\n", plugin->name().c_str()); } return 0; } diff --git a/licq/src/plugin/generalplugin.cpp b/licq/src/plugin/generalplugin.cpp index 645c5c072..22a97a744 100644 --- a/licq/src/plugin/generalplugin.cpp +++ b/licq/src/plugin/generalplugin.cpp @@ -18,18 +18,19 @@ */ #include "generalplugin.h" +#include "generalplugininstance.h" #include -#include +#include -using namespace LicqDaemon; +#include -static void nullDeleter(void*) { /* Empty */ } +using namespace LicqDaemon; GeneralPlugin::GeneralPlugin( - int id, DynamicLibrary::Ptr lib, PluginThread::Ptr thread, + DynamicLibrary::Ptr lib, boost::shared_ptr factory) - : Plugin(id, lib, thread), + : Plugin(lib), myFactory(factory) { // Empty @@ -37,77 +38,55 @@ GeneralPlugin::GeneralPlugin( GeneralPlugin::~GeneralPlugin() { - if (myInterface) - myFactory->destroyPlugin(myInterface.get()); -} - -std::string GeneralPlugin::description() const -{ - return myFactory->description(); -} - -std::string GeneralPlugin::usage() const -{ - return myFactory->usage(); + // Empty } -std::string GeneralPlugin::configFile() const +boost::shared_ptr GeneralPlugin::createInstance( + int id, PluginThread::Ptr thread) { - return myFactory->configFile(); -} + GeneralPluginInstance::Ptr instance = + boost::make_shared( + id, boost::dynamic_pointer_cast(shared_from_this()), + thread); -bool GeneralPlugin::isEnabled() const -{ - return myInterface->isEnabled(); -} + if (instance->create()) + registerInstance(instance); + else + instance.reset(); -void GeneralPlugin::enable() -{ - if (isRunning()) - myInterface->enable(); + return instance; } -void GeneralPlugin::disable() +boost::shared_ptr +GeneralPlugin::generalFactory() { - if (isRunning()) - myInterface->disable(); + return myFactory; } -bool GeneralPlugin::wantSignal(unsigned long signalType) const +std::string GeneralPlugin::description() const { - return myInterface->wantSignal(signalType); + return myFactory->description(); } -void GeneralPlugin::pushSignal( - boost::shared_ptr signal) +std::string GeneralPlugin::usage() const { - if (isRunning()) - myInterface->pushSignal(signal); + return myFactory->usage(); } -void GeneralPlugin::pushEvent(boost::shared_ptr event) +std::string GeneralPlugin::configFile() const { - if (isRunning()) - myInterface->pushEvent(event); + return myFactory->configFile(); } -void GeneralPlugin::createInterface() +Licq::GeneralPluginInstance::Ptr GeneralPlugin::instance() const { - assert(!myInterface); - myInterface.reset(myFactory->createPlugin(), &nullDeleter); + Licq::MutexLocker locker(myMutex); + assert(myInstances.size() == 1); + return boost::dynamic_pointer_cast( + myInstances.front().lock()); } boost::shared_ptr GeneralPlugin::factory() const { return myFactory; } - -boost::shared_ptr GeneralPlugin::interface() -{ - return myInterface; -} - -boost::shared_ptr GeneralPlugin::interface() const -{ - return myInterface; -} diff --git a/licq/src/plugin/generalplugin.h b/licq/src/plugin/generalplugin.h index 11435f44f..d36c04477 100644 --- a/licq/src/plugin/generalplugin.h +++ b/licq/src/plugin/generalplugin.h @@ -20,51 +20,49 @@ #ifndef LICQDAEMON_GENERALPLUGIN_H #define LICQDAEMON_GENERALPLUGIN_H -#include #include "plugin.h" +#include "pluginthread.h" + +#include namespace Licq { class Event; class GeneralPluginFactory; -class GeneralPluginInterface; class PluginSignal; } namespace LicqDaemon { +class GeneralPluginInstance; + class GeneralPlugin : public Plugin, public Licq::GeneralPlugin { public: typedef boost::shared_ptr Ptr; - GeneralPlugin(int id, DynamicLibrary::Ptr lib, PluginThread::Ptr thread, + GeneralPlugin(DynamicLibrary::Ptr lib, boost::shared_ptr factory); ~GeneralPlugin(); + boost::shared_ptr createInstance( + int id, PluginThread::Ptr thread); + + boost::shared_ptr generalFactory(); + // From Licq::GeneralPlugin std::string description() const; std::string usage() const; std::string configFile() const; - bool isEnabled() const; - void enable(); - void disable(); - - bool wantSignal(unsigned long signalType) const; - void pushSignal(boost::shared_ptr signal); - void pushEvent(boost::shared_ptr event); + Licq::GeneralPluginInstance::Ptr instance() const; protected: // From Plugin - void createInterface(); boost::shared_ptr factory() const; - boost::shared_ptr interface(); - boost::shared_ptr interface() const; private: boost::shared_ptr myFactory; - boost::shared_ptr myInterface; }; } // namespace LicqDaemon diff --git a/licq/src/plugin/generalplugininstance.cpp b/licq/src/plugin/generalplugininstance.cpp new file mode 100644 index 000000000..ed1ea50da --- /dev/null +++ b/licq/src/plugin/generalplugininstance.cpp @@ -0,0 +1,102 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "generalplugininstance.h" + +#include +#include + +using namespace LicqDaemon; + +static void nullDeleter(void*) { /* Empty */ } + +GeneralPluginInstance::GeneralPluginInstance( + int id, GeneralPlugin::Ptr plugin, PluginThread::Ptr thread) + : PluginInstance(id, thread), + myPlugin(plugin) +{ + // Empty +} + +GeneralPluginInstance::~GeneralPluginInstance() +{ + if (myInterface) + myPlugin->generalFactory()->destroyPlugin(myInterface.get()); +} + +boost::shared_ptr GeneralPluginInstance::plugin() const +{ + return myPlugin; +} + +bool GeneralPluginInstance::isEnabled() const +{ + return myInterface->isEnabled(); +} + +void GeneralPluginInstance::enable() +{ + if (isRunning()) + myInterface->enable(); +} + +void GeneralPluginInstance::disable() +{ + if (isRunning()) + myInterface->disable(); +} + +bool GeneralPluginInstance::wantSignal(unsigned long signalType) const +{ + return myInterface->wantSignal(signalType); +} + +void GeneralPluginInstance::pushSignal( + boost::shared_ptr signal) +{ + if (isRunning()) + myInterface->pushSignal(signal); +} + +void GeneralPluginInstance::pushEvent( + boost::shared_ptr event) +{ + if (isRunning()) + myInterface->pushEvent(event); +} + +void GeneralPluginInstance::createInterface() +{ + assert(!myInterface); + myInterface.reset(myPlugin->generalFactory()->createPlugin(), &nullDeleter); +} + +boost::shared_ptr GeneralPluginInstance::interface() +{ + return myInterface; +} + +boost::shared_ptr +GeneralPluginInstance::interface() const +{ + return myInterface; +} diff --git a/licq/src/plugin/generalplugininstance.h b/licq/src/plugin/generalplugininstance.h new file mode 100644 index 000000000..d653b666b --- /dev/null +++ b/licq/src/plugin/generalplugininstance.h @@ -0,0 +1,76 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LICQDAEMON_GENERALPLUGININSTANCE_H +#define LICQDAEMON_GENERALPLUGININSTANCE_H + +#include "generalplugin.h" +#include "plugininstance.h" + +#include + +namespace Licq +{ +class Event; +class GeneralPluginFactory; +class PluginSignal; +} + +namespace LicqDaemon +{ + +class GeneralPluginInstance : public PluginInstance, + public Licq::GeneralPluginInstance +{ +public: + typedef boost::shared_ptr Ptr; + + GeneralPluginInstance( + int id, GeneralPlugin::Ptr plugin, PluginThread::Ptr thread); + ~GeneralPluginInstance(); + + GeneralPlugin::Ptr plugin() { return myPlugin; } + + // From Licq::GeneralPluginInstance + boost::shared_ptr plugin() const; + bool isEnabled() const; + void enable(); + void disable(); + + bool wantSignal(unsigned long signalType) const; + void pushSignal(boost::shared_ptr signal); + void pushEvent(boost::shared_ptr event); + +protected: + // From PluginInstance + void createInterface(); + boost::shared_ptr interface(); + boost::shared_ptr interface() const; + +private: + GeneralPlugin::Ptr myPlugin; + boost::shared_ptr myInterface; +}; + +} // namespace LicqDaemon + +#endif diff --git a/licq/src/plugin/plugin.cpp b/licq/src/plugin/plugin.cpp index 7f96d74c4..170c2690e 100644 --- a/licq/src/plugin/plugin.cpp +++ b/licq/src/plugin/plugin.cpp @@ -20,45 +20,19 @@ #include "plugin.h" #include -#include - -#include -#include -#include -#include - -// From licq.cpp -extern char** global_argv; +#include using namespace LicqDaemon; -using namespace std; -Plugin::Plugin(int id, DynamicLibrary::Ptr lib, PluginThread::Ptr thread) - : myId(id), - myLibrary(lib), - myThread(thread), - myIsRunning(false), - myArgc(0), - myArgv(NULL), - myArgvCopy(NULL), - myInitCallback(NULL), - myStartCallback(NULL), - myExitCallback(NULL) +Plugin::Plugin(DynamicLibrary::Ptr lib) + : myLibrary(lib) { // Empty } Plugin::~Plugin() { - for (int i = 0; i < myArgc; ++i) - ::free(myArgv[i]); - delete[] myArgv; - delete[] myArgvCopy; -} - -int Plugin::id() const -{ - return myId; + // Empty } std::string Plugin::name() const @@ -76,121 +50,19 @@ std::string Plugin::libraryName() const return myLibrary->getName(); } -boost::shared_ptr Plugin::internalInterface() -{ - // Create a shared_ptr that keeps this object alive at least until the - // returned pointer goes out of scope. - return boost::shared_ptr( - shared_from_this(), interface().get()); -} - -bool Plugin::isThread(const pthread_t& thread) const -{ - return myThread->isThread(thread); -} - -bool Plugin::create() -{ - myThread->createPlugin(&createThreadEntry, this); - return !! interface(); -} - -bool Plugin::init(int argc, char** argv, void (*callback)(const Plugin&)) -{ - assert(myInitCallback == NULL); - - const size_t size = argc + 2; - - myArgv = new char*[size]; - myArgvCopy = new char*[size]; - - myArgv[size - 1] = NULL; - - myArgv[0] = ::strdup(global_argv[0]); - - for (int i = 0; i < argc; ++i) - myArgv[i + 1] = ::strdup(argv[i]); - - myArgc = argc + 1; - - // We need to create a copy of myArgv and pass that to the plugin, since - // e.g. KDE changes the pointers in argv (e.g. to strip the path in argv[0]) - // and that messes up free, causing SIGSEGV in the destructor. - ::memcpy(myArgvCopy, myArgv, size * sizeof(char*)); - - myInitCallback = callback; - return myThread->initPlugin(&initThreadEntry, this); -} - -void Plugin::run(void (*startCallback)(const Plugin&), - void (*exitCallback)(const Plugin&)) +void Plugin::registerInstance(boost::weak_ptr instance) { - assert(myStartCallback == NULL && myExitCallback == NULL); - myStartCallback = startCallback; - myExitCallback = exitCallback; + Licq::MutexLocker locker(myMutex); - myThread->startPlugin(&startThreadEntry, this); -} - -void Plugin::shutdown() -{ - interface()->shutdown(); - myIsRunning = false; -} - -int Plugin::joinThread() -{ - void* result = myThread->join(); - if (result != NULL && result != PTHREAD_CANCELED) + // Clean up stale entries + for (std::vector< boost::weak_ptr >::iterator it = + myInstances.begin(); it != myInstances.end();) { - int* retval = static_cast(result); - int value = *retval; - delete retval; - return value; + if (!it->lock()) + it = myInstances.erase(it); + else + ++it; } - return -1; -} - -void Plugin::cancelThread() -{ - myThread->cancel(); -} - -void Plugin::createThreadEntry(void* plugin) -{ - Plugin* thisPlugin = static_cast(plugin); - thisPlugin->createInterface(); -} - -bool Plugin::initThreadEntry(void* plugin) -{ - Plugin* thisPlugin = static_cast(plugin); - - if (thisPlugin->myInitCallback) - thisPlugin->myInitCallback(*thisPlugin); - - // Set optind to 0 so plugins can use getopt - optind = 0; - - return thisPlugin->interface()->init( - thisPlugin->myArgc, thisPlugin->myArgvCopy); -} - -void* Plugin::startThreadEntry(void* plugin) -{ - Plugin* thisPlugin = static_cast(plugin); - - if (thisPlugin->myStartCallback != NULL) - (*thisPlugin->myStartCallback)(*thisPlugin); - - thisPlugin->myIsRunning = true; - - int* retval = new int; - *retval = thisPlugin->interface()->run(); - - if (thisPlugin->myExitCallback != NULL) - (*thisPlugin->myExitCallback)(*thisPlugin); - - return retval; + myInstances.push_back(instance); } diff --git a/licq/src/plugin/plugin.h b/licq/src/plugin/plugin.h index f35f8041b..857e12e7a 100644 --- a/licq/src/plugin/plugin.h +++ b/licq/src/plugin/plugin.h @@ -20,120 +20,51 @@ #ifndef LICQDAEMON_PLUGIN_H #define LICQDAEMON_PLUGIN_H -#include - #include "utils/dynamiclibrary.h" -#include "pluginthread.h" + +#include +#include #include +#include +#include namespace Licq { class PluginFactory; -class PluginInterface; } namespace LicqDaemon { +class PluginInstance; + class Plugin : public virtual Licq::Plugin, public boost::enable_shared_from_this { public: - Plugin(int id, DynamicLibrary::Ptr lib, PluginThread::Ptr thread); + typedef boost::shared_ptr Ptr; + + Plugin(DynamicLibrary::Ptr lib); ~Plugin(); // From Licq::Plugin - int id() const; std::string name() const; std::string version() const; std::string libraryName() const; - boost::shared_ptr internalInterface(); - - /** - * Check if a thread belongs to this plugin - * - * @param thread Thread to test - * @return True if thread is the main thread for this plugin - */ - bool isThread(const pthread_t& thread) const; - - /** - * Create the plugin instance - * - * @return True if the plugin was created successfully - */ - bool create(); - - /** - * Initialize the plugin - * - * @param argc Number of command line parameters - * @param argv Command line parameters - * @param callback Called in the thread just before init is called - * @return True if initialization was successful - */ - bool init(int argc, char** argv, void (*callback)(const Plugin&)); - - /** - * Run the plugin - * - * @param startCallback Called in the thread just before run is called - * @param exitCallback Called in the thread just after run returns - */ - void run(void (*startCallback)(const Plugin&), - void (*exitCallback)(const Plugin&)); - - /** - * Tell a plugin to shut down - */ - void shutdown(); - - /** - * Wait for the plugin to stop - * - * @return Exit code from plugin thread - */ - int joinThread(); - - /** - * Cancel the plugin's thread - */ - void cancelThread(); - - // For use by unit test - void setIsRunning(bool running) { myIsRunning = running; } protected: - virtual void createInterface() = 0; virtual boost::shared_ptr factory() const = 0; - virtual boost::shared_ptr interface() = 0; - virtual boost::shared_ptr interface() const = 0; - bool isRunning() const { return myIsRunning; } + void registerInstance(boost::weak_ptr instance); -private: - /// Entry point for creating plugin in plugin's thread - static void createThreadEntry(void* plugin); - - /// Entry point for calling init() in plugin's thread - static bool initThreadEntry(void* plugin); - - /// Entry point for calling run() in plugin's thread - static void* startThreadEntry(void* plugin); + mutable Licq::Mutex myMutex; + std::vector< boost::weak_ptr > myInstances; - const int myId; +private: DynamicLibrary::Ptr myLibrary; - PluginThread::Ptr myThread; - bool myIsRunning; - int myArgc; char** myArgv; - char** myArgvCopy; - - void (*myInitCallback)(const Plugin&); - void (*myStartCallback)(const Plugin&); - void (*myExitCallback)(const Plugin&); }; } // namespace LicqDaemon diff --git a/licq/src/plugin/plugininstance.cpp b/licq/src/plugin/plugininstance.cpp new file mode 100644 index 000000000..1e2d2ffff --- /dev/null +++ b/licq/src/plugin/plugininstance.cpp @@ -0,0 +1,181 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "plugininstance.h" + +#include + +#include +#include + +// From licq.cpp +extern char** global_argv; + +using namespace LicqDaemon; + +PluginInstance::PluginInstance( + int id, PluginThread::Ptr thread) + : myId(id), + myThread(thread), + myIsRunning(false), + myArgc(0), + myArgv(NULL), + myArgvCopy(NULL), + myInitCallback(NULL), + myStartCallback(NULL), + myExitCallback(NULL) +{ + // Empty +} + +PluginInstance::~PluginInstance() +{ + for (int i = 0; i < myArgc; ++i) + ::free(myArgv[i]); + delete[] myArgv; + delete[] myArgvCopy; +} + +int PluginInstance::id() const +{ + return myId; +} + +boost::shared_ptr PluginInstance::internalInterface() +{ + // Create a shared_ptr that keeps this object alive at least until the + // returned pointer goes out of scope. + return boost::shared_ptr( + shared_from_this(), interface().get()); +} + +bool PluginInstance::isThread(const pthread_t& thread) const +{ + return myThread->isThread(thread); +} + +bool PluginInstance::create() +{ + myThread->createPlugin(&createThreadEntry, this); + return !! interface(); +} + +bool PluginInstance::init( + int argc, char** argv, void (*callback)(const PluginInstance&)) +{ + assert(myInitCallback == NULL); + + const size_t size = argc + 2; + + myArgv = new char*[size]; + myArgvCopy = new char*[size]; + + myArgv[size - 1] = NULL; + + myArgv[0] = ::strdup(global_argv[0]); + + for (int i = 0; i < argc; ++i) + myArgv[i + 1] = ::strdup(argv[i]); + + myArgc = argc + 1; + + // We need to create a copy of myArgv and pass that to the plugin, since + // e.g. KDE changes the pointers in argv (e.g. to strip the path in argv[0]) + // and that messes up free, causing SIGSEGV in the destructor. + ::memcpy(myArgvCopy, myArgv, size * sizeof(char*)); + + myInitCallback = callback; + return myThread->initPlugin(&initThreadEntry, this); +} + +void PluginInstance::run(void (*startCallback)(const PluginInstance&), + void (*exitCallback)(const PluginInstance&)) +{ + assert(myStartCallback == NULL && myExitCallback == NULL); + myStartCallback = startCallback; + myExitCallback = exitCallback; + + myThread->startPlugin(&startThreadEntry, this); +} + +void PluginInstance::shutdown() +{ + interface()->shutdown(); + myIsRunning = false; +} + +int PluginInstance::joinThread() +{ + void* result = myThread->join(); + if (result != NULL && result != PTHREAD_CANCELED) + { + int* retval = static_cast(result); + int value = *retval; + delete retval; + return value; + } + + return -1; +} + +void PluginInstance::cancelThread() +{ + myThread->cancel(); +} + +void PluginInstance::createThreadEntry(void* plugin) +{ + PluginInstance* thisPlugin = static_cast(plugin); + thisPlugin->createInterface(); +} + +bool PluginInstance::initThreadEntry(void* plugin) +{ + PluginInstance* thisPlugin = static_cast(plugin); + + if (thisPlugin->myInitCallback) + thisPlugin->myInitCallback(*thisPlugin); + + // Set optind to 0 so plugins can use getopt + optind = 0; + + return thisPlugin->interface()->init( + thisPlugin->myArgc, thisPlugin->myArgvCopy); +} + +void* PluginInstance::startThreadEntry(void* plugin) +{ + PluginInstance* thisPlugin = static_cast(plugin); + + if (thisPlugin->myStartCallback != NULL) + (*thisPlugin->myStartCallback)(*thisPlugin); + + thisPlugin->myIsRunning = true; + + int* retval = new int; + *retval = thisPlugin->interface()->run(); + + if (thisPlugin->myExitCallback != NULL) + (*thisPlugin->myExitCallback)(*thisPlugin); + + return retval; +} diff --git a/licq/src/plugin/plugininstance.h b/licq/src/plugin/plugininstance.h new file mode 100644 index 000000000..406934596 --- /dev/null +++ b/licq/src/plugin/plugininstance.h @@ -0,0 +1,135 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LICQDAEMON_PLUGININSTANCE_H +#define LICQDAEMON_PLUGININSTANCE_H + +#include + +#include "pluginthread.h" + +#include + +namespace LicqDaemon +{ + +class PluginInstance : public virtual Licq::PluginInstance, + public boost::enable_shared_from_this +{ +public: + typedef boost::shared_ptr Ptr; + + PluginInstance(int id, PluginThread::Ptr thread); + ~PluginInstance(); + + // From Licq::PluginInstance + int id() const; + boost::shared_ptr internalInterface(); + + /** + * Check if a thread belongs to this plugin + * + * @param thread Thread to test + * @return True if thread is the main thread for this plugin + */ + bool isThread(const pthread_t& thread) const; + + /** + * Create the plugin instance + * + * @return True if the plugin was created successfully + */ + bool create(); + + /** + * Initialize the plugin + * + * @param argc Number of command line parameters + * @param argv Command line parameters + * @param callback Called in the thread just before init is called + * @return True if initialization was successful + */ + bool init(int argc, char** argv, + void (*callback)(const PluginInstance&)); + + /** + * Run the plugin + * + * @param startCallback Called in the thread just before run is called + * @param exitCallback Called in the thread just after run returns + */ + void run(void (*startCallback)(const PluginInstance&), + void (*exitCallback)(const PluginInstance&)); + + /** + * Tell a plugin to shut down + */ + void shutdown(); + + /** + * Wait for the plugin to stop + * + * @return Exit code from plugin thread + */ + int joinThread(); + + /** + * Cancel the plugin's thread + */ + void cancelThread(); + + // For use by unit test + void setIsRunning(bool running) { myIsRunning = running; } + + bool isRunning() const { return myIsRunning; } + +protected: + virtual void createInterface() = 0; + virtual boost::shared_ptr interface() = 0; + virtual boost::shared_ptr interface() const = 0; + +private: + /// Entry point for creating plugin in plugin's thread + static void createThreadEntry(void* plugin); + + /// Entry point for calling init() in plugin's thread + static bool initThreadEntry(void* plugin); + + /// Entry point for calling run() in plugin's thread + static void* startThreadEntry(void* plugin); + + const int myId; + PluginThread::Ptr myThread; + bool myIsRunning; + + int myArgc; + char** myArgv; + char** myArgvCopy; + + void (*myInitCallback)(const PluginInstance&); + void (*myStartCallback)(const PluginInstance&); + void (*myExitCallback)(const PluginInstance&); +}; + +} // namespace LicqDaemon + +#endif diff --git a/licq/src/plugin/pluginmanager.cpp b/licq/src/plugin/pluginmanager.cpp index 15ffea1f5..0bfbf2f28 100644 --- a/licq/src/plugin/pluginmanager.cpp +++ b/licq/src/plugin/pluginmanager.cpp @@ -25,9 +25,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -35,6 +33,7 @@ #include #include +#include #include #include #include @@ -45,10 +44,6 @@ #include "../contactlist/usermanager.h" #include "../daemon.h" #include "../utils/dynamiclibrary.h" -#include "generalplugin.h" -#include "plugin.h" -#include "pluginthread.h" -#include "protocolplugin.h" using Licq::MutexLocker; using Licq::Owner; @@ -70,16 +65,30 @@ namespace { // Called in the plugin's thread just before the init function -static void initPluginCallback(const Plugin& plugin) +static void initPluginCallback(const PluginInstance& instance) { - string name = plugin.name(); + string name; + + try + { + name = dynamic_cast< + const ProtocolPluginInstance&>(instance).plugin()->name(); + // Append / to protocols to be able to separate instances + name += "/" + boost::lexical_cast(instance.id()); + } + catch (std::bad_cast&) + { + name = dynamic_cast< + const GeneralPluginInstance&>(instance).plugin()->name(); + } + std::transform(name.begin(), name.end(), name.begin(), ::tolower); gLogService.createThreadLog(name); } -static void exitPluginCallback(const Plugin& plugin) +static void exitPluginCallback(const PluginInstance& instance) { - gPluginManager.pluginHasExited(plugin.id()); + gPluginManager.pluginHasExited(instance.id()); } } // namespace @@ -131,14 +140,17 @@ GeneralPlugin::Ptr PluginManager::loadGeneralPlugin( boost::shared_ptr factory( (*pluginData->createFactory)(), pluginData->destroyFactory); - // Create the plugin - GeneralPlugin::Ptr plugin = boost::make_shared( - getNewPluginId(), lib, pluginThread, factory); - if (!plugin->create()) + GeneralPlugin::Ptr plugin = + boost::make_shared(lib, factory); + + // Create the plugin instance + GeneralPluginInstance::Ptr instance = plugin->createInstance( + getNewPluginId(), pluginThread); + if (!instance) throw std::exception(); // Let the plugin initialize itself - if (!plugin->init(argc, argv, &initPluginCallback)) + if (!instance->init(argc, argv, &initPluginCallback)) { gLog.error(tr("Failed to initialize plugin (%s)"), plugin->name().c_str()); @@ -148,7 +160,7 @@ GeneralPlugin::Ptr PluginManager::loadGeneralPlugin( if (keep) { MutexLocker generalLocker(myGeneralPluginsMutex); - myGeneralPlugins.push_back(plugin); + myGeneralInstances.push_back(instance); } return plugin; } @@ -197,31 +209,27 @@ loadProtocolPlugin(const std::string& name, bool keep) { // Check if we already got a plugin for this protocol MutexLocker protocolLocker(myProtocolPluginsMutex); - BOOST_FOREACH(ProtocolPlugin::Ptr proto, myProtocolPlugins) + BOOST_FOREACH(ProtocolPluginInstance::Ptr proto, myProtocolInstances) { - if (proto->protocolId() == factory->protocolId()) + if (proto->plugin()->protocolId() == factory->protocolId()) throw std::exception(); } } - // Create the plugin - ProtocolPlugin::Ptr plugin = boost::make_shared( - getNewPluginId(), lib, pluginThread, factory); - if (!plugin->create()) - throw std::exception(); + ProtocolPlugin::Ptr plugin = + boost::make_shared(lib, factory); - // Let the plugin initialize itself - if (!plugin->init(0, NULL, &initPluginCallback)) - { - gLog.error(tr("Failed to initialize plugin (%s)"), - plugin->name().c_str()); + // Create the plugin instance + ProtocolPluginInstance::Ptr instance = createProtocolInstance( + plugin, pluginThread); + + if (!instance) throw std::exception(); - } if (keep) { MutexLocker protocolLocker(myProtocolPluginsMutex); - myProtocolPlugins.push_back(plugin); + myProtocolInstances.push_back(instance); } // Let the plugins know about the new protocol plugin @@ -246,47 +254,42 @@ loadProtocolPlugin(const std::string& name, bool keep) void PluginManager::startAllPlugins() { - list ppids; + set ppids; { MutexLocker protocolLocker(myProtocolPluginsMutex); - BOOST_FOREACH(ProtocolPlugin::Ptr plugin, myProtocolPlugins) - ppids.push_back(plugin->protocolId()); + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) + ppids.insert(instance->plugin()->protocolId()); } // Must call loadProtocol without holding mutex BOOST_FOREACH(unsigned long protocolId, ppids) gUserManager.loadProtocol(protocolId); - MutexLocker generalLocker(myGeneralPluginsMutex); - MutexLocker protocolLocker(myProtocolPluginsMutex); - - BOOST_FOREACH(GeneralPlugin::Ptr plugin, myGeneralPlugins) { - startPlugin(plugin); + MutexLocker generalLocker(myGeneralPluginsMutex); + BOOST_FOREACH(GeneralPluginInstance::Ptr instance, myGeneralInstances) + startInstance(instance); } - BOOST_FOREACH(ProtocolPlugin::Ptr plugin, myProtocolPlugins) { - startPlugin(plugin); + MutexLocker protocolLocker(myProtocolPluginsMutex); + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) + startInstance(instance); } } void PluginManager::shutdownAllPlugins() { { - MutexLocker locker(myGeneralPluginsMutex); - BOOST_FOREACH(GeneralPlugin::Ptr plugin, myGeneralPlugins) - { - plugin->shutdown(); - } + MutexLocker generalLocker(myGeneralPluginsMutex); + BOOST_FOREACH(GeneralPluginInstance::Ptr instance, myGeneralInstances) + instance->shutdown(); } { - MutexLocker locker(myProtocolPluginsMutex); - BOOST_FOREACH(ProtocolPlugin::Ptr plugin, myProtocolPlugins) - { - plugin->shutdown(); - } + MutexLocker protocolLocker(myProtocolPluginsMutex); + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) + instance->shutdown(); } } @@ -299,51 +302,20 @@ void PluginManager::pluginHasExited(unsigned short id) void PluginManager::reapPlugin() { - unsigned short exitId = myExitList.front(); - myExitList.pop(); - - MutexLocker generalLocker(myGeneralPluginsMutex); - MutexLocker protocolLocker(myProtocolPluginsMutex); - - // Check general plugins first - for (list::iterator plugin = myGeneralPlugins.begin(); - plugin != myGeneralPlugins.end(); ++plugin) + int exitId; { - if ((*plugin)->id() == exitId) - { - int result = (*plugin)->joinThread(); - gLog.info(tr("Plugin %s exited with code %d"), - (*plugin)->name().c_str(), result); - myGeneralPlugins.erase(plugin); - return; - } + MutexLocker locker(myExitListMutex); + exitId = myExitList.front(); + myExitList.pop(); } - generalLocker.unlock(); - - // Then check protocol plugins - for (list::iterator plugin = myProtocolPlugins.begin(); - plugin != myProtocolPlugins.end(); ++plugin) - { - if ((*plugin)->id() == exitId) - { - unsigned long protocolId = (*plugin)->protocolId(); - int result = (*plugin)->joinThread(); - gLog.info(tr("Protocol plugin %s exited with code %d"), - (*plugin)->name().c_str(), result); - // Should already been done, but if protocol exited by itself clean it up here - gUserManager.unloadProtocol(protocolId); - - // Remove plugin from list, if this was only reference it will unload library - myProtocolPlugins.erase(plugin); - - // Notify plugins about the removed protocol - pushPluginSignal(new Licq::PluginSignal( - Licq::PluginSignal::SignalRemoveProtocol, protocolId)); + // Check general plugins first + if (reapGeneralInstance(exitId)) + return; - return; - } - } + // Then check protocol plugins + if (reapProtocolInstance(exitId)) + return; gLog.error(tr("Invalid plugin id (%d) in exit signal"), exitId); } @@ -352,19 +324,21 @@ void PluginManager::cancelAllPlugins() { { MutexLocker locker(myGeneralPluginsMutex); - BOOST_FOREACH(GeneralPlugin::Ptr plugin, myGeneralPlugins) + BOOST_FOREACH(GeneralPluginInstance::Ptr instance, myGeneralInstances) { - gLog.warning(tr("Plugin %s failed to exit"), plugin->name().c_str()); - plugin->cancelThread(); + gLog.warning(tr("Plugin %s failed to exit"), + instance->plugin()->name().c_str()); + instance->cancelThread(); } } { MutexLocker locker(myProtocolPluginsMutex); - BOOST_FOREACH(ProtocolPlugin::Ptr plugin, myProtocolPlugins) + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) { - gLog.warning(tr("Protocol plugin %s failed to exit"), plugin->name().c_str()); - plugin->cancelThread(); + gLog.warning(tr("Protocol plugin %s (id %d) failed to exit"), + instance->plugin()->name().c_str(), instance->id()); + instance->cancelThread(); } } } @@ -372,51 +346,95 @@ void PluginManager::cancelAllPlugins() size_t PluginManager::getGeneralPluginsCount() const { MutexLocker locker(myGeneralPluginsMutex); - return myGeneralPlugins.size(); + return myGeneralInstances.size(); } size_t PluginManager::pluginCount() const { MutexLocker generalLocker(myGeneralPluginsMutex); MutexLocker protocolLocker(myProtocolPluginsMutex); - return myGeneralPlugins.size() + myProtocolPlugins.size(); + return myGeneralInstances.size() + myProtocolInstances.size(); } User* PluginManager::createProtocolUser(const UserId& id, bool temporary) { - ProtocolPlugin::Ptr plugin = boost::dynamic_pointer_cast( - getProtocolPlugin(id.protocolId())); - if (!plugin) - return NULL; + ProtocolPluginInstance::Ptr instance; + { + MutexLocker locker(myProtocolPluginsMutex); + BOOST_FOREACH(ProtocolPluginInstance::Ptr it, myProtocolInstances) + { + if (it->plugin()->protocolId() == id.protocolId()) + { + instance = it; + break; + } + } + } - return plugin->createUser(id, temporary); + return instance->plugin()->createUser(id, temporary); } Owner* PluginManager::createProtocolOwner(const UserId& id) { - ProtocolPlugin::Ptr plugin = boost::dynamic_pointer_cast( - getProtocolPlugin(id.protocolId())); - if (!plugin) - return NULL; + ProtocolPluginInstance::Ptr instance; + { + MutexLocker locker(myProtocolPluginsMutex); + BOOST_FOREACH(ProtocolPluginInstance::Ptr it, myProtocolInstances) + { + if (it->plugin()->protocolId() == id.protocolId()) + { + if (!it->ownerId().isValid()) + { + gLog.debug("Setting owner %s for existing protocol instance %d", + id.toString().c_str(), it->id()); + it->setOwnerId(id); + locker.unlock(); + return it->plugin()->createOwner(id); + } + else + instance = it; + } + } + } + + gLog.debug("Create new protocol instance for %s", id.toString().c_str()); + + const bool isRunning = instance->isRunning(); + + instance = createProtocolInstance(instance->plugin()); + instance->setOwnerId(id); - return plugin->createOwner(id); + { + MutexLocker locker(myProtocolPluginsMutex); + myProtocolInstances.push_back(instance); + if (isRunning) + startInstance(instance); + } + + return instance->plugin()->createOwner(id); } + void PluginManager:: getGeneralPluginsList(Licq::GeneralPluginsList& plugins) const { plugins.clear(); MutexLocker locker(myGeneralPluginsMutex); - std::copy(myGeneralPlugins.begin(), myGeneralPlugins.end(), - std::back_inserter(plugins)); + BOOST_FOREACH(GeneralPluginInstance::Ptr instance, myGeneralInstances) + plugins.push_back(instance->plugin()); } void PluginManager:: getProtocolPluginsList(Licq::ProtocolPluginsList& plugins) const { + std::set protocols; + { + MutexLocker locker(myProtocolPluginsMutex); + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) + protocols.insert(instance->plugin()); + } + plugins.clear(); - MutexLocker locker(myProtocolPluginsMutex); - std::copy(myProtocolPlugins.begin(), myProtocolPlugins.end(), - std::back_inserter(plugins)); + std::copy(protocols.begin(), protocols.end(), std::back_inserter(plugins)); } void PluginManager::getAvailableGeneralPlugins( @@ -427,9 +445,9 @@ void PluginManager::getAvailableGeneralPlugins( if (!includeLoaded) { MutexLocker locker(myGeneralPluginsMutex); - BOOST_FOREACH(GeneralPlugin::Ptr plugin, myGeneralPlugins) + BOOST_FOREACH(GeneralPluginInstance::Ptr instance, myGeneralInstances) { - string name = plugin->libraryName(); + string name = instance->plugin()->libraryName(); size_t pos = name.find_last_of('/'); name.erase(0, pos+6); name.erase(name.size() - 3); @@ -446,12 +464,9 @@ void PluginManager::getAvailableProtocolPlugins( if (!includeLoaded) { MutexLocker locker(myProtocolPluginsMutex); - BOOST_FOREACH(ProtocolPlugin::Ptr plugin, myProtocolPlugins) + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) { - string name = plugin->libraryName(); - // Special case, the internal ICQ plugin has no library - if (name.empty()) - continue; + string name = instance->plugin()->libraryName(); size_t pos = name.find_last_of('/'); name.erase(0, pos+10); name.erase(name.size() - 3); @@ -485,63 +500,94 @@ Licq::ProtocolPlugin::Ptr PluginManager::getProtocolPlugin( unsigned long protocolId) const { MutexLocker locker(myProtocolPluginsMutex); - BOOST_FOREACH(ProtocolPlugin::Ptr protocol, myProtocolPlugins) + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) { - if (protocol->protocolId() == protocolId) - return protocol; + if (instance->plugin()->protocolId() == protocolId) + return instance->plugin(); } return Licq::ProtocolPlugin::Ptr(); } +Licq::ProtocolPluginInstance::Ptr PluginManager::getProtocolInstance( + const Licq::UserId& ownerId) const +{ + MutexLocker locker(myProtocolPluginsMutex); + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) + { + if (instance->ownerId() == ownerId) + return instance; + } + return Licq::ProtocolPluginInstance::Ptr(); +} + +Licq::ProtocolPluginInstance::Ptr PluginManager::getProtocolInstance( + unsigned long protocolId) const +{ + MutexLocker locker(myProtocolPluginsMutex); + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) + { + if (instance->ownerId().protocolId() == protocolId) + return instance; + } + return Licq::ProtocolPluginInstance::Ptr(); +} + bool PluginManager:: startGeneralPlugin(const std::string& name, int argc, char** argv) { GeneralPlugin::Ptr plugin = loadGeneralPlugin(name, argc, argv); - if (plugin) - { - MutexLocker locker(myGeneralPluginsMutex); - startPlugin(plugin); - return true; - } - return false; + if (!plugin) + return false; + + startInstance(boost::dynamic_pointer_cast( + plugin->instance())); + return true; } bool PluginManager::startProtocolPlugin(const std::string& name) { ProtocolPlugin::Ptr plugin = loadProtocolPlugin(name); - if (plugin) - { - // Load contacts and owners for the new protocol - gUserManager.loadProtocol(plugin->protocolId()); + if (!plugin) + return false; - MutexLocker locker(myProtocolPluginsMutex); - startPlugin(plugin); - return true; + // Load contacts and owners for the new protocol + gUserManager.loadProtocol(plugin->protocolId()); + + ProtocolPlugin::Instances instances = plugin->instances(); + BOOST_FOREACH(Licq::ProtocolPluginInstance::Ptr instance, instances) + { + startInstance( + boost::dynamic_pointer_cast(instance)); } - return false; + return true; } -void PluginManager::unloadGeneralPlugin(Licq::GeneralPlugin::Ptr p) +void PluginManager::unloadGeneralPlugin(Licq::GeneralPlugin::Ptr plugin) { - GeneralPlugin::Ptr plugin = boost::dynamic_pointer_cast(p); if (!plugin) return; - plugin->shutdown(); + GeneralPluginInstance::Ptr instance = + boost::dynamic_pointer_cast(plugin->instance()); + if (instance) + instance->shutdown(); } -void PluginManager::unloadProtocolPlugin(Licq::ProtocolPlugin::Ptr p) +void PluginManager::unloadProtocolPlugin(Licq::ProtocolPlugin::Ptr plugin) { - ProtocolPlugin::Ptr plugin = boost::dynamic_pointer_cast(p); if (!plugin) return; - - // Check with user manager first if unloading is allowed + + // Check with user manager first if unloading is allowed if (!gUserManager.allowUnloadProtocol(plugin->protocolId())) return; gUserManager.unloadProtocol(plugin->protocolId()); - plugin->shutdown(); + + // Shutdown all instances + ProtocolPlugin::Instances instances = plugin->instances(); + BOOST_FOREACH(Licq::ProtocolPluginInstance::Ptr instance, instances) + boost::dynamic_pointer_cast(instance)->shutdown(); } DynamicLibrary::Ptr PluginManager::loadPlugin( @@ -621,20 +667,118 @@ int PluginManager::getNewPluginId() return myNextPluginId++; } -void PluginManager::startPlugin(GeneralPlugin::Ptr plugin) +ProtocolPluginInstance::Ptr PluginManager::createProtocolInstance( + ProtocolPlugin::Ptr plugin, PluginThread::Ptr thread) +{ + if (!thread) + thread = boost::make_shared(); + + ProtocolPluginInstance::Ptr instance = plugin->createInstance( + getNewPluginId(), thread); + + if (instance && !instance->init(0, NULL, &initPluginCallback)) + { + gLog.error(tr("Failed to initialize protocol plugin (%s)"), + plugin->name().c_str()); + instance.reset(); + } + + return instance; +} + +void PluginManager::startInstance(GeneralPluginInstance::Ptr instance) +{ + Licq::GeneralPlugin::Ptr plugin = instance->plugin(); + gLog.info(tr("Starting plugin %s (id %d; version %s)"), + plugin->name().c_str(), instance->id(), plugin->version().c_str()); + + instance->run(NULL, exitPluginCallback); +} + +void PluginManager::startInstance(ProtocolPluginInstance::Ptr instance) { - gLog.info(tr("Starting plugin %s (version %s)"), - plugin->name().c_str(), plugin->version().c_str()); + ProtocolPlugin::Ptr plugin = instance->plugin(); + gLog.info(tr("Starting protocol plugin %s (id %d; version %s)"), + plugin->name().c_str(), instance->id(), plugin->version().c_str()); - plugin->run(NULL, exitPluginCallback); + instance->run(NULL, exitPluginCallback); } -void PluginManager::startPlugin(ProtocolPlugin::Ptr plugin) +bool PluginManager::reapGeneralInstance(int exitId) { - gLog.info(tr("Starting protocol plugin %s (version %s)"), - plugin->name().c_str(), plugin->version().c_str()); + MutexLocker locker(myGeneralPluginsMutex); - plugin->run(NULL, exitPluginCallback); + GeneralPluginInstance::Ptr instance; + for (list::iterator it = + myGeneralInstances.begin(); + it != myGeneralInstances.end(); ++it) + { + if ((*it)->id() == exitId) + { + instance = *it; + myGeneralInstances.erase(it); + break; + } + } + + if (!instance) + return false; + + Plugin::Ptr plugin = instance->plugin(); + + int result = instance->joinThread(); + gLog.info(tr("Plugin %s exited with code %d"), + plugin->name().c_str(), result); + + return true; +} + +bool PluginManager::reapProtocolInstance(int exitId) +{ + MutexLocker locker(myProtocolPluginsMutex); + + ProtocolPluginInstance::Ptr instance; + for (list::iterator it = + myProtocolInstances.begin(); + it != myProtocolInstances.end(); ++it) + { + if ((*it)->id() == exitId) + { + instance = *it; + myProtocolInstances.erase(it); + break; + } + } + + if (!instance) + return false; + + ProtocolPlugin::Ptr plugin = instance->plugin(); + + int result = instance->joinThread(); + gLog.info(tr("Protocol plugin %s (id %d; owner %s) exited with code %d"), + plugin->name().c_str(), exitId, instance->ownerId().accountId().c_str(), + result); + + const unsigned long protocolId = plugin->protocolId(); + + // See if there is any more instances of this protocol + for (list::iterator it = + myProtocolInstances.begin(); + it != myProtocolInstances.end(); ++it) + { + if ((*it)->plugin()->protocolId() == protocolId) + return true; + } + + // Should already been done, but if protocol exited by itself clean it up here + gUserManager.unloadProtocol(protocolId); + + // Notify plugins about the removed protocol + pushPluginSignal(new Licq::PluginSignal( + Licq::PluginSignal::SignalRemoveProtocol, protocolId)); + + return true; } void PluginManager::pushPluginEvent(Licq::Event* rawEvent) @@ -642,11 +786,11 @@ void PluginManager::pushPluginEvent(Licq::Event* rawEvent) boost::shared_ptr event(rawEvent); MutexLocker locker(myGeneralPluginsMutex); - BOOST_FOREACH(GeneralPlugin::Ptr plugin, myGeneralPlugins) + BOOST_FOREACH(GeneralPluginInstance::Ptr instance, myGeneralInstances) { - if (plugin->isThread(event->thread_plugin)) + if (instance->isThread(event->thread_plugin)) { - plugin->pushEvent(event); + instance->pushEvent(event); return; } } @@ -657,27 +801,28 @@ void PluginManager::pushPluginSignal(Licq::PluginSignal* rawSignal) boost::shared_ptr signal(rawSignal); MutexLocker locker(myGeneralPluginsMutex); - BOOST_FOREACH(GeneralPlugin::Ptr plugin, myGeneralPlugins) + BOOST_FOREACH(GeneralPluginInstance::Ptr instance, myGeneralInstances) { - if (plugin->wantSignal(signal->signal())) - plugin->pushSignal(signal); + if (instance->wantSignal(signal->signal())) + instance->pushSignal(signal); } } void PluginManager::pushProtocolSignal(Licq::ProtocolSignal* rawSignal) { boost::shared_ptr signal(rawSignal); - const unsigned long protocolId = signal->userId().protocolId(); + const Licq::UserId ownerId = signal->userId().ownerId(); MutexLocker locker(myProtocolPluginsMutex); - BOOST_FOREACH(ProtocolPlugin::Ptr plugin, myProtocolPlugins) + BOOST_FOREACH(ProtocolPluginInstance::Ptr instance, myProtocolInstances) { - if (plugin->protocolId() == protocolId) + if (instance->ownerId() == ownerId) { - plugin->pushSignal(signal); + instance->pushSignal(signal); return; } } - Licq::gLog.error(tr("Invalid protocol plugin requested (%ld)"), protocolId); + gLog.error(tr("Invalid protocol plugin requested (%s)"), + ownerId.toString().c_str()); } diff --git a/licq/src/plugin/pluginmanager.h b/licq/src/plugin/pluginmanager.h index 4af9178ec..44d890409 100644 --- a/licq/src/plugin/pluginmanager.h +++ b/licq/src/plugin/pluginmanager.h @@ -26,8 +26,10 @@ #include "../utils/dynamiclibrary.h" #include "generalplugin.h" +#include "generalplugininstance.h" #include "pluginthread.h" #include "protocolplugin.h" +#include "protocolplugininstance.h" #include @@ -100,6 +102,10 @@ class PluginManager : public Licq::PluginManager void getAvailableProtocolPlugins(Licq::StringList& plugins, bool includeLoaded = true) const; Licq::ProtocolPlugin::Ptr getProtocolPlugin(unsigned long protocolId) const; + Licq::ProtocolPluginInstance::Ptr getProtocolInstance( + const Licq::UserId& ownerId) const; + Licq::ProtocolPluginInstance::Ptr getProtocolInstance( + unsigned long protocolId) const; bool startGeneralPlugin(const std::string& name, int argc, char** argv); bool startProtocolPlugin(const std::string& name); @@ -110,6 +116,9 @@ class PluginManager : public Licq::PluginManager void pushProtocolSignal(Licq::ProtocolSignal* signal); private: + void getAvailablePlugins(Licq::StringList& plugins, + const std::string& prefix) const; + DynamicLibrary::Ptr loadPlugin(PluginThread::Ptr pluginThread, const std::string& name, const std::string& prefix); @@ -117,23 +126,27 @@ class PluginManager : public Licq::PluginManager bool verifyPluginVersion(const std::string& name, int version); int getNewPluginId(); - void startPlugin(GeneralPlugin::Ptr plugin); - void startPlugin(ProtocolPlugin::Ptr plugin); + ProtocolPluginInstance::Ptr createProtocolInstance( + ProtocolPlugin::Ptr plugin, + PluginThread::Ptr thread = PluginThread::Ptr()); - void getAvailablePlugins(Licq::StringList& plugins, - const std::string& prefix) const; + void startInstance(GeneralPluginInstance::Ptr instance); + void startInstance(ProtocolPluginInstance::Ptr instance); + + bool reapGeneralInstance(int exitId); + bool reapProtocolInstance(int exitId); int myNextPluginId; PluginThread::Ptr myGuiThread; - std::list myGeneralPlugins; mutable Licq::Mutex myGeneralPluginsMutex; + std::list myGeneralInstances; - std::list myProtocolPlugins; mutable Licq::Mutex myProtocolPluginsMutex; + std::list myProtocolInstances; Licq::Mutex myExitListMutex; - std::queue myExitList; + std::queue myExitList; }; extern PluginManager gPluginManager; diff --git a/licq/src/plugin/protocolplugin.cpp b/licq/src/plugin/protocolplugin.cpp index b48d11b6c..f795ac864 100644 --- a/licq/src/plugin/protocolplugin.cpp +++ b/licq/src/plugin/protocolplugin.cpp @@ -18,18 +18,19 @@ */ #include "protocolplugin.h" +#include "protocolplugininstance.h" #include -#include +#include -using namespace LicqDaemon; +#include -static void nullDeleter(void*) { /* Empty */ } +using namespace LicqDaemon; ProtocolPlugin::ProtocolPlugin( - int id, DynamicLibrary::Ptr lib, PluginThread::Ptr thread, + DynamicLibrary::Ptr lib, boost::shared_ptr factory) - : Plugin(id, lib, thread), + : Plugin(lib), myFactory(factory) { // Empty @@ -37,8 +38,29 @@ ProtocolPlugin::ProtocolPlugin( ProtocolPlugin::~ProtocolPlugin() { - if (myInterface) - myFactory->destroyPlugin(myInterface.get()); + // Empty +} + +boost::shared_ptr ProtocolPlugin::createInstance( + int id, PluginThread::Ptr thread) +{ + ProtocolPluginInstance::Ptr instance = + boost::make_shared( + id, boost::dynamic_pointer_cast(shared_from_this()), + thread); + + if (instance->create()) + registerInstance(instance); + else + instance.reset(); + + return instance; +} + +boost::shared_ptr +ProtocolPlugin::protocolFactory() +{ + return myFactory; } unsigned long ProtocolPlugin::protocolId() const @@ -51,11 +73,22 @@ unsigned long ProtocolPlugin::capabilities() const return myFactory->capabilities(); } -void ProtocolPlugin::pushSignal( - boost::shared_ptr signal) +Licq::ProtocolPlugin::Instances ProtocolPlugin::instances() const { - if (isRunning()) - myInterface->pushSignal(signal); + Instances list; + + Licq::MutexLocker locker(myMutex); + + for (std::vector< boost::weak_ptr >::const_iterator it = + myInstances.begin(); it != myInstances.end(); ++it) + { + ProtocolPluginInstance::Ptr instance = + boost::dynamic_pointer_cast(it->lock()); + if (instance) + list.push_back(instance); + } + + return list; } Licq::User* ProtocolPlugin::createUser(const Licq::UserId& id, bool temporary) @@ -68,24 +101,7 @@ Licq::Owner* ProtocolPlugin::createOwner(const Licq::UserId& id) return myFactory->createOwner(id); } -void ProtocolPlugin::createInterface() -{ - assert(!myInterface); - myInterface.reset(myFactory->createPlugin(), &nullDeleter); -} - boost::shared_ptr ProtocolPlugin::factory() const { return myFactory; } - -boost::shared_ptr ProtocolPlugin::interface() -{ - return myInterface; -} - -boost::shared_ptr -ProtocolPlugin::interface() const -{ - return myInterface; -} diff --git a/licq/src/plugin/protocolplugin.h b/licq/src/plugin/protocolplugin.h index b5d16d8ee..365c5ad33 100644 --- a/licq/src/plugin/protocolplugin.h +++ b/licq/src/plugin/protocolplugin.h @@ -20,14 +20,15 @@ #ifndef LICQDAEMON_PROTOCOLPLUGIN_H #define LICQDAEMON_PROTOCOLPLUGIN_H -#include #include "plugin.h" +#include "pluginthread.h" + +#include namespace Licq { class Owner; class ProtocolPluginFactory; -class ProtocolPluginInterface; class ProtocolSignal; class User; class UserId; @@ -36,33 +37,36 @@ class UserId; namespace LicqDaemon { +class ProtocolPluginInstance; + class ProtocolPlugin : public Plugin, public Licq::ProtocolPlugin { public: typedef boost::shared_ptr Ptr; - ProtocolPlugin(int id, DynamicLibrary::Ptr lib, PluginThread::Ptr thread, + ProtocolPlugin(DynamicLibrary::Ptr lib, boost::shared_ptr factory); ~ProtocolPlugin(); + boost::shared_ptr createInstance( + int id, PluginThread::Ptr thread); + + boost::shared_ptr protocolFactory(); + // From Licq::ProtocolPlugin unsigned long protocolId() const; unsigned long capabilities() const; + Instances instances() const; - void pushSignal(boost::shared_ptr signal); Licq::User* createUser(const Licq::UserId& id, bool temporary); Licq::Owner* createOwner(const Licq::UserId& id); protected: // From Plugin - void createInterface(); boost::shared_ptr factory() const; - boost::shared_ptr interface(); - boost::shared_ptr interface() const; private: boost::shared_ptr myFactory; - boost::shared_ptr myInterface; }; } // namespace LicqDaemon diff --git a/licq/src/plugin/protocolplugininstance.cpp b/licq/src/plugin/protocolplugininstance.cpp new file mode 100644 index 000000000..8557c6e38 --- /dev/null +++ b/licq/src/plugin/protocolplugininstance.cpp @@ -0,0 +1,73 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "protocolplugininstance.h" + +#include +#include + +using namespace LicqDaemon; + +static void nullDeleter(void*) { /* Empty */ } + +ProtocolPluginInstance::ProtocolPluginInstance( + int id, ProtocolPlugin::Ptr plugin, PluginThread::Ptr thread) + : PluginInstance(id, thread), + myPlugin(plugin) +{ + // Empty +} + +ProtocolPluginInstance::~ProtocolPluginInstance() +{ + if (myInterface) + myPlugin->protocolFactory()->destroyPlugin(myInterface.get()); +} + +boost::shared_ptr ProtocolPluginInstance::plugin() const +{ + return myPlugin; +} + +void ProtocolPluginInstance::pushSignal( + boost::shared_ptr signal) +{ + if (isRunning()) + myInterface->pushSignal(signal); +} + +void ProtocolPluginInstance::createInterface() +{ + assert(!myInterface); + myInterface.reset(myPlugin->protocolFactory()->createPlugin(), &nullDeleter); +} + +boost::shared_ptr ProtocolPluginInstance::interface() +{ + return myInterface; +} + +boost::shared_ptr +ProtocolPluginInstance::interface() const +{ + return myInterface; +} diff --git a/licq/src/plugin/protocolplugininstance.h b/licq/src/plugin/protocolplugininstance.h new file mode 100644 index 000000000..9066bd9b1 --- /dev/null +++ b/licq/src/plugin/protocolplugininstance.h @@ -0,0 +1,75 @@ +/* + * This file is part of Licq, an instant messaging client for UNIX. + * Copyright (C) 2013 Licq Developers + * + * Please refer to the COPYRIGHT file distributed with this source + * distribution for the names of the individual contributors. + * + * Licq is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Licq 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 General Public License + * along with Licq; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LICQDAEMON_PROTOCOLPLUGININSTANCE_H +#define LICQDAEMON_PROTOCOLPLUGININSTANCE_H + +#include "plugininstance.h" +#include "protocolplugin.h" + +#include + +#include + +namespace Licq +{ +class ProtocolPluginFactory; +class ProtocolSignal; +} + +namespace LicqDaemon +{ + +class ProtocolPluginInstance : public PluginInstance, + public Licq::ProtocolPluginInstance +{ +public: + typedef boost::shared_ptr Ptr; + + ProtocolPluginInstance( + int id, ProtocolPlugin::Ptr plugin, PluginThread::Ptr thread); + ~ProtocolPluginInstance(); + + ProtocolPlugin::Ptr plugin() { return myPlugin; } + + // From Licq::ProtocolPluginInstance + boost::shared_ptr plugin() const; + const Licq::UserId& ownerId() const { return myOwnerId; } + + void setOwnerId(const Licq::UserId& ownerId) { myOwnerId = ownerId; } + void pushSignal(boost::shared_ptr signal); + +protected: + // From PluginInstance + void createInterface(); + boost::shared_ptr interface(); + boost::shared_ptr interface() const; + +private: + ProtocolPlugin::Ptr myPlugin; + boost::shared_ptr myInterface; + Licq::UserId myOwnerId; +}; + +} // namespace LicqDaemon + +#endif diff --git a/licq/src/plugin/tests/generalplugintest.cpp b/licq/src/plugin/tests/generalplugintest.cpp index d36f13882..50301680a 100644 --- a/licq/src/plugin/tests/generalplugintest.cpp +++ b/licq/src/plugin/tests/generalplugintest.cpp @@ -18,6 +18,7 @@ */ #include "../generalplugin.h" +#include "../generalplugininstance.h" #include #include @@ -26,6 +27,7 @@ #include using LicqDaemon::GeneralPlugin; +using LicqDaemon::GeneralPluginInstance; using LicqDaemon::DynamicLibrary; using LicqDaemon::PluginThread; @@ -73,19 +75,21 @@ struct GeneralPluginFixture : public ::testing::Test MockGeneralPluginFactory myMockFactory; MockGeneralPlugin myMockInterface; GeneralPlugin plugin; + GeneralPluginInstance instance; GeneralPluginFixture() : myLib(new DynamicLibrary("")), myThread(new PluginThread()), - plugin(1, myLib, myThread, - boost::shared_ptr( - &myMockFactory, &nullDeleter)) + plugin(myLib, boost::shared_ptr( + &myMockFactory, &nullDeleter)), + instance(1, boost::shared_ptr(&plugin, &nullDeleter), + myThread) { EXPECT_CALL(myMockFactory, createPlugin()) .WillOnce(Return(&myMockInterface)); EXPECT_CALL(myMockFactory, destroyPlugin(&myMockInterface)); - plugin.create(); + EXPECT_TRUE(instance.create()); } ~GeneralPluginFixture() @@ -106,7 +110,7 @@ TEST_P(RunnableGeneralPluginFixture, callApiFunctions) using boost::shared_ptr; if (GetParam()) - plugin.setIsRunning(true); + instance.setIsRunning(true); unsigned long signalType = 123; shared_ptr signal( @@ -135,12 +139,12 @@ TEST_P(RunnableGeneralPluginFixture, callApiFunctions) plugin.description(); plugin.usage(); plugin.configFile(); - plugin.isEnabled(); - plugin.enable(); - plugin.disable(); - plugin.wantSignal(signalType); - plugin.pushSignal(signal); - plugin.pushEvent(event); + instance.isEnabled(); + instance.enable(); + instance.disable(); + instance.wantSignal(signalType); + instance.pushSignal(signal); + instance.pushEvent(event); } INSTANTIATE_TEST_CASE_P(Running, RunnableGeneralPluginFixture, diff --git a/licq/src/plugin/tests/plugintest.cpp b/licq/src/plugin/tests/plugintest.cpp index 204842d35..e934a3be8 100644 --- a/licq/src/plugin/tests/plugintest.cpp +++ b/licq/src/plugin/tests/plugintest.cpp @@ -18,6 +18,7 @@ */ #include "../plugin.h" +#include "../plugininstance.h" #include #include @@ -30,6 +31,7 @@ static const char* argv0 = "test"; char** global_argv = const_cast(&argv0); using LicqDaemon::Plugin; +using LicqDaemon::PluginInstance; using LicqDaemon::DynamicLibrary; using LicqDaemon::PluginThread; @@ -65,34 +67,58 @@ class MockPlugin : public Licq::PluginInterface, class TestPlugin : public Plugin { public: - bool myIsCreated; + typedef boost::shared_ptr Ptr; - TestPlugin(int id, DynamicLibrary::Ptr lib, PluginThread::Ptr thread, - boost::shared_ptr factory, - boost::shared_ptr interface) - : Plugin(id, lib, thread), - myIsCreated(false), - myFactory(factory), - myInterface(interface) + TestPlugin(DynamicLibrary::Ptr lib, + boost::shared_ptr factory) + : Plugin(lib), + myFactory(factory) { // Empty } - ~TestPlugin() + boost::shared_ptr factory() { - if (myInterface) - myFactory->destroyPlugin(myInterface.get()); + return myFactory; } protected: // From Plugin - void createInterface() { myIsCreated = true; } - boost::shared_ptr factory() const { return myFactory; } +private: + boost::shared_ptr myFactory; +}; + +class TestPluginInstance : public PluginInstance +{ +public: + bool myIsCreated; + + TestPluginInstance( + int id, TestPlugin::Ptr plugin, PluginThread::Ptr thread, + boost::shared_ptr interface) + : PluginInstance(id, thread), + myIsCreated(false), + myPlugin(plugin), + myInterface(interface) + { + // Empty + } + + ~TestPluginInstance() + { + if (myInterface) + myPlugin->factory()->destroyPlugin(myInterface.get()); + } + +protected: + // From PluginInstance + void createInterface() { myIsCreated = true; } + boost::shared_ptr interface() { return myInterface; @@ -104,7 +130,7 @@ class TestPlugin : public Plugin } private: - boost::shared_ptr myFactory; + TestPlugin::Ptr myPlugin; boost::shared_ptr myInterface; }; @@ -117,15 +143,18 @@ struct PluginFixture : public ::testing::Test MockPluginFactory myMockFactory; MockPlugin myMockInterface; TestPlugin plugin; + TestPluginInstance instance; pthread_t myPluginThreadId; PluginFixture() : myLib(new DynamicLibrary("")), myThread(new PluginThread()), - plugin(1, myLib, myThread, - boost::shared_ptr(&myMockFactory, &nullDeleter), - boost::shared_ptr(&myMockInterface, &nullDeleter)), + plugin(myLib, + boost::shared_ptr(&myMockFactory, &nullDeleter)), + instance(1, boost::shared_ptr(&plugin, &nullDeleter), + myThread, + boost::shared_ptr(&myMockInterface, &nullDeleter)), myPluginThreadId(0) { EXPECT_CALL(myMockFactory, destroyPlugin(&myMockInterface)); @@ -153,12 +182,12 @@ TEST_F(PluginFixture, callApiFunctions) // Verify that the calls are forwarded to the interface plugin.name(); plugin.version(); - plugin.shutdown(); + instance.shutdown(); } TEST_F(PluginFixture, castToInternalInterface) { - Plugin::Ptr ptr(&plugin, &nullDeleter); + PluginInstance::Ptr ptr(&instance, &nullDeleter); EXPECT_FALSE(plugin_internal_cast(ptr)); EXPECT_EQ(plugin_internal_cast(ptr).get(), @@ -181,7 +210,7 @@ TEST_F(PluginFixture, lifeTimeOfCastedObject) { boost::shared_ptr interface; { - Plugin::Ptr ptr(&plugin, &countingNullDeleter); + PluginInstance::Ptr ptr(&instance, &countingNullDeleter); interface = plugin_internal_cast(ptr); } EXPECT_EQ(0, DeleteCount); @@ -192,25 +221,25 @@ TEST_F(PluginFixture, lifeTimeOfCastedObject) TEST_F(PluginFixture, create) { - EXPECT_FALSE(plugin.myIsCreated); - EXPECT_TRUE(plugin.create()); - EXPECT_TRUE(plugin.myIsCreated); + EXPECT_FALSE(instance.myIsCreated); + EXPECT_TRUE(instance.create()); + EXPECT_TRUE(instance.myIsCreated); } struct CallbackData { bool myCalled; - const Plugin* myPlugin; + const PluginInstance* myInstance; pthread_t myThreadId; - CallbackData() : myCalled(false), myPlugin(NULL), myThreadId(0) { } + CallbackData() : myCalled(false), myInstance(NULL), myThreadId(0) { } }; static CallbackData InitCallbackData; -static void initCallback(const Plugin& plugin) +static void initCallback(const PluginInstance& instance) { InitCallbackData.myCalled = true; - InitCallbackData.myPlugin = &plugin; + InitCallbackData.myInstance = &instance; InitCallbackData.myThreadId = ::pthread_self(); } @@ -219,26 +248,26 @@ TEST_F(PluginFixture, init) EXPECT_CALL(myMockInterface, init(1, _)); InitCallbackData = CallbackData(); - plugin.init(0, NULL, &initCallback); + instance.init(0, NULL, &initCallback); EXPECT_TRUE(InitCallbackData.myCalled); - EXPECT_EQ(&plugin, InitCallbackData.myPlugin); + EXPECT_EQ(&instance, InitCallbackData.myInstance); EXPECT_TRUE(myThread->isThread(InitCallbackData.myThreadId)); } static CallbackData StartCallbackData; -static void startCallback(const Plugin& plugin) +static void startCallback(const PluginInstance& instance) { StartCallbackData.myCalled = true; - StartCallbackData.myPlugin = &plugin; + StartCallbackData.myInstance = &instance; StartCallbackData.myThreadId = ::pthread_self(); } static CallbackData ExitCallbackData; -static void exitCallback(const Plugin& plugin) +static void exitCallback(const PluginInstance& instance) { ExitCallbackData.myCalled = true; - ExitCallbackData.myPlugin = &plugin; + ExitCallbackData.myInstance = &instance; ExitCallbackData.myThreadId = ::pthread_self(); } @@ -250,15 +279,15 @@ TEST_F(PluginFixture, run) StartCallbackData = CallbackData(); ExitCallbackData = CallbackData(); - plugin.run(&startCallback, &exitCallback); - EXPECT_EQ(5, plugin.joinThread()); + instance.run(&startCallback, &exitCallback); + EXPECT_EQ(5, instance.joinThread()); EXPECT_TRUE(StartCallbackData.myCalled); - EXPECT_EQ(&plugin, StartCallbackData.myPlugin); + EXPECT_EQ(&instance, StartCallbackData.myInstance); EXPECT_TRUE(::pthread_equal(myPluginThreadId, StartCallbackData.myThreadId)); EXPECT_TRUE(ExitCallbackData.myCalled); - EXPECT_EQ(&plugin, ExitCallbackData.myPlugin); + EXPECT_EQ(&instance, ExitCallbackData.myInstance); EXPECT_TRUE(::pthread_equal(myPluginThreadId, ExitCallbackData.myThreadId)); } diff --git a/licq/src/plugin/tests/protocolplugintest.cpp b/licq/src/plugin/tests/protocolplugintest.cpp index f791b0bf9..87a3b9eaf 100644 --- a/licq/src/plugin/tests/protocolplugintest.cpp +++ b/licq/src/plugin/tests/protocolplugintest.cpp @@ -18,6 +18,7 @@ */ #include "../protocolplugin.h" +#include "../protocolplugininstance.h" #include #include @@ -27,6 +28,7 @@ #include using LicqDaemon::ProtocolPlugin; +using LicqDaemon::ProtocolPluginInstance; using LicqDaemon::DynamicLibrary; using LicqDaemon::PluginThread; @@ -71,19 +73,21 @@ struct ProtocolPluginFixture : public ::testing::Test MockProtocolPluginFactory myMockFactory; MockProtocolPlugin myMockInterface; ProtocolPlugin plugin; + ProtocolPluginInstance instance; ProtocolPluginFixture() : myLib(new DynamicLibrary("")), myThread(new PluginThread()), - plugin(1, myLib, myThread, - boost::shared_ptr( - &myMockFactory, &nullDeleter)) + plugin(myLib, boost::shared_ptr( + &myMockFactory, &nullDeleter)), + instance(1, boost::shared_ptr(&plugin, &nullDeleter), + myThread) { EXPECT_CALL(myMockFactory, createPlugin()) .WillOnce(Return(&myMockInterface)); EXPECT_CALL(myMockFactory, destroyPlugin(&myMockInterface)); - plugin.create(); + EXPECT_TRUE(instance.create()); } ~ProtocolPluginFixture() @@ -102,7 +106,7 @@ struct RunnableProtocolPluginFixture TEST_P(RunnableProtocolPluginFixture, callApiFunctions) { if (GetParam()) - plugin.setIsRunning(true); + instance.setIsRunning(true); boost::shared_ptr signal( reinterpret_cast(123), &nullDeleter); @@ -120,7 +124,7 @@ TEST_P(RunnableProtocolPluginFixture, callApiFunctions) // Verify that the calls are forwarded to the interface plugin.protocolId(); plugin.capabilities(); - plugin.pushSignal(signal); + instance.pushSignal(signal); plugin.createUser(user, false); plugin.createOwner(owner); } diff --git a/qt4-gui/src/core/systemmenu.cpp b/qt4-gui/src/core/systemmenu.cpp index 42b9ff15d..24e6bc7e3 100644 --- a/qt4-gui/src/core/systemmenu.cpp +++ b/qt4-gui/src/core/systemmenu.cpp @@ -418,7 +418,7 @@ void SystemMenu::toggleMainInvisibleStatus() void SystemMenu::updateAllUsers() { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -439,7 +439,7 @@ void SystemMenu::updateAllUsersInGroup() return; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -692,7 +692,7 @@ void OwnerData::setIcqFollowMeStatus(QAction* action) int id = action->data().toUInt(); Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; icq->icqSetPhoneFollowMeStatus(myUserId, id); diff --git a/qt4-gui/src/core/usermenu.cpp b/qt4-gui/src/core/usermenu.cpp index 115a5c1d3..ad281982a 100644 --- a/qt4-gui/src/core/usermenu.cpp +++ b/qt4-gui/src/core/usermenu.cpp @@ -451,7 +451,7 @@ void UserMenu::send(QAction* action) Licq::IcqProtocol::Ptr icq; if (myPpid == LICQ_PPID) icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); switch (index) { diff --git a/qt4-gui/src/dialogs/adduserdlg.cpp b/qt4-gui/src/dialogs/adduserdlg.cpp index d5e04c9b7..74e834d13 100644 --- a/qt4-gui/src/dialogs/adduserdlg.cpp +++ b/qt4-gui/src/dialogs/adduserdlg.cpp @@ -130,7 +130,7 @@ void AddUserDlg::ok() if (added && notify && userId.protocolId() == LICQ_PPID) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (icq) icq->icqAlertUser(userId); } diff --git a/qt4-gui/src/dialogs/chatdlg.cpp b/qt4-gui/src/dialogs/chatdlg.cpp index f65a80446..acee487b8 100644 --- a/qt4-gui/src/dialogs/chatdlg.cpp +++ b/qt4-gui/src/dialogs/chatdlg.cpp @@ -337,7 +337,7 @@ ChatDlg::ChatDlg(const Licq::UserId& userId, QWidget* parent) style |= Licq::STYLE_VARIABLExPITCH; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) { close(); diff --git a/qt4-gui/src/dialogs/editcategorydlg.cpp b/qt4-gui/src/dialogs/editcategorydlg.cpp index 8e74ae745..d7b7e4949 100644 --- a/qt4-gui/src/dialogs/editcategorydlg.cpp +++ b/qt4-gui/src/dialogs/editcategorydlg.cpp @@ -43,7 +43,7 @@ EditCategoryDlg::EditCategoryDlg(Licq::UserCat cat, const Licq::UserCategoryMap& QString title = "Licq - Edit @ Category"; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) { close(); @@ -139,7 +139,7 @@ EditCategoryDlg::EditCategoryDlg(Licq::UserCat cat, const Licq::UserCategoryMap& void EditCategoryDlg::ok() { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) { close(); diff --git a/qt4-gui/src/dialogs/filedlg.cpp b/qt4-gui/src/dialogs/filedlg.cpp index 3c753210f..7ef649089 100644 --- a/qt4-gui/src/dialogs/filedlg.cpp +++ b/qt4-gui/src/dialogs/filedlg.cpp @@ -134,7 +134,7 @@ FileDlg::FileDlg(const Licq::UserId& userId, QWidget* parent) hbox->addWidget(btnCancel); Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (icq) { //TODO fix this diff --git a/qt4-gui/src/dialogs/mmsenddlg.cpp b/qt4-gui/src/dialogs/mmsenddlg.cpp index d4be2690e..98ee0b3c5 100644 --- a/qt4-gui/src/dialogs/mmsenddlg.cpp +++ b/qt4-gui/src/dialogs/mmsenddlg.cpp @@ -251,7 +251,7 @@ void MMSendDlg::SendNext() case Licq::UserEvent::TypeContactList: { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; diff --git a/qt4-gui/src/dialogs/phonedlg.cpp b/qt4-gui/src/dialogs/phonedlg.cpp index a142bb7ed..4bba6b08e 100644 --- a/qt4-gui/src/dialogs/phonedlg.cpp +++ b/qt4-gui/src/dialogs/phonedlg.cpp @@ -54,7 +54,7 @@ EditPhoneDlg::EditPhoneDlg(QWidget* parent, const struct Licq::PhoneBookEntry* p m_nEntry = nEntry; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) { close(); diff --git a/qt4-gui/src/dialogs/randomchatdlg.cpp b/qt4-gui/src/dialogs/randomchatdlg.cpp index a5bf230dd..38e6eb783 100644 --- a/qt4-gui/src/dialogs/randomchatdlg.cpp +++ b/qt4-gui/src/dialogs/randomchatdlg.cpp @@ -109,7 +109,7 @@ RandomChatDlg::~RandomChatDlg() void RandomChatDlg::okPressed() { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; diff --git a/qt4-gui/src/dialogs/searchuserdlg.cpp b/qt4-gui/src/dialogs/searchuserdlg.cpp index 17e655b76..658fe9440 100644 --- a/qt4-gui/src/dialogs/searchuserdlg.cpp +++ b/qt4-gui/src/dialogs/searchuserdlg.cpp @@ -63,7 +63,7 @@ SearchUserDlg::SearchUserDlg(const Licq::UserId& ownerId) setWindowTitle(tr("Licq - User Search")); Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) { close(); @@ -240,7 +240,7 @@ void SearchUserDlg::startSearch() unsigned short maxs[7] = {0, 22, 29, 39, 49, 59, 120}; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; diff --git a/qt4-gui/src/dialogs/showawaymsgdlg.cpp b/qt4-gui/src/dialogs/showawaymsgdlg.cpp index 1d43b5af8..f20d3b360 100644 --- a/qt4-gui/src/dialogs/showawaymsgdlg.cpp +++ b/qt4-gui/src/dialogs/showawaymsgdlg.cpp @@ -97,7 +97,7 @@ ShowAwayMsgDlg::ShowAwayMsgDlg(const Licq::UserId& userId, bool fetch, QWidget* if (myUserId.protocolId() == LICQ_PPID) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (icq) icqEventTag = icq->icqFetchAutoResponse(myUserId); } diff --git a/qt4-gui/src/settings/plugins.cpp b/qt4-gui/src/settings/plugins.cpp index 6be859db6..ec88e9217 100644 --- a/qt4-gui/src/settings/plugins.cpp +++ b/qt4-gui/src/settings/plugins.cpp @@ -1,6 +1,6 @@ /* * This file is part of Licq, an instant messaging client for UNIX. - * Copyright (C) 2012 Licq developers + * Copyright (C) 2012-2013 Licq developers * * Licq is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,16 +41,17 @@ using namespace LicqQtGui; /* TRANSLATOR LicqQtGui::Settings::Plugins */ -static Licq::GeneralPlugin::Ptr getGeneralPlugin(int id) +static Licq::GeneralPluginInstance::Ptr getGeneralPluginInstance(int id) { Licq::GeneralPluginsList plugins; Licq::gPluginManager.getGeneralPluginsList(plugins); BOOST_FOREACH(Licq::GeneralPlugin::Ptr plugin, plugins) { - if (plugin->id() == id) - return plugin; + Licq::GeneralPluginInstance::Ptr instance = plugin->instance(); + if (instance && instance->id() == id) + return instance; } - return Licq::GeneralPlugin::Ptr(); + return Licq::GeneralPluginInstance::Ptr(); } Settings::Plugins::Plugins(SettingsDlg* parent) @@ -116,14 +117,18 @@ void Settings::Plugins::updatePluginList() Licq::gPluginManager.getGeneralPluginsList(plugins); BOOST_FOREACH(Licq::GeneralPlugin::Ptr plugin, plugins) { + Licq::GeneralPluginInstance::Ptr instance = plugin->instance(); + if (!instance) + continue; + QTreeWidgetItem* item = new QTreeWidgetItem(myPluginsList); item->setText(0, plugin->name().c_str()); item->setText(1, plugin->version().c_str()); - item->setText(2, plugin->isEnabled() ? tr("Yes") : tr("No")); + item->setText(2, instance->isEnabled() ? tr("Yes") : tr("No")); item->setText(3, plugin->description().c_str()); - item->setData(0, Qt::UserRole, plugin->id()); - item->setData(2, Qt::UserRole, plugin->isEnabled()); + item->setData(0, Qt::UserRole, instance->id()); + item->setData(2, Qt::UserRole, instance->isEnabled()); } // Get list of available (not loaded) plugins @@ -174,11 +179,11 @@ void Settings::Plugins::unloadPlugin() return; int index = item->data(0, Qt::UserRole).toInt(); - Licq::GeneralPlugin::Ptr plugin = getGeneralPlugin(index); - if (plugin.get() == NULL) + Licq::GeneralPluginInstance::Ptr instance = getGeneralPluginInstance(index); + if (!instance) return; - Licq::gPluginManager.unloadGeneralPlugin(plugin); + Licq::gPluginManager.unloadGeneralPlugin(instance->plugin()); QTimer::singleShot(1000, this, SLOT(updatePluginList())); } @@ -190,11 +195,11 @@ void Settings::Plugins::enablePlugin() return; int index = item->data(0, Qt::UserRole).toInt(); - Licq::GeneralPlugin::Ptr plugin = getGeneralPlugin(index); - if (plugin.get() == NULL) + Licq::GeneralPluginInstance::Ptr instance = getGeneralPluginInstance(index); + if (!instance) return; - plugin->enable(); + instance->enable(); QTimer::singleShot(1000, this, SLOT(updatePluginList())); } @@ -206,11 +211,11 @@ void Settings::Plugins::disablePlugin() return; int index = item->data(0, Qt::UserRole).toInt(); - Licq::GeneralPlugin::Ptr plugin = getGeneralPlugin(index); - if (plugin.get() == NULL) + Licq::GeneralPluginInstance::Ptr instance = getGeneralPluginInstance(index); + if (!instance) return; - plugin->disable(); + instance->disable(); QTimer::singleShot(1000, this, SLOT(updatePluginList())); } @@ -228,10 +233,12 @@ void Settings::Plugins::pluginDoubleClicked(QTreeWidgetItem* item, int /* index } int index = item->data(0, Qt::UserRole).toInt(); - Licq::GeneralPlugin::Ptr plugin = getGeneralPlugin(index); - if (plugin.get() == NULL) + Licq::GeneralPluginInstance::Ptr instance = getGeneralPluginInstance(index); + if (!instance) return; + Licq::GeneralPlugin::Ptr plugin = instance->plugin(); + if (plugin->configFile().empty()) { InformUser(dynamic_cast(parent()), diff --git a/qt4-gui/src/userdlg/info.cpp b/qt4-gui/src/userdlg/info.cpp index 85504ccdc..dd1ee09d1 100644 --- a/qt4-gui/src/userdlg/info.cpp +++ b/qt4-gui/src/userdlg/info.cpp @@ -190,7 +190,7 @@ QWidget* UserPages::Info::createPageGeneral(QWidget* parent) if (myPpid == LICQ_PPID) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); lay->addWidget(new QLabel(tr("Email 2:")), ++CR, 0); nfoEmailSecondary = new InfoField(false); @@ -284,7 +284,7 @@ void UserPages::Info::loadPageGeneral(const Licq::User* u) return; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -330,7 +330,7 @@ void UserPages::Info::savePageGeneral(Licq::User* u) return; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -438,7 +438,7 @@ QWidget* UserPages::Info::createPageMore(QWidget* parent) lay->addWidget(cmbLanguage[2], CR, 1); Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (icq) { for (unsigned short i = 0; i < 3; i++) @@ -481,7 +481,7 @@ QWidget* UserPages::Info::createPageMore(QWidget* parent) void UserPages::Info::loadPageMore(const Licq::User* u) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -621,7 +621,7 @@ void UserPages::Info::savePageMore(Licq::User* u) if (m_bOwner) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -754,7 +754,7 @@ void UserPages::Info::updateMore2Info(Licq::UserCat cat, const Licq::UserCategor delete lvChild; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -814,7 +814,7 @@ void UserPages::Info::savePageMore2(Licq::IcqUser* u) QWidget* UserPages::Info::createPageWork(QWidget* parent) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); QWidget* w = new QWidget(parent); myPageWorkLayout = new QVBoxLayout(w); @@ -905,7 +905,7 @@ QWidget* UserPages::Info::createPageWork(QWidget* parent) void UserPages::Info::loadPageWork(const Licq::User* u) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -952,7 +952,7 @@ void UserPages::Info::loadPageWork(const Licq::User* u) void UserPages::Info::savePageWork(Licq::User* u) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -1085,7 +1085,7 @@ void UserPages::Info::loadPagePhoneBook(const Licq::IcqUser* u) void UserPages::Info::updatePhoneBook() { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -1491,7 +1491,7 @@ unsigned long UserPages::Info::retrieve(UserDlg::UserPage page) if (myPpid != LICQ_PPID) return 0; Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); icqEventTag = icq->icqRequestPluginInfo( myUserId, Licq::IcqProtocol::PluginPhoneBook); } @@ -1536,7 +1536,7 @@ unsigned long UserPages::Info::send(UserDlg::UserPage page) if (myPpid == LICQ_PPID) { icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return 0; } diff --git a/qt4-gui/src/userdlg/owner.cpp b/qt4-gui/src/userdlg/owner.cpp index f96bf8d61..8474e2ee5 100644 --- a/qt4-gui/src/userdlg/owner.cpp +++ b/qt4-gui/src/userdlg/owner.cpp @@ -279,7 +279,7 @@ unsigned long UserPages::Owner::send(UserDlg::UserPage page) if (myProtocolId == LICQ_PPID) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return 0; diff --git a/qt4-gui/src/userevents/usersendevent.cpp b/qt4-gui/src/userevents/usersendevent.cpp index 772c29de6..a93986e28 100644 --- a/qt4-gui/src/userevents/usersendevent.cpp +++ b/qt4-gui/src/userevents/usersendevent.cpp @@ -945,7 +945,7 @@ void UserSendEvent::retrySend(const Licq::Event* e, unsigned flags) if (myUsers.front().protocolId() == LICQ_PPID) { icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); } switch (e->userEvent()->eventType()) @@ -1314,7 +1314,7 @@ void UserSendEvent::send() if (myUsers.front().protocolId() == LICQ_PPID) { icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); } switch (myType) diff --git a/qt4-gui/src/userevents/userviewevent.cpp b/qt4-gui/src/userevents/userviewevent.cpp index 139e57644..21f558cf2 100644 --- a/qt4-gui/src/userevents/userviewevent.cpp +++ b/qt4-gui/src/userevents/userviewevent.cpp @@ -422,7 +422,7 @@ void UserViewEvent::read2() case Licq::UserEvent::TypeChat: // accept a chat request { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -502,7 +502,7 @@ void UserViewEvent::read3() if (r->exec()) { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; @@ -565,7 +565,7 @@ void UserViewEvent::read4() case Licq::UserEvent::TypeChat: // join to current chat { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return; diff --git a/rms/src/rms.cpp b/rms/src/rms.cpp index 5c305ae50..e719067d2 100644 --- a/rms/src/rms.cpp +++ b/rms/src/rms.cpp @@ -1306,7 +1306,7 @@ int CRMSClient::Process_SMS_number() int CRMSClient::Process_SMS_message() { Licq::IcqProtocol::Ptr icq = plugin_internal_cast( - Licq::gPluginManager.getProtocolPlugin(LICQ_PPID)); + Licq::gPluginManager.getProtocolInstance(LICQ_PPID)); if (!icq) return fflush(fs);