# HG changeset patch # User Eric Warmenhoven # Date 973117836 0 # Node ID ece2d1543b20fa6a8b46307da453896965cee0f4 # Parent 4593605da0e2220987a940b599137700ce6d68fd [gaim-migrate @ 1057] Plugins now use GModule. Protocol plugins can be dynamically updated. committer: Tailor Script diff -r 4593605da0e2 -r ece2d1543b20 ChangeLog --- a/ChangeLog Wed Nov 01 11:34:56 2000 +0000 +++ b/ChangeLog Wed Nov 01 22:30:36 2000 +0000 @@ -9,6 +9,7 @@ * X-Idle support added (thanks bmiller and bryner) * small change in the way away messages are displayed (Thanks Ryan C. Gordon) + * plugin system uses GModule now (improves portability, adds features) version 0.10.3 (10/09/2000): * Segfault when viewing user info fixed diff -r 4593605da0e2 -r ece2d1543b20 FIXME --- a/FIXME Wed Nov 01 11:34:56 2000 +0000 +++ b/FIXME Wed Nov 01 22:30:36 2000 +0000 @@ -1,33 +1,10 @@ GAIM: Items to be fixed ------------------------ -This is just for the buddy list window now. Everything else is nearing completion. - -1. Enforce order. E.g. a buddy list looks like: - |-Buddies - | |--EWarmenhoven - | `--RobFlynn - `-Friends - `--Zilding - - Need to enforce that Buddies comes before Friends, and EWarmenhoven comes before RobFlynn. - See appropriate FIXME comments in buddy.c. DONE - -2. Need to make it so that when the buddy list is edited the main window properly reflects that. - -3. Need to modify the right-click menu for buddies, to include status for the buddy from each - connection that has it registered, and also to get available actions from each connection - that has it registered. DONE - -4. Need to get Aliases working again. DONE - I think - -5. Need to set number of buddies in group (as an option) - -6. Need to not hide empty groups (as an option) - -7. Need to do Buddy Pounces on a per-connection basis - -8. Need to report logins/outs to convo window - -9. Need to get the permit/deny stuff put back - -10. Need to have per-connection protocol options (e.g. which server to connect to for IRC) +Need to make it so that when the buddy list is edited the main window properly reflects that. +Need to set number of buddies in group (as an option) +Need to not hide empty groups (as an option) +Need to do Buddy Pounces on a per-connection basis +Need to report logins/outs to convo window +Need to get the permit/deny stuff put back +Need to have per-connection protocol options (e.g. which server to connect to for IRC) +Need to get the ticker working again. diff -r 4593605da0e2 -r ece2d1543b20 configure.in --- a/configure.in Wed Nov 01 11:34:56 2000 +0000 +++ b/configure.in Wed Nov 01 22:30:36 2000 +0000 @@ -59,7 +59,7 @@ fi CFLAGS="$CFLAGS -I../libfaim -I../libfaim/faim" -LDADD="$LDADD -L../libfaim -lfaim -pthread" +LDADD="$LDADD -L../libfaim -lfaim" if test "x$enable_gnome" = "xyes" ; then if test "x$enable_panel" = "xyes" ; then @@ -133,15 +133,8 @@ CFLAGS="$CFLAGS $GTK_CFLAGS" -dnl Even more X-Chat code if test "x$enable_plugins" = xyes ; then - AC_CHECK_FUNCS(dlopen, have_dl=yes) - if test "$have_dl" = yes; then - AC_CHECK_FUNCS(dlerror) - AC_DEFINE(GAIM_PLUGINS) - else - enable_plugins=no - fi + AC_DEFINE(GAIM_PLUGINS) fi dnl This was taken straight from X-Chat. diff -r 4593605da0e2 -r ece2d1543b20 plugins/ChangeLog --- a/plugins/ChangeLog Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/ChangeLog Wed Nov 01 22:30:36 2000 +0000 @@ -2,18 +2,25 @@ Gaim is now multi-connection based. This represents a significant change. Most of the code was modified, though most of the modifications were small (referencing an int as part of a struct as opposed to as a - global int). Such changes will require most plugins to be modified to - match the new function declarations and such. + global int). Plugins need to be modified to match the new function + declarations and such. - The plugin system itself was only slightly modified. However, the - arguments passed to signal handlers have been modified in some cases. - Look at the updates SIGNALS file to see what the new arguments passed - to your handlers are. In some cases the only change necessary will be - to modify the function declaration; in many cases the changes will be - much more substantial. The only thing really to say here is that there - is no more event_blist_update. This event may make a comeback, but - that seems doubtful at this point. The good news is that you shouldn't - need it anymore anyway. + Gaim now uses GModule from the GLib library for plugins. This brings + a few changes. gaim_plugin_init is now passed a GModule *, which it + should use for all of its callbacks. gaim_plugin_init now returns + char * instead of int instead of void. If gaim_plugin_init returns + NULL then gaim assumes everything was OK and proceeds. Otherwise, it + displays the error message and unloads your plugin. There is no more + gaim_plugin_error (at least, that gaim itself will use. You may wish + to simply return gaim_plugin_error() in gaim_plugin_init). + + Because gaim now uses GModule, plugins are opened with RTLD_GLOBAL. I + had previously wanted to avoid this, but there are simply too many + benefits gained from using GModule to reject it for this reason. This + means that plugins can now call each other's functions. Beware, this + has good and bad implications. If you call a function, it will look + first in your plugin, and then in gaim's global symbol table, including + other plugins. The new system allows for protocol plugins. New protocols (including Yahoo, MSN, IRC, ICQ, etc) can be loaded dynamically. However, most diff -r 4593605da0e2 -r ece2d1543b20 plugins/Makefile.am --- a/plugins/Makefile.am Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/Makefile.am Wed Nov 01 22:30:36 2000 +0000 @@ -1,13 +1,14 @@ -LDFLAGS += $(LDADD) $(LIBS) -shared +LDFLAGS += $(LDADD) $(LIBS) -ggdb -shared +CFLAGS += -DHAVE_CONFIG_H SUFFIXES = .c .so .c.so: - $(CC) $(CFLAGS) -I../src -DVERSION=\"$(VERSION)\" -fPIC -o $@ $< $(LDFLAGS) $(PLUGIN_LIBS) + $(CC) $(CFLAGS) -I../src -DVERSION=\"$(VERSION)\" -o $@ $< $(LDFLAGS) $(PLUGIN_LIBS) if PLUGINS plugin_DATA = autorecon.so iconaway.so notify.so spellchk.so lagmeter.so plugindir = $(libdir)/gaim -clean distclean clean-recursive distclean-recursive: +clean distclean: $(RM) $(plugin_DATA) endif diff -r 4593605da0e2 -r ece2d1543b20 plugins/autorecon.c --- a/plugins/autorecon.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/autorecon.c Wed Nov 01 22:30:36 2000 +0000 @@ -40,7 +40,7 @@ away_state = 0; } -void gaim_plugin_init(void *handle) { +char *gaim_plugin_init(GModule *handle) { if (imaway) { away_state = 1; last_away = awaymessage; @@ -50,4 +50,6 @@ gaim_signal_connect(handle, event_away, away_toggle, (void *)1); gaim_signal_connect(handle, event_back, away_toggle, (void *)0); gaim_signal_connect(handle, event_signoff, reconnect, NULL); + + return NULL; } diff -r 4593605da0e2 -r ece2d1543b20 plugins/error.c --- a/plugins/error.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/error.c Wed Nov 01 22:30:36 2000 +0000 @@ -4,7 +4,9 @@ #include #include -int gaim_plugin_init(void *handle) { +char *gaim_plugin_error(int); + +char *gaim_plugin_init(GModule *handle) { int error; /* so here, we load any callbacks, do the normal stuff */ @@ -13,7 +15,7 @@ error = rand() % 3; error -= 2; /* there's a 1 in 3 chance there *won't* be an error :) */ - return error; + return gaim_plugin_error(error); } void gaim_plugin_remove() { @@ -27,13 +29,12 @@ * and do any other clean-up stuff we need to do. */ switch (error) { case -1: - do_error_dialog("I'm calling the error myself", "MY BAD"); - return NULL; + return "MY BAD"; case -2: return "Internal plugin error: exiting."; + default: + return NULL; } - /* we should never get here */ - return NULL; } char *name() { diff -r 4593605da0e2 -r ece2d1543b20 plugins/events.c --- a/plugins/events.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/events.c Wed Nov 01 22:30:36 2000 +0000 @@ -11,117 +11,112 @@ #define GAIM_PLUGINS #include "gaim.h" -void evt_signon(void *data) +static void evt_signon(struct gaim_connection *gc, void *data) { printf("event_signon\n"); } -void evt_signoff(void *data) +static void evt_signoff(struct gaim_connection *gc, void *data) { printf("event_signoff\n"); } -void evt_away(void *data) +static void evt_away(void *data) { printf("event_away\n"); } -void evt_back(void *data) +static void evt_back(void *data) { printf("event_back\n"); } -void evt_im_recv(char **who, char **what, void *data) +static void evt_im_recv(struct gaim_connection *gc, char **who, char **what, void *data) { printf("event_im_recv: %s %s\n", *who, *what); } -void evt_im_send(char *who, char **what, void *data) +static void evt_im_send(struct gaim_connection *gc, char *who, char **what, void *data) { printf("event_im_send: %s %s\n", who, *what); } -void evt_buddy_signon(char *who, void *data) +static void evt_buddy_signon(struct gaim_connection *gc, char *who, void *data) { printf("event_buddy_signon: %s\n", who); } -void evt_buddy_signoff(char *who, void *data) +static void evt_buddy_signoff(struct gaim_connection *gc, char *who, void *data) { printf("event_buddy_signoff: %s\n", who); } -void evt_buddy_away(char *who, void *data) +static void evt_buddy_away(struct gaim_connection *gc, char *who, void *data) { printf("event_buddy_away: %s\n", who); } -void evt_buddy_back(char *who, void *data) +static void evt_buddy_back(struct gaim_connection *gc, char *who, void *data) { printf("event_buddy_back: %s\n", who); } -void evt_blist_update(void *data) -{ - printf("event_blist_update\n"); -} - -void evt_chat_invited(char *who, char *room, char *message, void *data) +static void evt_chat_invited(struct gaim_connection *gc, char *who, char *room, char *message, void *data) { printf("event_chat_invited: %s %s %s\n", who, room, message); } -void evt_chat_join(char *room, void *data) +static void evt_chat_join(struct gaim_connection *gc, char *room, void *data) { printf("event_chat_join: %s\n", room); } -void evt_chat_leave(char *room, void *data) +static void evt_chat_leave(struct gaim_connection *gc, char *room, void *data) { printf("event_chat_leave: %s\n", room); } -void evt_chat_buddy_join(char *room, char *who, void *data) +static void evt_chat_buddy_join(struct gaim_connection *gc, char *room, char *who, void *data) { printf("event_chat_buddy_join: %s %s\n", room, who); } -void evt_chat_buddy_leave(char *room, char *who, void *data) +static void evt_chat_buddy_leave(struct gaim_connection *gc, char *room, char *who, void *data) { printf("event_chat_buddy_leave: %s %s\n", room, who); } -void evt_chat_recv(char *room, char *who, char *text, void *data) +static void evt_chat_recv(struct gaim_connection *gc, char *room, char *who, char *text, void *data) { printf("event_chat_recv: %s %s %s\n", room, who, text); } -void evt_chat_send(char *room, char **what, void *data) +static void evt_chat_send(struct gaim_connection *gc, char *room, char **what, void *data) { printf("event_chat_send: %s %s\n", room, *what); } -void evt_warned(char *who, int level, void *data) +static void evt_warned(struct gaim_connection *gc, char *who, int level, void *data) { printf("event_warned: %s %d\n", who, level); } -void evt_error(int error, void *data) +static void evt_error(int error, void *data) { printf("event_error: %d\n", error); } -void evt_quit(void *data) +static void evt_quit(void *data) { printf("event_quit\n"); } -void evt_new_conversation(char *who, void *data) +static void evt_new_conversation(char *who, void *data) { printf("event_new_conversation: %s\n", who); } -int gaim_plugin_init(void *h) +char *gaim_plugin_init(GModule *h) { gaim_signal_connect(h, event_signon, evt_signon, NULL); gaim_signal_connect(h, event_signoff, evt_signoff, NULL); @@ -133,7 +128,6 @@ gaim_signal_connect(h, event_buddy_signoff, evt_buddy_signoff, NULL); gaim_signal_connect(h, event_buddy_away, evt_buddy_away, NULL); gaim_signal_connect(h, event_buddy_back, evt_buddy_back, NULL); - gaim_signal_connect(h, event_blist_update, evt_blist_update, NULL); gaim_signal_connect(h, event_chat_invited, evt_chat_invited, NULL); gaim_signal_connect(h, event_chat_join, evt_chat_join, NULL); gaim_signal_connect(h, event_chat_leave, evt_chat_leave, NULL); @@ -145,7 +139,7 @@ gaim_signal_connect(h, event_error, evt_error, NULL); gaim_signal_connect(h, event_quit, evt_quit, NULL); gaim_signal_connect(h, event_new_conversation, evt_new_conversation, NULL); - return 0; + return NULL; } char *name() diff -r 4593605da0e2 -r ece2d1543b20 plugins/filectl.c --- a/plugins/filectl.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/filectl.c Wed Nov 01 22:30:36 2000 +0000 @@ -16,7 +16,6 @@ static void init_file(); static void check_file(); -extern void dologin(GtkWidget *, GtkWidget *); extern void do_quit(); /* parse char * as if were word array */ @@ -45,7 +44,11 @@ dologin(NULL, NULL); } } else if (!strncasecmp(command, "signoff", 7)) { - signoff(); + struct gaim_connection *gc = NULL; + arg1 = getarg(buffer, 1, 1); + if (arg1) gc = find_gaim_conn_by_name(arg1); + if (gc) signoff(gc); + else signoff_all(NULL, NULL); } else if (!strncasecmp(command, "send", 4)) { struct conversation *c; arg1 = getarg(buffer, 1, 0); @@ -53,7 +56,7 @@ c = find_conversation(arg1); if (!c) c = new_conversation(arg1); write_to_conv(c, arg2, WFLAG_SEND, NULL); - serv_send_im(arg1, arg2, 0); + serv_send_im(c->gc, arg1, arg2, 0); free(arg1); free(arg2); } else if (!strncasecmp(command, "away", 4)) { @@ -78,7 +81,7 @@ mtime = finfo.st_mtime; } -void gaim_plugin_init(void *h) { +char *gaim_plugin_init(GModule *h) { handle = h; init_file(); check = gtk_timeout_add(5000, (GtkFunction)check_file, NULL); diff -r 4593605da0e2 -r ece2d1543b20 plugins/gaiminc.c --- a/plugins/gaiminc.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/gaiminc.c Wed Nov 01 22:30:36 2000 +0000 @@ -12,7 +12,7 @@ show_about(NULL, NULL); } -void reverse(char **who, char **message, void *m) { +void reverse(struct gaim_connection *gc, char **who, char **message, void *m) { /* this will drive you insane. whenever you receive a message, * the text of the message (HTML and all) will be reversed. */ int i, l; @@ -24,7 +24,7 @@ l = strlen(*message); - if (!strcmp(*who, current_user->username)) + if (!strcmp(*who, gc->username)) return; for (i = 0; i < l/2; i++) { @@ -34,13 +34,13 @@ } } -void bud(char *who, void *m) { +void bud(struct gaim_connection *gc, char *who, void *m) { /* whenever someone comes online, it sends them a message. if i * cared more, i'd make it so it popped up on your screen too */ - serv_send_im(who, "Hello!", 0); + serv_send_im(gc, who, "Hello!", 0); } -void gaim_plugin_init(void *handle) { +char *gaim_plugin_init(GModule *handle) { /* this is for doing something fun when we sign on */ gaim_signal_connect(handle, event_signon, echo_hi, NULL); @@ -49,6 +49,8 @@ /* this is for doing something fun when a buddy comes online */ gaim_signal_connect(handle, event_buddy_signon, bud, NULL); + + return NULL; } char *name() { diff -r 4593605da0e2 -r ece2d1543b20 plugins/gtik.c --- a/plugins/gtik.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/gtik.c Wed Nov 01 22:30:36 2000 +0000 @@ -825,7 +825,7 @@ /*-----------------------------------------------------------------*/ - int gaim_plugin_init(void *handle) { /* used to be main() */ + char *gaim_plugin_init(GModule *handle) { /* used to be main() */ GtkWidget *label; GtkWidget * vbox; @@ -877,7 +877,7 @@ (gpointer)updateOutput,"NULL"); - return 0; + return NULL; } diff -r 4593605da0e2 -r ece2d1543b20 plugins/iconaway.c --- a/plugins/iconaway.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/iconaway.c Wed Nov 01 22:30:36 2000 +0000 @@ -26,10 +26,12 @@ #endif } -void gaim_plugin_init(void *h) { +char *gaim_plugin_init(GModule *h) { handle = h; gaim_signal_connect(handle, event_away, iconify_windows, NULL); + + return NULL; } char *name() { diff -r 4593605da0e2 -r ece2d1543b20 plugins/irc.c --- a/plugins/irc.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/irc.c Wed Nov 01 22:30:36 2000 +0000 @@ -892,9 +892,9 @@ irc_request_buddy_update(gc); } -struct prpl *irc_init() { - struct prpl *ret = g_new0(struct prpl, 1); +static struct prpl *my_protocol = NULL; +void irc_init(struct prpl *ret) { ret->protocol = PROTO_IRC; ret->name = irc_name; ret->login = irc_login; @@ -922,11 +922,17 @@ ret->chat_whisper = NULL; ret->chat_send = irc_chat_send; ret->keepalive = NULL; - - return ret; + + my_protocol = ret; } -int gaim_plugin_init(void *handle) { - load_protocl(irc_init); - return 0; +char *gaim_plugin_init(GModule *handle) { + load_protocol(irc_init); + return NULL; } + +void gaim_plugin_remove() { + struct prpl *p = find_prpl(PROTO_IRC); + if (p == my_protocol) + unload_protocol(p); +} diff -r 4593605da0e2 -r ece2d1543b20 plugins/lagmeter.c --- a/plugins/lagmeter.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/lagmeter.c Wed Nov 01 22:30:36 2000 +0000 @@ -113,7 +113,7 @@ check_timeout = gtk_timeout_add(1000 * delay, (GtkFunction)send_lag, gc); } -void gaim_plugin_init(void *h) { +char *gaim_plugin_init(GModule *h) { handle = h; confdlg = NULL; diff -r 4593605da0e2 -r ece2d1543b20 plugins/notify.c --- a/plugins/notify.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/notify.c Wed Nov 01 22:30:36 2000 +0000 @@ -10,6 +10,13 @@ char buf[256]; struct conversation *cnv = find_conversation(*who); GtkWindow *win; + char *me = g_strdup(normalize(gc->username)); + + if (!strcmp(me, normalize(*who))) { + g_free(me); + return; + } + g_free(me); if (cnv == NULL) cnv = new_conversation(*who); @@ -35,7 +42,7 @@ } } -void gaim_plugin_init(void *hndl) { +char *gaim_plugin_init(GModule *hndl) { handle = hndl; gaim_signal_connect(handle, event_im_recv, received_im, NULL); diff -r 4593605da0e2 -r ece2d1543b20 plugins/oscar.c --- a/plugins/oscar.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/oscar.c Wed Nov 01 22:30:36 2000 +0000 @@ -1372,6 +1372,8 @@ gtk_widget_show(button); } +static struct prpl *my_protocol = NULL; + void oscar_init(struct prpl *ret) { ret->protocol = PROTO_OSCAR; ret->name = oscar_name; @@ -1405,6 +1407,8 @@ ret->chat_whisper = oscar_chat_whisper; ret->chat_send = oscar_chat_send; ret->keepalive = oscar_keepalive; + + my_protocol = ret; } char *name() { @@ -1415,7 +1419,13 @@ return "Allows gaim to use the Oscar protocol"; } -int gaim_plugin_init(void *handle) { +char *gaim_plugin_init(GModule *handle) { load_protocol(oscar_init); - return 0; + return NULL; } + +void gaim_plugin_remove() { + struct prpl *p = find_prpl(PROTO_OSCAR); + if (p == my_protocol) + unload_protocol(p); +} diff -r 4593605da0e2 -r ece2d1543b20 plugins/perl.c --- a/plugins/perl.c Wed Nov 01 11:34:56 2000 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * This is a plugin to load perl scripts. If you don't enter - * in a name of a script to load it will unload all perl - * scripts. This is just to test that perl is working in gaim - * before the UI comes in. You can use this to start building - * perl scripts, but don't use this for anything real yet. - * - */ - -#define GAIM_PLUGINS -#include "gaim.h" -#include "pixmaps/add.xpm" -#include "pixmaps/cancel.xpm" - -char *name() { - return "Perl Plug"; -} - -char *description() { - return "Interface for loading perl scripts"; -} - -int gaim_plugin_init(void *h) { -} - -static GtkWidget *config = NULL; -static GtkWidget *entry = NULL; - -static void cfdes(GtkWidget *m, gpointer n) { - if (config) gtk_widget_destroy(config); - config = NULL; -} - -static void do_load(GtkWidget *m, gpointer n) { - char *file = gtk_entry_get_text(GTK_ENTRY(entry)); - if (!file || !strlen(file)) { - perl_end(); - perl_init(); - return; - } - perl_load_file(file); - gtk_widget_destroy(config); -} - -void gaim_plugin_config() { - GtkWidget *frame; - GtkWidget *vbox; - GtkWidget *hbox; - GtkWidget *label; - GtkWidget *ok; - GtkWidget *cancel; - - if (config) { - gtk_widget_show(config); - return; - } - - config = gtk_window_new(GTK_WINDOW_DIALOG); - gtk_window_set_policy(GTK_WINDOW(config), 0, 0, 1); - gtk_window_set_title(GTK_WINDOW(config), "Gaim - Add Perl Script"); - gtk_container_set_border_width(GTK_CONTAINER(config), 5); - gtk_signal_connect(GTK_OBJECT(config), "destroy", GTK_SIGNAL_FUNC(cfdes), 0); - gtk_widget_realize(config); - aol_icon(config->window); - - frame = gtk_frame_new("Load Script"); - gtk_container_add(GTK_CONTAINER(config), frame); - gtk_widget_show(frame); - - vbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(frame), vbox); - gtk_widget_show(vbox); - - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5); - gtk_widget_show(hbox); - - label = gtk_label_new("File Name:"); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); - gtk_widget_show(label); - - entry = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 5); - gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(do_load), 0); - gtk_widget_show(entry); - - hbox = gtk_hbox_new(TRUE, 10); - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5); - gtk_widget_show(hbox); - - ok = picture_button(config, "Load", add_xpm); - gtk_box_pack_start(GTK_BOX(hbox), ok, FALSE, FALSE, 5); - gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(do_load), 0); - - cancel = picture_button(config, "Cancel", cancel_xpm); - gtk_box_pack_start(GTK_BOX(hbox), cancel, FALSE, FALSE, 5); - gtk_signal_connect(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(cfdes), 0); - - gtk_widget_show(config); -} - -void gaim_plugin_remove() { - if (config) gtk_widget_destroy(config); -} diff -r 4593605da0e2 -r ece2d1543b20 plugins/simple.c --- a/plugins/simple.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/simple.c Wed Nov 01 22:30:36 2000 +0000 @@ -3,9 +3,9 @@ #include #include "gaim.h" -static void *handle = NULL; +static GModule *handle = NULL; -void gaim_plugin_init(void *h) { +char *gaim_plugin_init(GModule *h) { printf("plugin loaded.\n"); handle = h; } diff -r 4593605da0e2 -r ece2d1543b20 plugins/spellchk.c --- a/plugins/spellchk.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/spellchk.c Wed Nov 01 22:30:36 2000 +0000 @@ -136,11 +136,12 @@ free(ibuf); } -void gaim_plugin_init(void *handle) { +char *gaim_plugin_init(GModule *handle) { load_conf(); gaim_signal_connect(handle, event_im_send, substitute_words, NULL); gaim_signal_connect(handle, event_chat_send, substitute_words, NULL); + return NULL; } void gaim_plugin_remove() { diff -r 4593605da0e2 -r ece2d1543b20 plugins/toc_commands.c --- a/plugins/toc_commands.c Wed Nov 01 11:34:56 2000 +0000 +++ b/plugins/toc_commands.c Wed Nov 01 22:30:36 2000 +0000 @@ -6,7 +6,8 @@ void enter_callback(GtkWidget *widget, GtkWidget *entry) { gchar *entry_text; entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); - sflap_send(entry_text, strlen(entry_text), TYPE_DATA); + /* this is bad, but you really shouldn't be using this plugin */ + sflap_send(connections->data, entry_text, strlen(entry_text), TYPE_DATA); } void destroy_callback(GtkWidget *widget, void *handle) { @@ -15,7 +16,7 @@ } GtkWidget *window; -void gaim_plugin_init(void *h) { +char *gaim_plugin_init(GModule *h) { GtkWidget *entry; window = gtk_window_new(GTK_WINDOW_DIALOG); @@ -33,6 +34,8 @@ h); gtk_widget_show(window); + + return NULL; } void gaim_plugin_remove() { diff -r 4593605da0e2 -r ece2d1543b20 src/aim.c --- a/src/aim.c Wed Nov 01 11:34:56 2000 +0000 +++ b/src/aim.c Wed Nov 01 22:30:36 2000 +0000 @@ -85,7 +85,6 @@ GList *c; struct gaim_plugin *p; void (*gaim_plugin_remove)(); - char *error; /* first we tell those who have requested it we're quitting */ plugin_event(event_quit, 0, 0, 0, 0); @@ -94,12 +93,10 @@ c = plugins; while (c) { p = (struct gaim_plugin *)c->data; - gaim_plugin_remove = dlsym(p->handle, "gaim_plugin_remove"); - if ((error = (char *)dlerror()) == NULL) + if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove)) (*gaim_plugin_remove)(); /* we don't need to worry about removing callbacks since * there won't be any more chance to call them back :) */ - g_free(p->filename); /* why do i bother? */ g_free(p); c = c->next; } @@ -437,12 +434,12 @@ int main(int argc, char *argv[]) { char opt; - int i; int opt_acct = 0, opt_help = 0, opt_version = 0, opt_user = 0, opt_login = 0, do_login_ret = -1; char *opt_user_arg = NULL, *opt_login_arg = NULL; #ifdef USE_GNOME + int i; poptContext popt_context; struct poptOption popt_options[] = { diff -r 4593605da0e2 -r ece2d1543b20 src/buddy.c --- a/src/buddy.c Wed Nov 01 11:34:56 2000 +0000 +++ b/src/buddy.c Wed Nov 01 22:30:36 2000 +0000 @@ -788,12 +788,10 @@ c = plugins; while (c) { p = (struct gaim_plugin *)c->data; - gaim_plugin_remove = dlsym(p->handle, "gaim_plugin_remove"); - if ((error = (char *)dlerror()) == NULL) + if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove)) (*gaim_plugin_remove)(); /* we don't need to worry about removing callbacks since * there won't be any more chance to call them back :) */ - g_free(p->filename); /* why do i bother? */ g_free(p); c = c->next; } diff -r 4593605da0e2 -r ece2d1543b20 src/gaim.h --- a/src/gaim.h Wed Nov 01 11:34:56 2000 +0000 +++ b/src/gaim.h Wed Nov 01 22:30:36 2000 +0000 @@ -196,15 +196,16 @@ }; #ifdef GAIM_PLUGINS +#include + struct gaim_plugin { + GModule *handle; char *name; - char *filename; char *description; - void *handle; }; struct gaim_callback { - void *handle; + GModule *handle; enum gaim_event event; void *function; void *data; @@ -780,9 +781,9 @@ #ifdef GAIM_PLUGINS extern void show_plugins(GtkWidget *, gpointer); extern void load_plugin (char *); -extern void gaim_signal_connect(void *, enum gaim_event, void *, void *); -extern void gaim_signal_disconnect(void *, enum gaim_event, void *); -extern void gaim_plugin_unload(void *); +extern void gaim_signal_connect(GModule *, enum gaim_event, void *, void *); +extern void gaim_signal_disconnect(GModule *, enum gaim_event, void *); +extern void gaim_plugin_unload(GModule *); #endif extern char *event_name(enum gaim_event); extern void plugin_event(enum gaim_event, void *, void *, void *, void *); diff -r 4593605da0e2 -r ece2d1543b20 src/gaimrc.c --- a/src/gaimrc.c Wed Nov 01 11:34:56 2000 +0000 +++ b/src/gaimrc.c Wed Nov 01 22:30:36 2000 +0000 @@ -388,7 +388,7 @@ p = (struct gaim_plugin *)pl->data; - path = escape_text2(p->filename); + path = escape_text2(g_module_name(p->handle)); fprintf(f, "\tplugin { %s }\n", path); diff -r 4593605da0e2 -r ece2d1543b20 src/plugins.c --- a/src/plugins.c Wed Nov 01 11:34:56 2000 +0000 +++ b/src/plugins.c Wed Nov 01 22:30:36 2000 +0000 @@ -70,14 +70,15 @@ void show_plugins (GtkWidget *, gpointer); void load_plugin (char *); - void gaim_signal_connect (void *, enum gaim_event, void *, void *); - void gaim_signal_disconnect(void *, enum gaim_event, void *); - void gaim_plugin_unload (void *); + void gaim_signal_connect (GModule *, enum gaim_event, void *, void *); + void gaim_signal_disconnect(GModule *, enum gaim_event, void *); + void gaim_plugin_unload (GModule *); static void destroy_plugins (GtkWidget *, gpointer); static void load_file (GtkWidget *, gpointer); static void load_which_plugin(GtkWidget *, gpointer); static void unload (GtkWidget *, gpointer); +static void unload_immediate (GModule *); static void list_clicked (GtkWidget *, struct gaim_plugin *); static void update_show_plugins(); static void hide_plugins (GtkWidget *, gpointer); @@ -146,59 +147,58 @@ void load_plugin(char *filename) { struct gaim_plugin *plug; GList *c = plugins; - int (*gaim_plugin_init)(); - char *(*gaim_plugin_error)(int); + char *(*gaim_plugin_init)(GModule *); char *(*cfunc)(); char *error; - int retval; - char *plugin_error; + char *retval; + char *tmp_filename; + if (!g_module_supported()) return; if (filename == NULL) return; - /* i shouldn't be checking based solely on path, but i'm lazy */ + while (c) { plug = (struct gaim_plugin *)c->data; - if (!strcmp(filename, plug->filename)) { - debug_printf( _("Already loaded %s, not reloading.\n"), filename); - return; - } - c = g_list_next(c); + if (!strcmp(filename, g_module_name(plug->handle))) { + void (*gaim_plugin_remove)(); + if (g_module_symbol(plug->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove)) + (*gaim_plugin_remove)(); + + unload_immediate(plug->handle); + c = plugins; + } else + c = g_list_next(c); } plug = g_malloc(sizeof *plug); if (!g_path_is_absolute(filename)) - plug->filename = g_strconcat(g_get_home_dir(), G_DIR_SEPARATOR_S, + tmp_filename = g_strconcat(g_get_home_dir(), G_DIR_SEPARATOR_S, PLUGIN_DIR, filename, NULL); else - plug->filename = g_strdup(filename); + tmp_filename = g_strdup(filename); if (last_dir) g_free(last_dir); - last_dir = g_dirname(plug->filename); + last_dir = g_dirname(tmp_filename); - debug_printf("Loading %s\n", filename); - /* do NOT `OR' with RTLD_GLOBAL, otherwise plugins may conflict - * (it's really just a way to work around other people's bad - * programming, by not using RTLD_GLOBAL :P ) */ - plug->handle = dlopen(plug->filename, RTLD_LAZY); + debug_printf("Loading %s\n", tmp_filename); + plug->handle = g_module_open(tmp_filename, 0); + g_free(tmp_filename); if (!plug->handle) { - error = (char *)dlerror(); + error = (char *)g_module_error(); do_error_dialog(error, _("Plugin Error")); - g_free(plug->filename); g_free(plug); return; } - gaim_plugin_init = dlsym(plug->handle, "gaim_plugin_init"); - if ((error = (char *)dlerror()) != NULL) { - do_error_dialog(error, _("Plugin Error")); - dlclose(plug->handle); - g_free(plug->filename); + if (!g_module_symbol(plug->handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) { + do_error_dialog(g_module_error(), _("Plugin Error")); + g_module_close(plug->handle); g_free(plug); return; } retval = (*gaim_plugin_init)(plug->handle); debug_printf("loaded plugin returned %d\n", retval); - if (retval < 0) { + if (retval) { GList *c = callbacks; struct gaim_callback *g; while (c) { @@ -216,28 +216,20 @@ c = g_list_next(c); } } - gaim_plugin_error = dlsym(plug->handle, "gaim_plugin_error"); - if ((error = (char *)dlerror()) == NULL) { - plugin_error = (*gaim_plugin_error)(retval); - if (plugin_error) - do_error_dialog(plugin_error, _("Plugin Error")); - } - dlclose(plug->handle); - g_free(plug->filename); + do_error_dialog(retval, _("Plugin Error")); + g_module_close(plug->handle); g_free(plug); return; } plugins = g_list_append(plugins, plug); - cfunc = dlsym(plug->handle, "name"); - if ((error = (char *)dlerror()) == NULL) + if (g_module_symbol(plug->handle, "name", (gpointer *)&cfunc)) plug->name = (*cfunc)(); else plug->name = NULL; - cfunc = dlsym(plug->handle, "description"); - if ((error = (char *)dlerror()) == NULL) + if (g_module_symbol(plug->handle, "description", (gpointer *)&cfunc)) plug->description = (*cfunc)(); else plug->description = NULL; @@ -332,7 +324,7 @@ while (plugs) { p = (struct gaim_plugin *)plugs->data; - label = gtk_label_new(p->filename); + label = gtk_label_new(g_module_name(p->handle)); list_item = gtk_list_item_new(); gtk_container_add(GTK_CONTAINER(list_item), label); gtk_signal_connect(GTK_OBJECT(list_item), "select", @@ -377,7 +369,7 @@ gtk_list_clear_items(GTK_LIST(pluglist), 0, -1); while (plugs) { p = (struct gaim_plugin *)plugs->data; - label = gtk_label_new(p->filename); + label = gtk_label_new(g_module_name(p->handle)); list_item = gtk_list_item_new(); gtk_container_add(GTK_CONTAINER(list_item), label); gtk_signal_connect(GTK_OBJECT(list_item), "select", @@ -402,7 +394,6 @@ GList *i; struct gaim_plugin *p; void (*gaim_plugin_remove)(); - char *error; i = GTK_LIST(pluglist)->selection; @@ -411,16 +402,13 @@ p = gtk_object_get_user_data(GTK_OBJECT(i->data)); /* Attempt to call the plugin's remove function (if there) */ - gaim_plugin_remove = dlsym(p->handle, "gaim_plugin_remove"); - if ((error = (char *)dlerror()) == NULL) + if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove)) (*gaim_plugin_remove)(); - gaim_plugin_unload(p->handle); + unload_immediate(p->handle); } -/* gaim_plugin_unload serves 2 purposes: 1. so plugins can unload themselves - * 2. to make my life easier */ -void gaim_plugin_unload(void *handle) { +static void unload_for_real(void *handle) { GList *i; struct gaim_plugin *p = NULL; GList *c = callbacks; @@ -438,7 +426,7 @@ if (!p) return; - sprintf(debug_buff, "Unloading %s\n", p->filename); + sprintf(debug_buff, "Unloading %s\n", g_module_name(p->handle)); debug_print(debug_buff); sprintf(debug_buff, "%d callbacks to search\n", g_list_length(callbacks)); @@ -462,14 +450,27 @@ } plugins = g_list_remove(plugins, p); - g_free(p->filename); - /* we don't dlclose(p->handle) in case if we still need code from the plugin later */ g_free(p); if (config) gtk_widget_set_sensitive(config, 0); update_show_plugins(); save_prefs(); } +void unload_immediate(GModule *handle) { + unload_for_real(handle); + g_module_close(handle); +} + +static gint unload_timeout(GModule *handle) { + g_module_close(handle); + return FALSE; +} + +void gaim_plugin_unload(GModule *handle) { + unload_for_real(handle); + gtk_timeout_add(5000, (GtkFunction)unload_timeout, handle); +} + void list_clicked(GtkWidget *w, struct gaim_plugin *p) { gchar *temp; guint text_len; @@ -487,8 +488,7 @@ g_free(temp); /* Find out if this plug-in has a configuration function */ - gaim_plugin_config = dlsym(p->handle, "gaim_plugin_config"); - if ((error = (char *)dlerror()) == NULL) { + if (g_module_symbol(p->handle, "gaim_plugin_config", (gpointer *)&gaim_plugin_config)) { confighandle = gtk_signal_connect(GTK_OBJECT(config), "clicked", GTK_SIGNAL_FUNC(gaim_plugin_config), NULL); gtk_widget_set_sensitive(config, 1); @@ -506,7 +506,7 @@ confighandle = 0; } -void gaim_signal_connect(void *handle, enum gaim_event which, +void gaim_signal_connect(GModule *handle, enum gaim_event which, void *func, void *data) { struct gaim_callback *call = g_new0(struct gaim_callback, 1); call->handle = handle; @@ -519,7 +519,7 @@ debug_print(debug_buff); } -void gaim_signal_disconnect(void *handle, enum gaim_event which, void *func) { +void gaim_signal_disconnect(GModule *handle, enum gaim_event which, void *func) { GList *c = callbacks; struct gaim_callback *g = NULL; @@ -672,6 +672,12 @@ /* struct gaim_connection *, char * */ case event_chat_join: case event_chat_leave: + case event_buddy_signon: + case event_buddy_signoff: + case event_buddy_away: + case event_buddy_back: + case event_buddy_idle: + case event_buddy_unidle: { void (*function)(struct gaim_connection *, char *, void *) = g->function; @@ -680,12 +686,6 @@ break; /* char * */ - case event_buddy_signon: - case event_buddy_signoff: - case event_buddy_away: - case event_buddy_back: - case event_buddy_idle: - case event_buddy_unidle: case event_new_conversation: { void (*function)(char *, void *) = g->function; diff -r 4593605da0e2 -r ece2d1543b20 src/prpl.c --- a/src/prpl.c Wed Nov 01 11:34:56 2000 +0000 +++ b/src/prpl.c Wed Nov 01 22:30:36 2000 +0000 @@ -52,26 +52,29 @@ struct prpl *old; GSList *n = protocols; pi(p); - if (old = find_prpl(p->protocol)) { - GSList *c = connections; - struct gaim_connection *g; - while (c) { - g = (struct gaim_connection *)c->data; - if (g->prpl == old) { - char buf[256]; - g_snprintf(buf, sizeof buf, _("%s was using %s, which got replaced." - " %s is now offline."), g->username, - (*p->name)(), g->username); - do_error_dialog(buf, _("Disconnect")); - signoff(g); - c = connections; - } else - c = c->next; - } - protocols = g_slist_remove(protocols, old); - g_free(old); + if (old = find_prpl(p->protocol)) + unload_protocol(old); + protocols = g_slist_insert_sorted(protocols, p, (GCompareFunc)proto_compare); +} + +void unload_protocol(struct prpl *p) { + GSList *c = connections; + struct gaim_connection *g; + while (c) { + g = (struct gaim_connection *)c->data; + if (g->prpl == p) { + char buf[256]; + g_snprintf(buf, sizeof buf, _("%s was using %s, which got removed." + " %s is now offline."), g->username, + (*p->name)(), g->username); + do_error_dialog(buf, _("Disconnect")); + signoff(g); + c = connections; + } else + c = c->next; } - protocols = g_slist_insert_sorted(protocols, p, (GCompareFunc)proto_compare); + protocols = g_slist_remove(protocols, p); + g_free(p); } void static_proto_init() diff -r 4593605da0e2 -r ece2d1543b20 src/prpl.h --- a/src/prpl.h Wed Nov 01 11:34:56 2000 +0000 +++ b/src/prpl.h Wed Nov 01 22:30:36 2000 +0000 @@ -96,6 +96,7 @@ /* this is what should actually load the protocol. pass it the protocol's initializer */ void load_protocol(proto_init); +void unload_protocol(struct prpl *); struct prpl *find_prpl(int);