1 /*
2  * This file is part of Licq, an instant messaging client for UNIX.
3  * Copyright (C) 2010-2013 Licq developers <licq-dev@googlegroups.com>
4  *
5  * Licq is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Licq is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Licq; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #ifndef LICQDAEMON_PLUGINMANAGER_H
21 #define LICQDAEMON_PLUGINMANAGER_H
22 
23 #include <licq/plugin/pluginmanager.h>
24 #include <licq/thread/mutex.h>
25 
26 #include "../utils/dynamiclibrary.h"
27 #include "generalplugin.h"
28 #include "generalplugininstance.h"
29 #include "pluginthread.h"
30 #include "protocolplugin.h"
31 #include "protocolplugininstance.h"
32 
33 #include <map>
34 #include <queue>
35 
36 namespace LicqDaemon
37 {
38 
39 class PluginManager : public Licq::PluginManager
40 {
41 public:
42   static const unsigned int MAX_WAIT_PLUGIN = 10;
43 
44   PluginManager();
45   ~PluginManager();
46 
setGuiThread(PluginThread::Ptr guiThread)47   void setGuiThread(PluginThread::Ptr guiThread) { myGuiThread = guiThread; }
48 
49   GeneralPlugin::Ptr loadGeneralPlugin(
50       const std::string& name, int argc, char** argv, bool keep = true);
51   ProtocolPlugin::Ptr loadProtocolPlugin(
52       const std::string& name, bool keep = true);
53 
54   /// Start all plugins that have been loaded
55   void startAllPlugins();
56 
57   /// Send shutdown signal to all the plugins
58   void shutdownAllPlugins();
59 
60   /// Shutdown specific protocol instance
61   void shutdownProtocolInstance(const Licq::UserId& ownerId);
62 
63   /// Notify the manager that a plugin has exited
64   void pluginHasExited(int id);
65 
66   /**
67    * Remove a plugin that has exited
68    * Called by main thread when notified about a plugin termination
69    */
70   void reapPlugin();
71 
72   /// Cancel all plugins' threads.
73   void cancelAllPlugins();
74 
75   size_t getGeneralPluginsCount() const;
76 
77   /// Get number of plugins (general and protocol)
78   size_t pluginCount() const;
79 
80   /**
81    * Create a protocol specific user object
82    * Wrapper so ProtocolPlugin doesn't have to friend UserManager
83    * Called by UserManager
84    *
85    * @param id User id
86    * @param temporary True if user isn't added permanently to contact list
87    * @return A newly created user object
88    */
89   Licq::User* createProtocolUser(const Licq::UserId& id, bool temporary = false);
90 
91   /**
92    * Create a protocol specific owner object
93    * Wrapper so ProtocolPlugin doesn't have to friend UserManager
94    *
95    * @param id Owner user id
96    * @return A newly created owner object
97    */
98   Licq::Owner* createProtocolOwner(const Licq::UserId& id);
99 
100   // From Licq::PluginManager
101   void getGeneralPluginsList(Licq::GeneralPluginsList& plugins) const;
102   void getProtocolPluginsList(Licq::ProtocolPluginsList& plugins) const;
103   void getAvailableGeneralPlugins(Licq::StringList& plugins,
104                                   bool includeLoaded = true) const;
105   void getAvailableProtocolPlugins(Licq::StringList& plugins,
106                                    bool includeLoaded = true) const;
107   Licq::ProtocolPlugin::Ptr getProtocolPlugin(unsigned long protocolId) const;
108   Licq::ProtocolPluginInstance::Ptr getProtocolInstance(
109       const Licq::UserId& ownerId) const;
110   bool startGeneralPlugin(const std::string& name, int argc, char** argv);
111   bool startProtocolPlugin(const std::string& name);
112   void unloadGeneralPlugin(Licq::GeneralPlugin::Ptr plugin);
113   void unloadProtocolPlugin(Licq::ProtocolPlugin::Ptr plugin);
114   void pushPluginEvent(Licq::Event* event);
115   void pushPluginSignal(Licq::PluginSignal* signal);
116   void pushProtocolSignal(Licq::ProtocolSignal* signal);
117 
118 private:
119   void getAvailablePlugins(Licq::StringList& plugins,
120                            const std::string& prefix) const;
121 
122   DynamicLibrary::Ptr loadPlugin(PluginThread::Ptr pluginThread,
123                                  const std::string& name,
124                                  const std::string& prefix);
125   bool verifyPluginMagic(const std::string& name, char magic[4]);
126   bool verifyPluginVersion(const std::string& name, int version);
127   int getNewPluginId();
128 
129   void startInstance(GeneralPluginInstance::Ptr instance);
130   void startInstance(ProtocolPluginInstance::Ptr instance);
131 
132   bool reapGeneralInstance(int exitId);
133   bool reapProtocolInstance(int exitId);
134 
135   int myNextPluginId;
136   PluginThread::Ptr myGuiThread;
137   bool myIsProtocolsStarted;
138 
139   mutable Licq::Mutex myGeneralPluginsMutex;
140   std::list<GeneralPlugin::Ptr> myGeneralPlugins;
141   std::list<GeneralPluginInstance::Ptr> myGeneralInstances;
142 
143   mutable Licq::Mutex myProtocolPluginsMutex;
144   std::list<ProtocolPlugin::Ptr> myProtocolPlugins;
145   typedef std::map<Licq::UserId, ProtocolPluginInstance::Ptr>
146   ProtocolOwnerInstances;
147   ProtocolOwnerInstances myProtocolInstances;
148 
149   Licq::Mutex myExitListMutex;
150   std::queue<int> myExitList;
151 };
152 
153 extern PluginManager gPluginManager;
154 
155 } // namespace LicqDaemon
156 
157 #endif
158