1 /* $Id: plugins.c,v 1.28 2005/05/20 15:22:12 mkobierzycki Exp $ */
2 
3 /*
4  * GNU Gadu 2
5  *
6  * Copyright (C) 2001-2005 GNU Gadu Team
7  *
8  * This program 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  * This program 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 this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 
23 #include <stdio.h>
24 #include <glib.h>
25 #include <gmodule.h>
26 #include <dlfcn.h>
27 
28 #include "plugins.h"
29 #include "ggadu_support.h"
30 #include "ggadu_types.h"
31 
32 /*
33     sprawdza czy plugin jest na liscie modulow do zaladowania
34     jesli nie ma pliku .gg2/modules.load laduje wszystkie dostepne pluginy
35     UWAGA: jesli plik istnieje lecz jest pusty, zaden plugin sie nie zaladuje
36 */
plugin_at_list(gchar * name)37 gboolean plugin_at_list(gchar * name)
38 {
39 	GIOChannel *ch = NULL;
40 	GString *buffer = NULL;
41 	gchar *filename;
42 	gint lines = 0;
43 	gchar *pattern_start = g_utf8_strchr(name,g_utf8_strlen(name,-1),'-');
44 
45 	if (pattern_start)
46 	{
47 		gint pattern_length = g_utf8_strlen(name,-1) - g_utf8_strlen(pattern_start,-1);
48 		gchar *pattern = g_strndup(name,pattern_length);
49 		gchar *pattern_concat = g_strconcat(pattern,"*",NULL);
50 		if (find_plugin_by_pattern(pattern_concat))
51 		{
52 		    g_free(pattern);
53 		    g_free(pattern_concat);
54 		    return FALSE;
55 		}
56 		g_free(pattern_concat);
57 		g_free(pattern);
58 	}
59 
60 	filename = g_build_filename(config->configdir, "modules.load", NULL);
61 	ch = g_io_channel_new_file(filename, "r", NULL);
62 	g_free(filename);
63 	if (!ch)
64 	{
65 		return TRUE;
66 	}
67 
68 	buffer =  g_string_new(NULL);
69 	while (g_io_channel_read_line_string(ch, buffer, NULL, NULL) != G_IO_STATUS_EOF)
70 	{
71 		if (buffer->str && *buffer->str == '\n')
72 		{
73 			continue;
74 		}
75 
76 		if (!g_strncasecmp(buffer->str, name, buffer->len - 1))
77 		{
78 			g_string_free(buffer, TRUE);
79 			return TRUE;
80 		}
81 
82 		lines++;
83 	}
84 
85 	g_string_free(buffer, TRUE);
86 	g_io_channel_shutdown(ch, TRUE, NULL);
87 	g_io_channel_unref(ch);
88 
89 	if (!lines)
90 		return TRUE;
91 
92 	return FALSE;
93 }
94 
95 /*
96  * Laduje modul o podanej sciezce (path) oraz nazwie (name)
97  */
load_plugin(gchar * path)98 gboolean load_plugin(gchar * path)
99 {
100 	GGaduPlugin *plugin_handler = NULL;
101 	GGaduPlugin *(*initialize_plugin) (gpointer);
102 	void (*start_plugin) ();
103 	void (*destroy_plugin) ();
104 	gchar *(*ggadu_plugin_name) ();
105 	gint(*ggadu_plugin_type) ();
106 	void *handler = NULL;
107 	gchar *error = NULL;
108 
109 	int i;
110 	const struct
111 	{
112 		char *name;
113 		void (**ptr) ();
114 	} syms[] =
115 	{
116 		{
117 		"ggadu_plugin_name", (void *) &ggadu_plugin_name},
118 		{
119 		"ggadu_plugin_type", (void *) &ggadu_plugin_type},
120 		{
121 		"initialize_plugin", (void *) &initialize_plugin},
122 		{
123 		"start_plugin", &start_plugin},
124 		{
125 		"destroy_plugin", &destroy_plugin},
126 		{
127 		NULL, NULL}
128 	};
129 
130 	print_debug("core: loading plugin: %s\n", path);
131 
132 	handler = dlopen(path, RTLD_NOW);
133 	if (!handler)
134 	{
135 		g_warning("%s is not a valid plugin file, load failed! %s\n", path, dlerror());
136 		return FALSE;
137 	}
138 	dlerror(); /* Clear previous errors */
139 
140 	for (i = 0; syms[i].name; i++)
141 	{
142 		*syms[i].ptr = dlsym(handler, syms[i].name);
143 
144 		if ((error = dlerror()) != NULL)
145 		{
146 			g_warning(_("core: %s have no %s: %s\n"), path, syms[i].name, error);
147 			dlclose(handler);
148 			return FALSE;
149 		}
150 	}
151 
152 	if (g_slist_find(config->loaded_plugins, ggadu_plugin_name()))
153 	{
154 		print_debug("core: ekhm... plugin %s is already loaded\n", path);
155 		dlclose(handler);
156 		return FALSE;
157 	}
158 
159 	if (plugin_at_list(ggadu_plugin_name()) || config->all_plugins_loaded)
160 	{
161 		plugin_handler = initialize_plugin(config);
162 		plugin_handler->plugin_so_handler = handler;
163 		plugin_handler->start_plugin = start_plugin;
164 		plugin_handler->destroy_plugin = destroy_plugin;
165 		plugin_handler->name = ggadu_plugin_name();
166 		plugin_handler->type = ggadu_plugin_type();
167 	}
168 
169 	if (config->all_plugins_loaded)
170 	{
171 		GSList *tmp = NULL;
172 		GGaduPluginFile *pf = NULL;
173 		char siedzi = 0;
174 
175 		tmp = config->all_available_plugins;
176 		while (tmp)
177 		{
178 			pf = (GGaduPluginFile *) tmp->data;
179 			if (!ggadu_strcasecmp(pf->name, ggadu_plugin_name()))
180 			{
181 				siedzi = 1;
182 				break;
183 			}
184 			tmp = tmp->next;
185 		}
186 		if (!siedzi)
187 		{
188 			pf = g_new0(GGaduPluginFile, 1);
189 
190 			pf->name = g_strdup(ggadu_plugin_name());
191 			pf->path = g_strdup(path);
192 
193 			config->all_available_plugins = g_slist_append(config->all_available_plugins, pf);
194 		}
195 		start_plugin();
196 	}
197 	else
198 	{
199 		GGaduPluginFile *pf = g_new0(GGaduPluginFile, 1);
200 
201 		pf->name = g_strdup(ggadu_plugin_name());
202 		pf->path = g_strdup(path);
203 
204 		config->all_available_plugins = g_slist_append(config->all_available_plugins, pf);
205 	}
206 
207 	return TRUE;
208 }
209 
unload_plugin(gchar * name)210 void unload_plugin(gchar * name)
211 {
212 	GGaduPlugin *plugin_handler = find_plugin_by_name(name);
213 	GSList *list_tmp = NULL;
214 	GGaduVar *var_tmp = NULL;
215 	GGaduSignalInfo *sig_tmp = NULL;
216 
217 	if (plugin_handler == NULL)
218 	{
219 		g_warning(_("core : trying to unload not loaded plugin %s\n"), name);
220 		return;
221 	}
222 
223 	print_debug("core: unloading plugin %s\n", name);
224 
225 	/* najpierw dajemy czas pluginowi na zrobienie porz�dku ze sob� */
226 	plugin_handler->destroy_plugin();
227 	dlclose(plugin_handler->plugin_so_handler);	/* tego ju� nie potrzebujemy */
228 
229 	/* jako, �e ju� nam praktycznie wszystko jedno w jakiej kolejno�ci,
230 	 * to dla porz�dku czy�cimy w takiej kolejno�ci, jak w ggadu_types.h,
231 	 * �eby o niczym nie zapomnie�
232 	 */
233 
234 	/* ważne - nie tyka� listy dost�pnych modu��w */
235 	/* wypierdzielamy plugin z listy w��czonych plugin�w */
236 	config->loaded_plugins = g_slist_remove(config->loaded_plugins, plugin_handler);
237 
238 	/* nie tyka� name */
239 /*
240     g_free (plugin_handler->name);
241 */
242 	g_free(plugin_handler->description);	/* description pod �cian� */
243 
244 	/* plugin_so_handler za�atwiony wcze�niej, wi�c skipujemy */
245 	g_free(plugin_handler->config_file);	/* po co komu plik konfiguracyjny? */
246 
247 	/* variables na celowniku */
248 	list_tmp = (GSList *) plugin_handler->variables;
249 	while (list_tmp)
250 	{
251 		var_tmp = (GGaduVar *) list_tmp->data;
252 		g_free(var_tmp->name);
253 		g_free(var_tmp);
254 		list_tmp = list_tmp->next;
255 	}
256 
257 	g_slist_free(plugin_handler->variables);
258 
259 	/* bye bye signals */
260 	list_tmp = (GSList *) plugin_handler->signals;
261 
262 	while (list_tmp)
263 	{
264 		sig_tmp = (GGaduSignalInfo *) list_tmp->data;
265 /*
266 	g_free (sig_tmp->name);
267 */
268 		g_free(sig_tmp);
269 		list_tmp = list_tmp->next;
270 	}
271 	g_slist_free(plugin_handler->signals);
272 	plugin_handler->signals = NULL;
273 
274 	/* dobry protok� to zwolniony protok� ;> */
275 /*
276     g_free (plugin_handler->protocol->display_name);
277     g_free (plugin_handler->protocol->img_filename);
278 */
279 
280 	/* protocol->statuslist */
281 /*
282     list_tmp = (GSList *)plugin_handler->protocol->statuslist;
283     while (list_tmp)
284     {
285 	sta_tmp = (GGaduStatusPrototype *) list_tmp->data;
286 	GGaduStatusPrototype_free (sta_tmp);
287 	list_tmp = list_tmp->next;
288     }
289     g_slist_free(plugin_handler->protocol->statuslist);
290 */
291 
292 	/* u�mierci� */
293 /*
294     g_free (plugin_handler->protocol);
295 */
296 	g_free(plugin_handler);
297 }
298 
299 /* caution : can return NULL and it not mean that there is no such variable */
config_var_get(GGaduPlugin * handler,gchar * name)300 gpointer config_var_get(GGaduPlugin * handler, gchar * name)
301 {
302 	GGaduVar *var = NULL;
303 	GSList *tmp = NULL;
304 
305 	if ((handler == NULL) || (name == NULL) || (handler->variables == NULL))
306 		return NULL;
307 
308 	tmp = handler->variables;
309 
310 	while (tmp)
311 	{
312 		var = (GGaduVar *) tmp->data;
313 
314 		if ((var != NULL) && (!ggadu_strcasecmp(var->name, name)))
315 		{
316 			return var->ptr;
317 		}
318 
319 		tmp = tmp->next;
320 	}
321 	return NULL;
322 }
323 
324 
register_signal_receiver(GGaduPlugin * plugin_handler,void (* sgr)(gpointer,gpointer))325 void register_signal_receiver(GGaduPlugin * plugin_handler, void (*sgr) (gpointer, gpointer))
326 {
327 	if ((plugin_handler == NULL) || (sgr == NULL))
328 		return;
329 
330 	print_debug("core : register_signal_receiver for %s\n", plugin_handler->name);
331 
332 	plugin_handler->signal_receive_func = sgr;
333 }
334 
335 /*
336  *    Rejestruje nowy protokol o nazwie (name) oraz o strukturze (struct_ptr) wrzucajac go do listy protokolow
337  *    Zwraca : handler zarejestrowanego protokolu
338  */
339 
register_plugin(gchar * name,gchar * desc)340 GGaduPlugin *register_plugin(gchar * name, gchar * desc)
341 {
342 	GGaduPlugin *plugin_handler = NULL;
343 
344 	if (name == NULL)
345 		return NULL;
346 
347 	print_debug("core : register_plugin %s\n", name);
348 
349 	plugin_handler = g_new0(GGaduPlugin, 1);	/* tu jest tworzony plugin tak naprawde */
350 
351 	plugin_handler->name = g_strdup(name);
352 	plugin_handler->description = g_strdup(desc);
353 
354 	config->loaded_plugins = g_slist_append(config->loaded_plugins, plugin_handler);
355 
356 	return (GGaduPlugin *) plugin_handler;
357 }
358 
359 
360 /*
361  *    Zwraca handler protokolu o podanej nazwie, z zaladowanych pluginow
362  */
363 
find_plugin_by_name(gchar * name)364 GGaduPlugin *find_plugin_by_name(gchar * name)
365 {
366 	GSList *tmp = (config) ? config->loaded_plugins : NULL;
367 	GGaduPlugin *plugin_handler = NULL;
368 
369 	if (name == NULL)
370 		return NULL;
371 
372 	while (tmp)
373 	{
374 		plugin_handler = (GGaduPlugin *) tmp->data;
375 
376 		if ((plugin_handler != NULL) && (plugin_handler->name != NULL) &&
377 		    (!ggadu_strcasecmp(plugin_handler->name, name)))
378 			return plugin_handler;
379 
380 		tmp = tmp->next;
381 	}
382 
383 	return NULL;
384 }
385 
386 /*
387  *  zwraca liste handlerow pasujacych do wzorca
388  */
find_plugin_by_pattern(gchar * pattern)389 GSList *find_plugin_by_pattern(gchar * pattern)
390 {
391 	GSList *tmp = config->loaded_plugins;
392 	GGaduPlugin *plugin_handler = NULL;
393 	GSList *found_list = NULL;
394 
395 	if (pattern == NULL)
396 		return NULL;
397 
398 	while (tmp)
399 	{
400 		plugin_handler = (GGaduPlugin *) tmp->data;
401 
402 		/* print_debug("pattern %s, name %s\n",pattern, plugin_handler->name); */
403 
404 		if (g_pattern_match_simple(pattern, plugin_handler->name))
405 			found_list = g_slist_append(found_list, plugin_handler);
406 
407 		tmp = tmp->next;
408 	}
409 
410 	return found_list;
411 }
412 
413 
register_extension_for_plugins(GGaduPluginExtension * ext)414 void register_extension_for_plugins(GGaduPluginExtension * ext)
415 {
416 	GSList *plugins;
417 
418 	if ((!ext) || (!config))
419 		return;
420 
421 	plugins = config->loaded_plugins;
422 
423 	while (plugins)
424 	{
425 		GGaduPlugin *handler = (GGaduPlugin *) plugins->data;
426 
427 		if (handler)
428 			handler->extensions = g_slist_append(handler->extensions, ext);
429 
430 		plugins = plugins->next;
431 	}
432 }
433 
register_extension_for_plugin(GGaduPluginExtension * ext,gint plugin_type)434 void register_extension_for_plugin(GGaduPluginExtension * ext, gint plugin_type)
435 {
436 	GSList *plugins;
437 
438 	if ((!ext) || (!config))
439 		return;
440 
441 	plugins = config->loaded_plugins;
442 
443 	while (plugins)
444 	{
445 		GGaduPlugin *handler = (GGaduPlugin *) plugins->data;
446 
447 		if ((handler) && handler->type == plugin_type)
448 			handler->extensions = g_slist_append(handler->extensions, ext);
449 
450 		plugins = plugins->next;
451 	}
452 
453 }
454 
unregister_extension_for_plugins(GGaduPluginExtension * ext)455 void unregister_extension_for_plugins(GGaduPluginExtension * ext)
456 {
457 	GSList *plugins;
458 	/* GSList *extensions; */
459 
460 	if ((!ext) || (!config))
461 		return;
462 
463 	plugins = config->loaded_plugins;
464 
465 	while (plugins)
466 	{
467 		GGaduPlugin *handler = (GGaduPlugin *) plugins->data;
468 
469 		handler->extensions = g_slist_remove((GSList *) handler->extensions, ext);
470 
471 /*		extensions = handler->extensions;
472 
473 		while (extensions) {
474 			GGaduPluginExtension *ext_search = extensions->data;
475 
476 			if (ext_search == ext)
477 				return ext;
478 
479 			extensions = extensions->next;
480 		}
481 
482 */
483 		plugins = plugins->next;
484 	}
485 
486 }
487 
ggadu_find_extension(GGaduPlugin * handler,gint type)488 GGaduPluginExtension *ggadu_find_extension(GGaduPlugin * handler, gint type)
489 {
490 	GSList *extensions;
491 
492 	if (!handler)
493 		return NULL;
494 
495 	extensions = handler->extensions;
496 	while (extensions)
497 	{
498 		GGaduPluginExtension *ext = extensions->data;
499 
500 		if (ext->type == type)
501 			return ext;
502 
503 		extensions = extensions->next;
504 	}
505 	return NULL;
506 }
507 
ggadu_get_extensions_list(GGaduPlugin * handler)508 gpointer ggadu_get_extensions_list(GGaduPlugin * handler)
509 {
510 	if (!handler)
511 		return NULL;
512 
513 	return handler->extensions;
514 }
515 
ggadu_extension_get_type(GGaduPluginExtension * ext)516 guint	ggadu_extension_get_type(GGaduPluginExtension *ext)
517 {
518 	if (!ext)
519 		return 0;
520 
521 	return ext->type;
522 }
523 
524 
525 
get_list_modules_load()526 GSList *get_list_modules_load()
527 {
528 	GIOChannel *ch = NULL;
529 	GString *buffer = g_string_new(NULL);
530 	GSList *tmp = NULL, *ret = NULL;
531 	GGaduPlugin *plugin = NULL;
532 
533 	ch = g_io_channel_new_file(g_build_filename(config->configdir, "modules.load", NULL), "r", NULL);
534 
535 	if (ch)
536 	{
537 		while (g_io_channel_read_line_string(ch, buffer, NULL, NULL) != G_IO_STATUS_EOF)
538 		{
539 			tmp = config->loaded_plugins;
540 			while (tmp)
541 			{
542 				plugin = (GGaduPlugin *) tmp->data;
543 
544 				if (buffer->len > 1 && !g_strncasecmp(buffer->str, plugin->name, buffer->len - 1))
545 					ret = g_slist_append(ret, plugin);
546 
547 				tmp = tmp->next;
548 			}
549 		}
550 		g_io_channel_shutdown(ch, TRUE, NULL);
551 		g_io_channel_unref(ch);
552 	}
553 
554 	/* ugly hack: no modules.load file, load all plugins */
555 	if (ret == NULL)
556 	{
557 		tmp = config->loaded_plugins;
558 		while (tmp)
559 		{
560 			plugin = (GGaduPlugin *) tmp->data;
561 			ret = g_slist_append(ret, plugin);
562 			tmp = tmp->next;
563 		}
564 	}
565 	return ret;
566 }
567