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