No issues found
1 /*
2 * e-plugin-lib.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "e-plugin-lib.h"
27
28 #ifdef G_OS_WIN32
29 #include <libedataserver/e-data-server-util.h> /* for e_util_replace_prefix() */
30 #endif
31
32 #include <string.h>
33
34 static gpointer parent_class;
35 static GType plugin_lib_type;
36
37 /* TODO:
38 * We need some way to manage lifecycle.
39 * We need some way to manage state.
40 *
41 * Maybe just the g module init method will do, or we could add
42 * another which returns context.
43 *
44 * There is also the question of per-instance context, e.g. for config
45 * pages.
46 */
47
48 static gint
49 plugin_lib_loadmodule (EPlugin *plugin)
50 {
51 EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin);
52 EPluginLibEnableFunc enable;
53 gboolean found_symbol;
54
55 if (plugin_lib->module != NULL)
56 return 0;
57
58 if (plugin_lib->location == NULL) {
59 plugin->enabled = FALSE;
60 g_warning ("Location not set in plugin '%s'", plugin->name);
61 return -1;
62 }
63
64 plugin_lib->module = g_module_open (plugin_lib->location, 0);
65
66 if (plugin_lib->module == NULL) {
67 plugin->enabled = FALSE;
68 g_warning (
69 "can't load plugin '%s': %s",
70 plugin_lib->location, g_module_error ());
71 return -1;
72 }
73
74 /* If the plugin is disabled, we're done. */
75 if (!plugin->enabled)
76 return 0;
77
78 found_symbol = g_module_symbol (
79 plugin_lib->module,
80 "e_plugin_lib_enable",
81 (gpointer) &enable);
82
83 if (found_symbol) {
84 if (enable (plugin, TRUE) != 0) {
85 plugin->enabled = FALSE;
86 g_module_close (plugin_lib->module);
87 plugin_lib->module = NULL;
88 return -1;
89 }
90 }
91
92 return 0;
93 }
94
95 static gpointer
96 plugin_lib_get_symbol (EPlugin *plugin,
97 const gchar *name)
98 {
99 EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin);
100 gpointer symbol;
101
102 if (plugin_lib_loadmodule (plugin) != 0)
103 return NULL;
104
105 if (!g_module_symbol (plugin_lib->module, name, &symbol))
106 return NULL;
107
108 return symbol;
109 }
110
111 static gpointer
112 plugin_lib_invoke (EPlugin *plugin,
113 const gchar *name,
114 gpointer data)
115 {
116 EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin);
117 EPluginLibFunc func;
118
119 if (!plugin->enabled) {
120 g_warning (
121 "Trying to invoke '%s' on disabled plugin '%s'",
122 name, plugin->id);
123 return NULL;
124 }
125
126 func = plugin_lib_get_symbol (plugin, name);
127
128 if (func == NULL) {
129 g_warning (
130 "Cannot resolve symbol '%s' in plugin '%s' "
131 "(not exported?)", name, plugin_lib->location);
132 return NULL;
133 }
134
135 return func (plugin, data);
136 }
137
138 static gint
139 plugin_lib_construct (EPlugin *plugin,
140 xmlNodePtr root)
141 {
142 EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin);
143
144 /* Set the location before chaining up, as some EPluginHooks
145 * will cause the module to load during hook construction. */
146
147 plugin_lib->location = e_plugin_xml_prop (root, "location");
148
149 if (plugin_lib->location == NULL) {
150 g_warning ("Library plugin '%s' has no location", plugin->id);
151 return -1;
152 }
153 #ifdef G_OS_WIN32
154 {
155 gchar *mapped_location =
156 e_util_replace_prefix (
157 EVOLUTION_PREFIX,
158 e_util_get_prefix (),
159 plugin_lib->location);
160 g_free (plugin_lib->location);
161 plugin_lib->location = mapped_location;
162 }
163 #endif
164
165 /* Chain up to parent's construct() method. */
166 if (E_PLUGIN_CLASS (parent_class)->construct (plugin, root) == -1)
167 return -1;
168
169 /* If we're enabled, check for the load-on-startup property */
170 if (plugin->enabled) {
171 xmlChar *tmp;
172
173 tmp = xmlGetProp (root, (const guchar *)"load-on-startup");
174 if (tmp) {
175 if (plugin_lib_loadmodule (plugin) != 0) {
176 xmlFree (tmp);
177 return -1;
178 }
179 xmlFree (tmp);
180 }
181 }
182
183 return 0;
184 }
185
186 static GtkWidget *
187 plugin_lib_get_configure_widget (EPlugin *plugin)
188 {
189 EPluginLibGetConfigureWidgetFunc get_configure_widget;
190
191 get_configure_widget = plugin_lib_get_symbol (
192 plugin, "e_plugin_lib_get_configure_widget");
193
194 if (get_configure_widget != NULL)
195 return get_configure_widget (plugin);
196
197 return NULL;
198 }
199
200 static void
201 plugin_lib_enable (EPlugin *plugin,
202 gint state)
203 {
204 EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin);
205 EPluginLibEnableFunc enable;
206
207 E_PLUGIN_CLASS (parent_class)->enable (plugin, state);
208
209 /* if we're disabling and it isn't loaded, nothing to do */
210 if (!state && plugin_lib->module == NULL)
211 return;
212
213 enable = plugin_lib_get_symbol (plugin, "e_plugin_lib_enable");
214
215 if (enable != NULL)
216 enable (plugin, state);
217 }
218
219 static void
220 plugin_lib_finalize (GObject *object)
221 {
222 EPluginLib *plugin_lib = E_PLUGIN_LIB (object);
223
224 g_free (plugin_lib->location);
225
226 if (plugin_lib->module)
227 g_module_close (plugin_lib->module);
228
229 /* Chain up to parent's finalize() method. */
230 G_OBJECT_CLASS (parent_class)->finalize (object);
231 }
232
233 static void
234 plugin_lib_class_init (EPluginClass *class)
235 {
236 GObjectClass *object_class;
237
238 parent_class = g_type_class_peek_parent (class);
239
240 object_class = G_OBJECT_CLASS (class);
241 object_class->finalize = plugin_lib_finalize;
242
243 class->construct = plugin_lib_construct;
244 class->invoke = plugin_lib_invoke;
245 class->get_symbol = plugin_lib_get_symbol;
246 class->enable = plugin_lib_enable;
247 class->get_configure_widget = plugin_lib_get_configure_widget;
248 class->type = "shlib";
249 }
250
251 GType
252 e_plugin_lib_get_type (void)
253 {
254 return plugin_lib_type;
255 }
256
257 void
258 e_plugin_lib_register_type (GTypeModule *type_module)
259 {
260 static const GTypeInfo type_info = {
261 sizeof (EPluginLibClass),
262 (GBaseInitFunc) NULL,
263 (GBaseFinalizeFunc) NULL,
264 (GClassInitFunc) plugin_lib_class_init,
265 (GClassFinalizeFunc) NULL,
266 NULL, /* class_data */
267 sizeof (EPluginLib),
268 0, /* n_preallocs */
269 (GInstanceInitFunc) NULL,
270 NULL /* value_table */
271 };
272
273 plugin_lib_type = g_type_module_register_type (
274 type_module, E_TYPE_PLUGIN,
275 "EPluginLib", &type_info, 0);
276 }