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
23 * Plugin support is currently being maintained by Mike Saraf
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
44 #include <sys/types.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
;
78 char *(*gaim_plugin_init
)(GModule
*);
83 if (!g_module_supported())
85 if (filename
&& !strlen(filename
))
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
);
96 plug
= g_malloc(sizeof *plug
);
100 last_dir
= g_dirname(filename
);
102 debug_printf("Loading %s\n", filename
);
103 plug
->handle
= g_module_open(filename
, 0);
105 error
= (char *)g_module_error();
106 do_error_dialog(error
, _("Plugin Error"));
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
);
118 retval
= gaim_plugin_init(plug
->handle
);
119 debug_printf("loaded plugin returned %s\n", retval
? retval
: "NULL");
121 plugin_remove_callbacks(plug
->handle
);
122 do_error_dialog(retval
, _("Plugin Error"));
123 g_module_close(plug
->handle
);
128 plugins
= g_list_append(plugins
, plug
);
130 if (g_module_symbol(plug
->handle
, "name", (gpointer
*)&cfunc
)) {
131 plug
->name
= cfunc();
136 if (g_module_symbol(plug
->handle
, "description", (gpointer
*)&cfunc
))
137 plug
->description
= cfunc();
139 plug
->description
= NULL
;
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
);
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
);
175 void gaim_plugin_unload(GModule
*handle
)
178 struct gaim_plugin
*p
= NULL
;
179 void (*gaim_plugin_remove
)();
183 if (p
->handle
== handle
)
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
);
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
)
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
);
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
));
230 g
= (struct gaim_callback
*)c
->data
;
231 if (g
->handle
== handle
) {
233 callbacks
= g_list_remove(callbacks
, (gpointer
)g
);
234 debug_printf("Removing callback, %d remain\n", g_list_length(callbacks
));
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
;
245 call
->function
= func
;
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
;
258 g
= (struct gaim_callback
*)c
->data
;
259 if (handle
== g
->handle
&& func
== g
->function
) {
260 callbacks
= g_list_remove(callbacks
, c
->data
);
270 #endif /* GAIM_PLUGINS */
272 char *event_name(enum gaim_event event
)
274 static char buf
[128];
277 sprintf(buf
, "event_signon");
280 sprintf(buf
, "event_signoff");
283 sprintf(buf
, "event_away");
286 sprintf(buf
, "event_back");
289 sprintf(buf
, "event_im_recv");
292 sprintf(buf
, "event_im_send");
294 case event_buddy_signon
:
295 sprintf(buf
, "event_buddy_signon");
297 case event_buddy_signoff
:
298 sprintf(buf
, "event_buddy_signoff");
300 case event_buddy_away
:
301 sprintf(buf
, "event_buddy_away");
303 case event_buddy_back
:
304 sprintf(buf
, "event_buddy_back");
306 case event_buddy_idle
:
307 sprintf(buf
, "event_buddy_idle");
309 case event_buddy_unidle
:
310 sprintf(buf
, "event_buddy_unidle");
312 case event_blist_update
:
313 sprintf(buf
, "event_blist_update");
315 case event_chat_invited
:
316 sprintf(buf
, "event_chat_invited");
318 case event_chat_join
:
319 sprintf(buf
, "event_chat_join");
321 case event_chat_leave
:
322 sprintf(buf
, "event_chat_leave");
324 case event_chat_buddy_join
:
325 sprintf(buf
, "event_chat_buddy_join");
327 case event_chat_buddy_leave
:
328 sprintf(buf
, "event_chat_buddy_leave");
330 case event_chat_recv
:
331 sprintf(buf
, "event_chat_recv");
333 case event_chat_send
:
334 sprintf(buf
, "event_chat_send");
337 sprintf(buf
, "event_warned");
340 sprintf(buf
, "event_error");
343 sprintf(buf
, "event_quit");
345 case event_new_conversation
:
346 sprintf(buf
, "event_new_conversation");
349 sprintf(buf
, "event_set_info");
351 case event_draw_menu
:
352 sprintf(buf
, "event_draw_menu");
354 case event_im_displayed_sent
:
355 sprintf(buf
, "event_im_displayed_sent");
357 case event_im_displayed_rcvd
:
358 sprintf(buf
, "event_im_displayed_rcvd");
360 case event_chat_send_invite
:
361 sprintf(buf
, "event_chat_send_invite");
363 case event_got_typing
:
364 sprintf(buf
, "event_got_typing");
367 sprintf(buf
, "event_unknown");
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
))
380 debug_printf("%s\n", event_name(event
));
384 debug_printf("%s: %s\n", event_name(event
),
385 ((struct gaim_connection
*)arg1
)->username
);
387 case event_new_conversation
:
388 debug_printf("event_new_conversation: %s\n", (char *)arg1
);
391 debug_printf("event_error: %d\n", (int)arg1
);
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
:
400 case event_got_typing
:
401 debug_printf("%s: %s %s\n", event_name(event
),
402 ((struct gaim_connection
*)arg1
)->username
, (char *)arg2
);
404 case event_chat_leave
:
405 debug_printf("event_chat_leave: %s %d\n",
406 ((struct gaim_connection
*)arg1
)->username
, (int)arg2
);
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
: "");
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
);
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
: "");
427 debug_printf("%s: %s %s %s\n", event_name(event
),
428 ((struct gaim_connection
*)arg1
)->username
,
429 (char *)arg2
, (char *)arg3
? (char *)arg3
: "");
432 debug_printf("%s: %s %s %d\n", event_name(event
),
433 ((struct gaim_connection
*)arg1
)->username
,
434 (char *)arg2
? (char *)arg2
: "", (int)arg3
);
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
: "");
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
: "");
448 case event_chat_recv
:
449 debug_printf("%s: %s %d %s\n", event_name(event
),
450 ((struct gaim_connection
*)arg1
)->username
,
452 (char *)arg3
? (char *)arg3
: "",
453 (char *)arg4
? (char *)arg4
: "");
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
: "");
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
: "");
472 int plugin_event(enum gaim_event event
, void *arg1
, void *arg2
, void *arg3
, void *arg4
)
475 GList
*c
= callbacks
;
476 struct gaim_callback
*g
;
479 debug_event(event
, arg1
, arg2
, arg3
, arg4
);
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
) {
494 case event_blist_update
:
503 case event_new_conversation
:
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
:
518 case event_draw_menu
:
519 case event_got_typing
:
521 two(arg1
, arg2
, g
->data
);
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
:
535 three(arg1
, arg2
, arg3
, g
->data
);
540 case event_chat_recv
:
541 case event_im_displayed_rcvd
:
542 case event_chat_send_invite
:
543 case event_chat_invited
:
545 four(arg1
, arg2
, arg3
, arg4
, g
->data
);
549 debug_printf("unknown event %d\n", event
);
555 #endif /* GAIM_PLUGINS */
557 return perl_event(event
, arg1
, arg2
, arg3
, arg4
);
563 /* Calls the gaim_plugin_remove function in any loaded plugin that has one */
565 void remove_all_plugins()
568 struct gaim_plugin
*p
;
569 void (*gaim_plugin_remove
)();
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();