[gaim-migrate @ 3063]
[pidgin-git.git] / src / module.c
bloba27b411467f4e40d67fc36205ce0b7be7ab56fe9
1 /*
2 * gaim
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * ----------------
21 * The Plug-in plug
23 * Plugin support is currently being maintained by Mike Saraf
24 * msaraf@dwc.edu
26 * Well, I didn't see any work done on it for a while, so I'm going to try
27 * my hand at it. - Eric warmenhoven@yahoo.com
29 * Mike is my roomate. I can assure you that he's lazy :-P -- Rob rob@marko.net
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
37 #include "gaim.h"
39 #ifdef GAIM_PLUGINS
41 #include <string.h>
42 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
47 #include <unistd.h>
48 #include <stdio.h>
49 #include <stdlib.h>
51 /* ------------------ Global Variables ----------------------- */
53 GList *plugins = NULL;
54 GList *callbacks = NULL;
56 char *last_dir = NULL;
58 /* --------------- Function Declarations --------------------- */
60 struct gaim_plugin * load_plugin(char *);
61 void unload_plugin(struct gaim_plugin *p);
62 struct gaim_plugin *reload_plugin(struct gaim_plugin *p);
64 void gaim_signal_connect(GModule *, enum gaim_event, void *, void *);
65 void gaim_signal_disconnect(GModule *, enum gaim_event, void *);
66 void gaim_plugin_unload(GModule *);
68 /* --------------- Static Function Declarations ------------- */
70 static void plugin_remove_callbacks(GModule *);
72 /* ------------------ Code Below ---------------------------- */
74 struct gaim_plugin *load_plugin(char *filename)
76 struct gaim_plugin *plug;
77 GList *c = plugins;
78 char *(*gaim_plugin_init)(GModule *);
79 char *(*cfunc)();
80 char *error;
81 char *retval;
83 if (!g_module_supported())
84 return NULL;
85 if (filename && !strlen(filename))
86 return NULL;
88 while (filename && c) {
89 plug = (struct gaim_plugin *)c->data;
90 if (!strcmp(filename, g_module_name(plug->handle))) {
91 /* just need to reload plugin */
92 return reload_plugin(plug);
93 } else
94 c = g_list_next(c);
96 plug = g_malloc(sizeof *plug);
98 if (last_dir)
99 g_free(last_dir);
100 last_dir = g_dirname(filename);
102 debug_printf("Loading %s\n", filename);
103 plug->handle = g_module_open(filename, 0);
104 if (!plug->handle) {
105 error = (char *)g_module_error();
106 do_error_dialog(error, _("Plugin Error"));
107 g_free(plug);
108 return NULL;
111 if (!g_module_symbol(plug->handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) {
112 do_error_dialog(g_module_error(), _("Plugin Error"));
113 g_module_close(plug->handle);
114 g_free(plug);
115 return NULL;
118 retval = gaim_plugin_init(plug->handle);
119 debug_printf("loaded plugin returned %s\n", retval ? retval : "NULL");
120 if (retval) {
121 plugin_remove_callbacks(plug->handle);
122 do_error_dialog(retval, _("Plugin Error"));
123 g_module_close(plug->handle);
124 g_free(plug);
125 return NULL;
128 plugins = g_list_append(plugins, plug);
130 if (g_module_symbol(plug->handle, "name", (gpointer *)&cfunc)) {
131 plug->name = cfunc();
132 } else {
133 plug->name = NULL;
136 if (g_module_symbol(plug->handle, "description", (gpointer *)&cfunc))
137 plug->description = cfunc();
138 else
139 plug->description = NULL;
141 save_prefs();
142 return plug;
145 static void unload_gaim_plugin(struct gaim_plugin *p)
147 void (*gaim_plugin_remove)();
149 debug_printf("Unloading %s\n", g_module_name(p->handle));
151 /* Attempt to call the plugin's remove function (if there) */
152 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
153 gaim_plugin_remove();
155 plugin_remove_callbacks(p->handle);
157 plugins = g_list_remove(plugins, p);
158 g_free(p);
159 save_prefs();
162 void unload_plugin(struct gaim_plugin *p)
164 GModule *handle = p->handle;
165 unload_gaim_plugin(p);
166 g_module_close(handle);
169 static gboolean unload_timeout(gpointer handle)
171 g_module_close(handle);
172 return FALSE;
175 void gaim_plugin_unload(GModule *handle)
177 GList *pl = plugins;
178 struct gaim_plugin *p = NULL;
179 void (*gaim_plugin_remove)();
181 while (pl) {
182 p = pl->data;
183 if (p->handle == handle)
184 break;
185 pl = pl->next;
187 if (!pl)
188 return;
190 debug_printf("Unloading %s\n", g_module_name(p->handle));
192 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
193 gaim_plugin_remove();
194 plugin_remove_callbacks(p->handle);
195 plugins = g_list_remove(plugins, p);
196 g_free(p);
197 /* XXX CUI need to tell UI what happened, but not like this */
198 update_show_plugins();
200 g_timeout_add(5000, unload_timeout, handle);
203 /* Do unload/load cycle of plugin. */
204 struct gaim_plugin *reload_plugin(struct gaim_plugin *p)
206 char file[1024];
207 GModule *handle = p->handle;
209 strncpy(file, g_module_name(handle), sizeof(file));
210 file[sizeof(file) - 1] = '\0';
212 debug_printf("Reloading %s\n", file);
214 /* Unload */
215 unload_plugin(p);
217 /* Load */
218 return load_plugin(file);
221 /* Remove all callbacks associated with plugin handle */
222 static void plugin_remove_callbacks(GModule *handle)
224 GList *c = callbacks;
225 struct gaim_callback *g;
227 debug_printf("%d callbacks to search\n", g_list_length(callbacks));
229 while (c) {
230 g = (struct gaim_callback *)c->data;
231 if (g->handle == handle) {
232 c = g_list_next(c);
233 callbacks = g_list_remove(callbacks, (gpointer)g);
234 debug_printf("Removing callback, %d remain\n", g_list_length(callbacks));
235 } else
236 c = g_list_next(c);
240 void gaim_signal_connect(GModule *handle, enum gaim_event which, void *func, void *data)
242 struct gaim_callback *call = g_new0(struct gaim_callback, 1);
243 call->handle = handle;
244 call->event = which;
245 call->function = func;
246 call->data = data;
248 callbacks = g_list_append(callbacks, call);
249 debug_printf("Adding callback %d\n", g_list_length(callbacks));
252 void gaim_signal_disconnect(GModule *handle, enum gaim_event which, void *func)
254 GList *c = callbacks;
255 struct gaim_callback *g = NULL;
257 while (c) {
258 g = (struct gaim_callback *)c->data;
259 if (handle == g->handle && func == g->function) {
260 callbacks = g_list_remove(callbacks, c->data);
261 g_free(g);
262 c = callbacks;
263 if (c == NULL)
264 break;
266 c = g_list_next(c);
270 #endif /* GAIM_PLUGINS */
272 char *event_name(enum gaim_event event)
274 static char buf[128];
275 switch (event) {
276 case event_signon:
277 sprintf(buf, "event_signon");
278 break;
279 case event_signoff:
280 sprintf(buf, "event_signoff");
281 break;
282 case event_away:
283 sprintf(buf, "event_away");
284 break;
285 case event_back:
286 sprintf(buf, "event_back");
287 break;
288 case event_im_recv:
289 sprintf(buf, "event_im_recv");
290 break;
291 case event_im_send:
292 sprintf(buf, "event_im_send");
293 break;
294 case event_buddy_signon:
295 sprintf(buf, "event_buddy_signon");
296 break;
297 case event_buddy_signoff:
298 sprintf(buf, "event_buddy_signoff");
299 break;
300 case event_buddy_away:
301 sprintf(buf, "event_buddy_away");
302 break;
303 case event_buddy_back:
304 sprintf(buf, "event_buddy_back");
305 break;
306 case event_buddy_idle:
307 sprintf(buf, "event_buddy_idle");
308 break;
309 case event_buddy_unidle:
310 sprintf(buf, "event_buddy_unidle");
311 break;
312 case event_blist_update:
313 sprintf(buf, "event_blist_update");
314 break;
315 case event_chat_invited:
316 sprintf(buf, "event_chat_invited");
317 break;
318 case event_chat_join:
319 sprintf(buf, "event_chat_join");
320 break;
321 case event_chat_leave:
322 sprintf(buf, "event_chat_leave");
323 break;
324 case event_chat_buddy_join:
325 sprintf(buf, "event_chat_buddy_join");
326 break;
327 case event_chat_buddy_leave:
328 sprintf(buf, "event_chat_buddy_leave");
329 break;
330 case event_chat_recv:
331 sprintf(buf, "event_chat_recv");
332 break;
333 case event_chat_send:
334 sprintf(buf, "event_chat_send");
335 break;
336 case event_warned:
337 sprintf(buf, "event_warned");
338 break;
339 case event_error:
340 sprintf(buf, "event_error");
341 break;
342 case event_quit:
343 sprintf(buf, "event_quit");
344 break;
345 case event_new_conversation:
346 sprintf(buf, "event_new_conversation");
347 break;
348 case event_set_info:
349 sprintf(buf, "event_set_info");
350 break;
351 case event_draw_menu:
352 sprintf(buf, "event_draw_menu");
353 break;
354 case event_im_displayed_sent:
355 sprintf(buf, "event_im_displayed_sent");
356 break;
357 case event_im_displayed_rcvd:
358 sprintf(buf, "event_im_displayed_rcvd");
359 break;
360 case event_chat_send_invite:
361 sprintf(buf, "event_chat_send_invite");
362 break;
363 case event_got_typing:
364 sprintf(buf, "event_got_typing");
365 break;
366 default:
367 sprintf(buf, "event_unknown");
368 break;
370 return buf;
373 static void debug_event(enum gaim_event event, void *arg1, void *arg2, void *arg3, void *arg4)
375 if (!opt_debug && !(misc_options & OPT_MISC_DEBUG))
376 return;
378 switch (event) {
379 case event_quit:
380 debug_printf("%s\n", event_name(event));
381 break;
382 case event_signon:
383 case event_signoff:
384 debug_printf("%s: %s\n", event_name(event),
385 ((struct gaim_connection *)arg1)->username);
386 break;
387 case event_new_conversation:
388 debug_printf("event_new_conversation: %s\n", (char *)arg1);
389 break;
390 case event_error:
391 debug_printf("event_error: %d\n", (int)arg1);
392 break;
393 case event_buddy_signon:
394 case event_buddy_signoff:
395 case event_buddy_away:
396 case event_buddy_back:
397 case event_buddy_idle:
398 case event_buddy_unidle:
399 case event_set_info:
400 case event_got_typing:
401 debug_printf("%s: %s %s\n", event_name(event),
402 ((struct gaim_connection *)arg1)->username, (char *)arg2);
403 break;
404 case event_chat_leave:
405 debug_printf("event_chat_leave: %s %d\n",
406 ((struct gaim_connection *)arg1)->username, (int)arg2);
407 break;
408 case event_im_send:
409 case event_im_displayed_sent:
410 debug_printf("%s: %s %s %s\n", event_name(event),
411 ((struct gaim_connection *)arg1)->username,
412 (char *)arg2, *(char **)arg3 ? *(char **)arg3 : "");
413 break;
414 case event_chat_join:
415 case event_chat_buddy_join:
416 case event_chat_buddy_leave:
417 debug_printf("%s: %s %d %s\n", event_name(event),
418 ((struct gaim_connection *)arg1)->username,
419 (int)arg2, (char *)arg3);
420 break;
421 case event_chat_send:
422 debug_printf("%s: %s %d %s\n", event_name(event),
423 ((struct gaim_connection *)arg1)->username,
424 (int)arg2, *(char **)arg3 ? *(char **)arg3 : "");
425 break;
426 case event_away:
427 debug_printf("%s: %s %s %s\n", event_name(event),
428 ((struct gaim_connection *)arg1)->username,
429 (char *)arg2, (char *)arg3 ? (char *)arg3 : "");
430 break;
431 case event_warned:
432 debug_printf("%s: %s %s %d\n", event_name(event),
433 ((struct gaim_connection *)arg1)->username,
434 (char *)arg2 ? (char *)arg2 : "", (int)arg3);
435 break;
436 case event_im_recv:
437 debug_printf("%s: %s %s %s\n", event_name(event),
438 ((struct gaim_connection *)arg1)->username,
439 *(char **)arg2 ? *(char **)arg2 : "",
440 *(char **)arg3 ? *(char **)arg3 : "");
441 break;
442 case event_im_displayed_rcvd:
443 debug_printf("%s: %s %s %s\n", event_name(event),
444 ((struct gaim_connection *)arg1)->username,
445 (char *)arg2 ? (char *)arg2 : "",
446 (char *)arg3 ? (char *)arg3 : "");
447 break;
448 case event_chat_recv:
449 debug_printf("%s: %s %d %s\n", event_name(event),
450 ((struct gaim_connection *)arg1)->username,
451 (int)arg2,
452 (char *)arg3 ? (char *)arg3 : "",
453 (char *)arg4 ? (char *)arg4 : "");
454 break;
455 case event_chat_send_invite:
456 debug_printf("%s: %s %d %s %s\n", event_name(event),
457 ((struct gaim_connection *)arg1)->username,
458 (int)arg2, (char *)arg3,
459 *(char **)arg4 ? *(char **)arg4 : "");
460 break;
461 case event_chat_invited:
462 debug_printf("%s: %s %s %s %s\n", event_name(event),
463 ((struct gaim_connection *)arg1)->username,
464 (char *)arg2, (char *)arg3,
465 (char *)arg4 ? (char *)arg4 : "");
466 break;
467 default:
468 break;
472 int plugin_event(enum gaim_event event, void *arg1, void *arg2, void *arg3, void *arg4)
474 #ifdef GAIM_PLUGINS
475 GList *c = callbacks;
476 struct gaim_callback *g;
477 #endif
479 debug_event(event, arg1, arg2, arg3, arg4);
481 #ifdef GAIM_PLUGINS
482 while (c) {
483 void (*zero)(void *);
484 void (*one)(void *, void *);
485 void (*two)(void *, void *, void *);
486 void (*three)(void *, void *, void *, void *);
487 void (*four)(void *, void *, void *, void *, void *);
489 g = (struct gaim_callback *)c->data;
490 if (g->event == event && g->function != NULL) {
491 switch (event) {
493 /* no args */
494 case event_blist_update:
495 case event_quit:
496 zero = g->function;
497 zero(g->data);
498 break;
500 /* one arg */
501 case event_signon:
502 case event_signoff:
503 case event_new_conversation:
504 case event_error:
505 one = g->function;
506 one(arg1, g->data);
507 break;
509 /* two args */
510 case event_buddy_signon:
511 case event_buddy_signoff:
512 case event_buddy_away:
513 case event_buddy_back:
514 case event_buddy_idle:
515 case event_buddy_unidle:
516 case event_chat_leave:
517 case event_set_info:
518 case event_draw_menu:
519 case event_got_typing:
520 two = g->function;
521 two(arg1, arg2, g->data);
522 break;
524 /* three args */
525 case event_im_send:
526 case event_im_displayed_sent:
527 case event_chat_join:
528 case event_chat_buddy_join:
529 case event_chat_buddy_leave:
530 case event_chat_send:
531 case event_away:
532 case event_back:
533 case event_warned:
534 three = g->function;
535 three(arg1, arg2, arg3, g->data);
536 break;
538 /* four args */
539 case event_im_recv:
540 case event_chat_recv:
541 case event_im_displayed_rcvd:
542 case event_chat_send_invite:
543 case event_chat_invited:
544 four = g->function;
545 four(arg1, arg2, arg3, arg4, g->data);
546 break;
548 default:
549 debug_printf("unknown event %d\n", event);
550 break;
553 c = c->next;
555 #endif /* GAIM_PLUGINS */
556 #ifdef USE_PERL
557 return perl_event(event, arg1, arg2, arg3, arg4);
558 #else
559 return 0;
560 #endif
563 /* Calls the gaim_plugin_remove function in any loaded plugin that has one */
564 #ifdef GAIM_PLUGINS
565 void remove_all_plugins()
567 GList *c = plugins;
568 struct gaim_plugin *p;
569 void (*gaim_plugin_remove)();
571 while (c) {
572 p = (struct gaim_plugin *)c->data;
573 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
574 gaim_plugin_remove();
575 g_free(p);
576 c = c->next;
579 #endif