evolution-3.6.4/modules/plugin-lib/e-plugin-lib.c

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 }