1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2013 Licq Developers <licq-dev@googlegroups.com>
4 *
5 * Please refer to the COPYRIGHT file distributed with this source
6 * distribution for the names of the individual contributors.
7 *
8 * Licq is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Licq is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Licq; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "plugininstance.h"
24
25 #include <licq/plugin/plugininterface.h>
26
27 #include <cassert>
28 #include <cstring>
29
30 // From licq.cpp
31 extern char** global_argv;
32
33 using namespace LicqDaemon;
34
PluginInstance(int id,PluginThread::Ptr thread)35 PluginInstance::PluginInstance(
36 int id, PluginThread::Ptr thread)
37 : myId(id),
38 myThread(thread),
39 myIsRunning(false),
40 myArgc(0),
41 myArgv(NULL),
42 myArgvCopy(NULL),
43 myCreateCallback(NULL),
44 myStartCallback(NULL),
45 myExitCallback(NULL)
46 {
47 // Empty
48 }
49
~PluginInstance()50 PluginInstance::~PluginInstance()
51 {
52 for (int i = 0; i < myArgc; ++i)
53 ::free(myArgv[i]);
54 delete[] myArgv;
55 delete[] myArgvCopy;
56 }
57
id() const58 int PluginInstance::id() const
59 {
60 return myId;
61 }
62
internalInterface()63 boost::shared_ptr<Licq::PluginInterface> PluginInstance::internalInterface()
64 {
65 // Create a shared_ptr that keeps this object alive at least until the
66 // returned pointer goes out of scope.
67 return boost::shared_ptr<Licq::PluginInterface>(
68 shared_from_this(), interface().get());
69 }
70
isThread(const pthread_t & thread) const71 bool PluginInstance::isThread(const pthread_t& thread) const
72 {
73 return myThread->isThread(thread);
74 }
75
create(void (* callback)(const PluginInstance &))76 bool PluginInstance::create(void (*callback)(const PluginInstance&))
77 {
78 assert(myCreateCallback == NULL);
79 myCreateCallback = callback;
80
81 myThread->createPlugin(&createThreadEntry, this);
82 return !! interface();
83 }
84
init(int argc,char ** argv)85 bool PluginInstance::init(int argc, char** argv)
86 {
87 const size_t size = argc + 2;
88
89 myArgv = new char*[size];
90 myArgvCopy = new char*[size];
91
92 myArgv[size - 1] = NULL;
93
94 myArgv[0] = ::strdup(global_argv[0]);
95
96 for (int i = 0; i < argc; ++i)
97 myArgv[i + 1] = ::strdup(argv[i]);
98
99 myArgc = argc + 1;
100
101 // We need to create a copy of myArgv and pass that to the plugin, since
102 // e.g. KDE changes the pointers in argv (e.g. to strip the path in argv[0])
103 // and that messes up free, causing SIGSEGV in the destructor.
104 ::memcpy(myArgvCopy, myArgv, size * sizeof(char*));
105
106 return myThread->initPlugin(&initThreadEntry, this);
107 }
108
run(void (* startCallback)(const PluginInstance &),void (* exitCallback)(const PluginInstance &))109 void PluginInstance::run(void (*startCallback)(const PluginInstance&),
110 void (*exitCallback)(const PluginInstance&))
111 {
112 assert(myStartCallback == NULL && myExitCallback == NULL);
113 myStartCallback = startCallback;
114 myExitCallback = exitCallback;
115
116 myThread->startPlugin(&startThreadEntry, this);
117 }
118
shutdown()119 void PluginInstance::shutdown()
120 {
121 interface()->shutdown();
122 myIsRunning = false;
123 }
124
joinThread()125 int PluginInstance::joinThread()
126 {
127 void* result = myThread->join();
128 if (result != NULL && result != PTHREAD_CANCELED)
129 {
130 int* retval = static_cast<int*>(result);
131 int value = *retval;
132 delete retval;
133 return value;
134 }
135
136 return -1;
137 }
138
cancelThread()139 void PluginInstance::cancelThread()
140 {
141 myThread->cancel();
142 }
143
createThreadEntry(void * plugin)144 void PluginInstance::createThreadEntry(void* plugin)
145 {
146 PluginInstance* thisPlugin = static_cast<PluginInstance*>(plugin);
147
148 if (thisPlugin->myCreateCallback)
149 thisPlugin->myCreateCallback(*thisPlugin);
150
151 thisPlugin->createInterface();
152 }
153
initThreadEntry(void * plugin)154 bool PluginInstance::initThreadEntry(void* plugin)
155 {
156 PluginInstance* thisPlugin = static_cast<PluginInstance*>(plugin);
157
158 // Set optind to 0 so plugins can use getopt
159 optind = 0;
160
161 return thisPlugin->interface()->init(
162 thisPlugin->myArgc, thisPlugin->myArgvCopy);
163 }
164
startThreadEntry(void * plugin)165 void* PluginInstance::startThreadEntry(void* plugin)
166 {
167 PluginInstance* thisPlugin = static_cast<PluginInstance*>(plugin);
168
169 if (thisPlugin->myStartCallback != NULL)
170 (*thisPlugin->myStartCallback)(*thisPlugin);
171
172 thisPlugin->myIsRunning = true;
173
174 int* retval = new int;
175 *retval = thisPlugin->interface()->run();
176
177 if (thisPlugin->myExitCallback != NULL)
178 (*thisPlugin->myExitCallback)(*thisPlugin);
179
180 return retval;
181 }
182