comparison src/plugins.c @ 2393:a7ecfd3f7714

[gaim-migrate @ 2406] Arkadiusz Miskiewicz\'s Gadu-Gadu plugin. I was able to figure out enough polish to be able to download Gadu-Gadu, create an account, and test the plugin. Imagine my shock when I got my info and it said I was a woman. Whoops. Also splitting plugins.c so that non-gtk stuff is in modules.c. gaim-core is almost ready for protocol implantaion. Also fixing an IRC bug. Also patiently waiting for anoncvs_gaim's lock in /cvsroot/gaim/gaim/pixmaps committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sat, 29 Sep 2001 23:06:30 +0000
parents 2927c2c26fe6
children 6e637ad18494
comparison
equal deleted inserted replaced
2392:9965c0bbdb7c 2393:a7ecfd3f7714
31 */ 31 */
32 32
33 #ifdef HAVE_CONFIG_H 33 #ifdef HAVE_CONFIG_H
34 #include <config.h> 34 #include <config.h>
35 #endif 35 #endif
36
37 #ifdef GAIM_PLUGINS
36 38
37 #include <string.h> 39 #include <string.h>
38 #include <sys/time.h> 40 #include <sys/time.h>
39 41
40 #include <sys/types.h> 42 #include <sys/types.h>
44 #include <stdio.h> 46 #include <stdio.h>
45 #include <stdlib.h> 47 #include <stdlib.h>
46 #include <gtk/gtk.h> 48 #include <gtk/gtk.h>
47 #include "gaim.h" 49 #include "gaim.h"
48 50
49 #ifdef GAIM_PLUGINS
50
51 #include <dlfcn.h>
52
53 #include "pixmaps/gnome_add.xpm" 51 #include "pixmaps/gnome_add.xpm"
54 #include "pixmaps/gnome_remove.xpm" 52 #include "pixmaps/gnome_remove.xpm"
55 #include "pixmaps/gnome_preferences.xpm" 53 #include "pixmaps/gnome_preferences.xpm"
56 #include "pixmaps/refresh.xpm" 54 #include "pixmaps/refresh.xpm"
57 #include "pixmaps/cancel.xpm" 55 #include "pixmaps/cancel.xpm"
58 56
59 #define PATHSIZE 1024 /* XXX: stolen from dialogs.c */ 57 #define PATHSIZE 1024 /* XXX: stolen from dialogs.c */
60 58
61 59
62 /* ------------------ Global Variables ----------------------- */
63
64 GList *plugins = NULL;
65 GList *callbacks = NULL;
66
67 /* ------------------ Local Variables ------------------------ */ 60 /* ------------------ Local Variables ------------------------ */
68 61
69 static GtkWidget *plugin_dialog = NULL; 62 static GtkWidget *plugin_dialog = NULL;
70 63
71 static GtkWidget *pluglist = NULL; 64 static GtkWidget *pluglist = NULL;
82 static char *last_dir = NULL; 75 static char *last_dir = NULL;
83 76
84 /* --------------- Function Declarations --------------------- */ 77 /* --------------- Function Declarations --------------------- */
85 78
86 void show_plugins(GtkWidget *, gpointer); 79 void show_plugins(GtkWidget *, gpointer);
87 void load_plugin(char *);
88
89 void gaim_signal_connect(GModule *, enum gaim_event, void *, void *);
90 void gaim_signal_disconnect(GModule *, enum gaim_event, void *);
91 void gaim_plugin_unload(GModule *);
92 80
93 /* UI button callbacks */ 81 /* UI button callbacks */
82 static void unload_plugin_cb(GtkWidget *, gpointer);
94 static void plugin_reload_cb(GtkWidget *, gpointer); 83 static void plugin_reload_cb(GtkWidget *, gpointer);
95 84
96 static const gchar *plugin_makelistname(GModule *); 85 static const gchar *plugin_makelistname(GModule *);
97 static void plugin_remove_callbacks(GModule *);
98
99 static void plugin_reload(struct gaim_plugin *p);
100 86
101 static void destroy_plugins(GtkWidget *, gpointer); 87 static void destroy_plugins(GtkWidget *, gpointer);
102 static void load_file(GtkWidget *, gpointer); 88 static void load_file(GtkWidget *, gpointer);
103 static void load_which_plugin(GtkWidget *, gpointer); 89 static void load_which_plugin(GtkWidget *, gpointer);
104 static void unload_plugin(GtkWidget *, gpointer);
105 static void unload_immediate(GModule *);
106 static void list_clicked(GtkWidget *, struct gaim_plugin *); 90 static void list_clicked(GtkWidget *, struct gaim_plugin *);
107 static void update_show_plugins(); 91 static void update_show_plugins();
108 static void hide_plugins(GtkWidget *, gpointer); 92 static void hide_plugins(GtkWidget *, gpointer);
109 93
110 /* ------------------ Code Below ---------------------------- */ 94 /* ------------------ Code Below ---------------------------- */
164 load_plugin(file); 148 load_plugin(file);
165 149
166 if (plugin_dialog) 150 if (plugin_dialog)
167 gtk_widget_destroy(plugin_dialog); 151 gtk_widget_destroy(plugin_dialog);
168 plugin_dialog = NULL; 152 plugin_dialog = NULL;
169 }
170
171 void load_plugin(char *filename)
172 {
173 struct gaim_plugin *plug;
174 GList *c = plugins;
175 char *(*gaim_plugin_init)(GModule *);
176 char *(*cfunc)();
177 char *error;
178 char *retval;
179
180 if (!g_module_supported())
181 return;
182 if (filename && !strlen(filename))
183 return;
184
185 while (filename && c) {
186 plug = (struct gaim_plugin *)c->data;
187 if (!strcmp(filename, g_module_name(plug->handle))) {
188 /* just need to reload plugin */
189 plugin_reload(plug);
190 return;
191 } else
192 c = g_list_next(c);
193 }
194 plug = g_malloc(sizeof *plug);
195
196 if (filename) {
197 if (last_dir)
198 g_free(last_dir);
199 last_dir = g_dirname(filename);
200 }
201
202 debug_printf("Loading %s\n", filename);
203 plug->handle = g_module_open(filename, 0);
204 if (!plug->handle) {
205 error = (char *)g_module_error();
206 do_error_dialog(error, _("Plugin Error"));
207 g_free(plug);
208 return;
209 }
210
211 if (!g_module_symbol(plug->handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) {
212 do_error_dialog(g_module_error(), _("Plugin Error"));
213 g_module_close(plug->handle);
214 g_free(plug);
215 return;
216 }
217
218 retval = (*gaim_plugin_init)(plug->handle);
219 debug_printf("loaded plugin returned %s\n", retval ? retval : "NULL");
220 if (retval) {
221 plugin_remove_callbacks(plug->handle);
222 do_error_dialog(retval, _("Plugin Error"));
223 g_module_close(plug->handle);
224 g_free(plug);
225 return;
226 }
227
228 plugins = g_list_append(plugins, plug);
229
230 if (g_module_symbol(plug->handle, "name", (gpointer *)&cfunc)) {
231 plug->name = (*cfunc)();
232 } else {
233 plug->name = NULL;
234 }
235
236 if (g_module_symbol(plug->handle, "description", (gpointer *)&cfunc))
237 plug->description = (*cfunc)();
238 else
239 plug->description = NULL;
240 153
241 update_show_plugins(); 154 update_show_plugins();
242 save_prefs();
243 } 155 }
244 156
245 void show_plugins(GtkWidget *w, gpointer data) 157 void show_plugins(GtkWidget *w, gpointer data)
246 { 158 {
247 /* most of this code was shamelessly stolen from Glade */ 159 /* most of this code was shamelessly stolen from Glade */
356 gtk_signal_connect(GTK_OBJECT(reload), "clicked", GTK_SIGNAL_FUNC(plugin_reload_cb), NULL); 268 gtk_signal_connect(GTK_OBJECT(reload), "clicked", GTK_SIGNAL_FUNC(plugin_reload_cb), NULL);
357 gtk_box_pack_start(GTK_BOX(bothbox), reload, TRUE, TRUE, 0); 269 gtk_box_pack_start(GTK_BOX(bothbox), reload, TRUE, TRUE, 0);
358 gtk_tooltips_set_tip(tooltips, reload, _("Reload the selected plugin"), ""); 270 gtk_tooltips_set_tip(tooltips, reload, _("Reload the selected plugin"), "");
359 271
360 unload = picture_button(plugwindow, _("Unload"), gnome_remove_xpm); 272 unload = picture_button(plugwindow, _("Unload"), gnome_remove_xpm);
361 gtk_signal_connect(GTK_OBJECT(unload), "clicked", GTK_SIGNAL_FUNC(unload_plugin), pluglist); 273 gtk_signal_connect(GTK_OBJECT(unload), "clicked", GTK_SIGNAL_FUNC(unload_plugin_cb), pluglist);
362 gtk_box_pack_start(GTK_BOX(bothbox), unload, TRUE, TRUE, 0); 274 gtk_box_pack_start(GTK_BOX(bothbox), unload, TRUE, TRUE, 0);
363 gtk_tooltips_set_tip(tooltips, unload, _("Unload the selected plugin"), ""); 275 gtk_tooltips_set_tip(tooltips, unload, _("Unload the selected plugin"), "");
364 276
365 close = picture_button(plugwindow, _("Close"), cancel_xpm); 277 close = picture_button(plugwindow, _("Close"), cancel_xpm);
366 gtk_signal_connect(GTK_OBJECT(close), "clicked", GTK_SIGNAL_FUNC(hide_plugins), NULL); 278 gtk_signal_connect(GTK_OBJECT(close), "clicked", GTK_SIGNAL_FUNC(hide_plugins), NULL);
413 gtk_widget_set_sensitive(reload, FALSE); 325 gtk_widget_set_sensitive(reload, FALSE);
414 gtk_widget_set_sensitive(unload, FALSE); 326 gtk_widget_set_sensitive(unload, FALSE);
415 } 327 }
416 } 328 }
417 329
418 static void unload_plugin(GtkWidget *w, gpointer data) 330 static void unload_plugin_cb(GtkWidget *w, gpointer data)
419 { 331 {
420 GList *i; 332 GList *i;
421 struct gaim_plugin *p; 333 struct gaim_plugin *p;
422 void (*gaim_plugin_remove)();
423 334
424 i = GTK_LIST(pluglist)->selection; 335 i = GTK_LIST(pluglist)->selection;
425 336
426 if (i == NULL) 337 if (i == NULL)
427 return; 338 return;
428 339
429 p = gtk_object_get_user_data(GTK_OBJECT(i->data)); 340 p = gtk_object_get_user_data(GTK_OBJECT(i->data));
430 341
431 /* Attempt to call the plugin's remove function (if there) */ 342 unload_plugin(p);
432 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
433 (*gaim_plugin_remove)();
434
435 unload_immediate(p->handle);
436 update_show_plugins(); 343 update_show_plugins();
437 } 344 }
438 345
439 static void unload_for_real(void *handle) 346 static void plugin_reload_cb(GtkWidget *w, gpointer data)
440 { 347 {
441 GList *i; 348 GList *i;
442 struct gaim_plugin *p = NULL; 349 struct gaim_plugin *p;
443
444 i = plugins;
445 while (i) {
446 p = (struct gaim_plugin *)i->data;
447 if (handle == p->handle)
448 break;
449 p = NULL;
450 i = g_list_next(i);
451 }
452
453 if (!p)
454 return;
455
456 debug_printf("Unloading %s\n", g_module_name(p->handle));
457
458 plugin_remove_callbacks(p->handle);
459
460 plugins = g_list_remove(plugins, p);
461 g_free(p);
462 update_show_plugins();
463 save_prefs();
464 }
465
466 static void unload_immediate(GModule *handle)
467 {
468 unload_for_real(handle);
469 g_module_close(handle);
470 }
471
472 static gboolean unload_timeout(gpointer handle)
473 {
474 g_module_close(handle);
475 return FALSE;
476 }
477
478 void gaim_plugin_unload(GModule *handle)
479 {
480 unload_for_real(handle);
481 g_timeout_add(5000, unload_timeout, handle);
482 }
483
484 static void plugin_reload_cb(GtkWidget *w, gpointer data)
485 {
486 GList *i;
487 350
488 i = GTK_LIST(pluglist)->selection; 351 i = GTK_LIST(pluglist)->selection;
489 if (i == NULL) 352 if (i == NULL)
490 return; 353 return;
491 354
492 /* Just pass off plugin to the actual function */ 355 /* Just pass off plugin to the actual function */
493 plugin_reload(gtk_object_get_user_data(GTK_OBJECT(i->data))); 356 p = reload_plugin(gtk_object_get_user_data(GTK_OBJECT(i->data)));
494 } 357
495 358 update_show_plugins();
496 /* Do unload/load cycle of plugin. */
497 static void plugin_reload(struct gaim_plugin *p)
498 {
499 char file[PATHSIZE];
500 void (*gaim_plugin_remove)();
501 GModule *handle = p->handle;
502 struct gaim_plugin *plug;
503 GList *plugs;
504
505 strncpy(file, g_module_name(handle), sizeof(file));
506 file[sizeof(file) - 1] = '\0';
507
508 debug_printf("Reloading %s\n", file);
509
510 /* Unload */
511 if (g_module_symbol(handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
512 (*gaim_plugin_remove)();
513 unload_immediate(handle);
514
515 /* Load */
516 load_plugin(file);
517 359
518 /* Try and reselect the plugin in list */ 360 /* Try and reselect the plugin in list */
519 if (!pluglist) 361 if (!pluglist)
520 return; 362 return;
521 plugs = plugins; 363 gtk_list_select_item(GTK_LIST(pluglist), g_list_index(plugins, p));
522 while (plugs) {
523 plug = plugs->data;
524 if (!strcmp(file, g_module_name(plug->handle))) {
525 gtk_list_select_item(GTK_LIST(pluglist), g_list_index(plugins, plug));
526 return;
527 }
528 plugs = plugs->next;
529 }
530 } 364 }
531 365
532 static void list_clicked(GtkWidget *w, struct gaim_plugin *p) 366 static void list_clicked(GtkWidget *w, struct gaim_plugin *p)
533 { 367 {
534 gchar *temp; 368 gchar *temp;
592 strncmp(filename + strlen(filename) - 3, ".so", 3) == 0) 426 strncmp(filename + strlen(filename) - 3, ".so", 3) == 0)
593 filename[strlen(filename) - 3] = '\0'; 427 filename[strlen(filename) - 3] = '\0';
594 428
595 return filename; 429 return filename;
596 } 430 }
597 431
598 /* Remove all callbacks associated with plugin handle */
599 static void plugin_remove_callbacks(GModule *handle)
600 {
601 GList *c = callbacks;
602 struct gaim_callback *g;
603
604 debug_printf("%d callbacks to search\n", g_list_length(callbacks));
605
606 while (c) {
607 g = (struct gaim_callback *)c->data;
608 if (g->handle == handle) {
609 c = g_list_next(c);
610 callbacks = g_list_remove(callbacks, (gpointer)g);
611 debug_printf("Removing callback, %d remain\n", g_list_length(callbacks));
612 } else
613 c = g_list_next(c);
614 }
615 }
616
617 void gaim_signal_connect(GModule *handle, enum gaim_event which, void *func, void *data)
618 {
619 struct gaim_callback *call = g_new0(struct gaim_callback, 1);
620 call->handle = handle;
621 call->event = which;
622 call->function = func;
623 call->data = data;
624
625 callbacks = g_list_append(callbacks, call);
626 debug_printf("Adding callback %d\n", g_list_length(callbacks));
627 }
628
629 void gaim_signal_disconnect(GModule *handle, enum gaim_event which, void *func)
630 {
631 GList *c = callbacks;
632 struct gaim_callback *g = NULL;
633
634 while (c) {
635 g = (struct gaim_callback *)c->data;
636 if (handle == g->handle && func == g->function) {
637 callbacks = g_list_remove(callbacks, c->data);
638 g_free(g);
639 c = callbacks;
640 if (c == NULL)
641 break;
642 }
643 c = g_list_next(c);
644 }
645 }
646
647 #endif /* GAIM_PLUGINS */
648
649 static char *event_name(enum gaim_event event)
650 {
651 static char buf[128];
652 switch (event) {
653 case event_signon:
654 sprintf(buf, "event_signon");
655 break;
656 case event_signoff:
657 sprintf(buf, "event_signoff");
658 break;
659 case event_away:
660 sprintf(buf, "event_away");
661 break;
662 case event_back:
663 sprintf(buf, "event_back");
664 break;
665 case event_im_recv:
666 sprintf(buf, "event_im_recv");
667 break;
668 case event_im_send:
669 sprintf(buf, "event_im_send");
670 break;
671 case event_buddy_signon:
672 sprintf(buf, "event_buddy_signon");
673 break;
674 case event_buddy_signoff:
675 sprintf(buf, "event_buddy_signoff");
676 break;
677 case event_buddy_away:
678 sprintf(buf, "event_buddy_away");
679 break;
680 case event_buddy_back:
681 sprintf(buf, "event_buddy_back");
682 break;
683 case event_buddy_idle:
684 sprintf(buf, "event_buddy_idle");
685 break;
686 case event_buddy_unidle:
687 sprintf(buf, "event_buddy_unidle");
688 break;
689 case event_blist_update:
690 sprintf(buf, "event_blist_update");
691 break;
692 case event_chat_invited:
693 sprintf(buf, "event_chat_invited");
694 break;
695 case event_chat_join:
696 sprintf(buf, "event_chat_join");
697 break;
698 case event_chat_leave:
699 sprintf(buf, "event_chat_leave");
700 break;
701 case event_chat_buddy_join:
702 sprintf(buf, "event_chat_buddy_join");
703 break;
704 case event_chat_buddy_leave:
705 sprintf(buf, "event_chat_buddy_leave");
706 break;
707 case event_chat_recv:
708 sprintf(buf, "event_chat_recv");
709 break;
710 case event_chat_send:
711 sprintf(buf, "event_chat_send");
712 break;
713 case event_warned:
714 sprintf(buf, "event_warned");
715 break;
716 case event_error:
717 sprintf(buf, "event_error");
718 break;
719 case event_quit:
720 sprintf(buf, "event_quit");
721 break;
722 case event_new_conversation:
723 sprintf(buf, "event_new_conversation");
724 break;
725 case event_set_info:
726 sprintf(buf, "event_set_info");
727 break;
728 case event_draw_menu:
729 sprintf(buf, "event_draw_menu");
730 break;
731 case event_im_displayed_sent:
732 sprintf(buf, "event_im_displayed_sent");
733 break;
734 case event_im_displayed_rcvd:
735 sprintf(buf, "event_im_displayed_rcvd");
736 break;
737 case event_chat_send_invite:
738 sprintf(buf, "event_chat_send_invite");
739 break;
740 default:
741 sprintf(buf, "event_unknown");
742 break;
743 }
744 return buf;
745 }
746
747 int plugin_event(enum gaim_event event, void *arg1, void *arg2, void *arg3, void *arg4)
748 {
749 #ifdef USE_PERL
750 char buf[BUF_LONG];
751 #endif 432 #endif
752 #ifdef GAIM_PLUGINS
753 GList *c = callbacks;
754 struct gaim_callback *g;
755
756 while (c) {
757 void (*zero)(void *);
758 void (*one)(void *, void *);
759 void (*two)(void *, void *, void *);
760 void (*three)(void *, void *, void *, void *);
761 void (*four)(void *, void *, void *, void *, void *);
762
763 g = (struct gaim_callback *)c->data;
764 if (g->event == event && g->function !=NULL) {
765 switch (event) {
766
767 /* no args */
768 case event_blist_update:
769 case event_quit:
770 zero = g->function;
771 (*zero)(g->data);
772 break;
773
774 /* one arg */
775 case event_signon:
776 case event_signoff:
777 case event_new_conversation:
778 case event_error:
779 one = g->function;
780 (*one)(arg1, g->data);
781 break;
782
783 /* two args */
784 case event_buddy_signon:
785 case event_buddy_signoff:
786 case event_buddy_away:
787 case event_buddy_back:
788 case event_buddy_idle:
789 case event_buddy_unidle:
790 case event_chat_leave:
791 case event_set_info:
792 case event_draw_menu:
793 two = g->function;
794 (*two)(arg1, arg2, g->data);
795 break;
796
797 /* three args */
798 case event_im_send:
799 case event_im_displayed_sent:
800 case event_chat_join:
801 case event_chat_buddy_join:
802 case event_chat_buddy_leave:
803 case event_chat_send:
804 case event_away:
805 case event_back:
806 case event_warned:
807 three = g->function;
808 (*three)(arg1, arg2, arg3, g->data);
809 break;
810
811 /* four args */
812 case event_im_recv:
813 case event_chat_recv:
814 case event_im_displayed_rcvd:
815 case event_chat_send_invite:
816 case event_chat_invited:
817 four = g->function;
818 (*four)(arg1, arg2, arg3, arg4, g->data);
819 break;
820
821 default:
822 debug_printf("unknown event %d\n", event);
823 break;
824 }
825 }
826 c = c->next;
827 }
828 #endif /* GAIM_PLUGINS */
829 #ifdef USE_PERL
830 switch (event) {
831 case event_signon:
832 case event_signoff:
833 case event_away:
834 case event_back:
835 g_snprintf(buf, sizeof buf, "%lu", (unsigned long)arg1);
836 break;
837 case event_im_recv:
838 g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
839 *(char **)arg2 ? *(char **)arg2 : "(null)",
840 *(char **)arg3 ? *(char **)arg3 : "(null)");
841 break;
842 case event_im_send:
843 g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
844 (char *)arg2, *(char **)arg3 ? *(char **)arg3 : "(null)");
845 break;
846 case event_buddy_signon:
847 case event_buddy_signoff:
848 case event_set_info:
849 case event_buddy_away:
850 case event_buddy_back:
851 case event_buddy_idle:
852 case event_buddy_unidle:
853 g_snprintf(buf, sizeof buf, "%lu \"%s\"", (unsigned long)arg1, (char *)arg2);
854 break;
855 case event_chat_invited:
856 g_snprintf(buf, sizeof buf, "%lu \"%s\" \"%s\" %s", (unsigned long)arg1,
857 (char *)arg2, (char *)arg3, arg4 ? (char *)arg4 : "");
858 break;
859 case event_chat_join:
860 case event_chat_buddy_join:
861 case event_chat_buddy_leave:
862 g_snprintf(buf, sizeof buf, "%lu %d \"%s\"", (unsigned long)arg1,
863 (int)arg2, (char *)arg3);
864 break;
865 case event_chat_leave:
866 g_snprintf(buf, sizeof buf, "%lu %d", (unsigned long)arg1, (int)arg2);
867 break;
868 case event_chat_recv:
869 g_snprintf(buf, sizeof buf, "%lu %d \"%s\" %s", (unsigned long)arg1,
870 (int)arg2, (char *)arg3, (char *)arg4 ? (char *)arg4 : "(null)");
871 break;
872 case event_chat_send_invite:
873 g_snprintf(buf, sizeof buf, "%lu %d \"%s\" %s", (unsigned long)arg1,
874 (int)arg2, (char *)arg3, *(char **)arg4 ? *(char **)arg4 : "(null)");
875 break;
876 case event_chat_send:
877 g_snprintf(buf, sizeof buf, "%lu %d %s", (unsigned long)arg1, (int)arg2,
878 *(char **)arg3 ? *(char **)arg3 : "(null)");
879 break;
880 case event_warned:
881 g_snprintf(buf, sizeof buf, "%lu \"%s\" %d", (unsigned long)arg1,
882 arg2 ? (char *)arg2 : "", (int)arg3);
883 break;
884 case event_quit:
885 buf[0] = 0;
886 break;
887 case event_new_conversation:
888 g_snprintf(buf, sizeof buf, "\"%s\"", (char *)arg1);
889 break;
890 case event_im_displayed_sent:
891 g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
892 (char *)arg2, *(char **)arg3 ? *(char **)arg3 : "(null)");
893 break;
894 case event_im_displayed_rcvd:
895 g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
896 (char *)arg2, (char *)arg3 ? (char *)arg3 : "(null)");
897 break;
898 default:
899 return 0;
900 }
901 return perl_event(event_name(event), buf);
902 #else
903 return 0;
904 #endif
905 }
906
907 /* Calls the gaim_plugin_remove function in any loaded plugin that has one */
908 #ifdef GAIM_PLUGINS
909 void remove_all_plugins()
910 {
911 GList *c = plugins;
912 struct gaim_plugin *p;
913 void (*gaim_plugin_remove)();
914
915 while (c) {
916 p = (struct gaim_plugin *)c->data;
917 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
918 (*gaim_plugin_remove)();
919 g_free(p);
920 c = c->next;
921 }
922 }
923 #endif