# HG changeset patch # User Eric Warmenhoven # Date 955279105 0 # Node ID 9f6ce50ffb78f120c4bed7689f094aa1ee71a5d4 # Parent 5ca21b68eb2926849f350245bfad1c71b82b083b [gaim-migrate @ 104] Woohoo, the landing of the plugins. Nearly everything necessary is here. The only thing missing is that you can't load a plugin without signing on first (at least, not without some trickery). committer: Tailor Script diff -r 5ca21b68eb29 -r 9f6ce50ffb78 configure.in --- a/configure.in Sun Apr 09 08:25:15 2000 +0000 +++ b/configure.in Sun Apr 09 11:18:25 2000 +0000 @@ -35,7 +35,7 @@ AC_ARG_ENABLE(esd, [ --disable-esd Turn off ESD (default=auto)],enable_esd=no,enable_esd=yes) AC_ARG_ENABLE(oscar, [ --enable-oscar Enable Oscar support (experimental)],enable_oscar=yes,) AC_ARG_ENABLE(nas, [ --enable-nas Enable NAS (Network Audio System) support],enable_nas=yes,) -dnl AC_ARG_ENABLE(plugins, [ --enable-plugins compile with plugin support],enable_plugins=yes,) +AC_ARG_ENABLE(plugins, [ --enable-plugins compile with plugin support],enable_plugins=yes,) GAIM_CFLAGS="$CFLAGS -I../" GAIM_LIBS="$LIBS" diff -r 5ca21b68eb29 -r 9f6ce50ffb78 plugins/CRAZY --- a/plugins/CRAZY Sun Apr 09 08:25:15 2000 +0000 +++ b/plugins/CRAZY Sun Apr 09 11:18:25 2000 +0000 @@ -1,5 +1,4 @@ -Figures out the other person's IP address if they also have the same -plugin loaded. +Figure out a user's IP address if they have the same plugin loaded This would be a really interesting and pretty useful plugin. It could work possibly by sending 'hidden' text in the form of an @@ -36,3 +35,23 @@ gaim. Plus the plugins tend to be small, and quick and easy to compile, so development should be quick. Try to have FUN with these plugins :-). (BTW, dibs on the 'control by file' plugin. :-) .) + +Other useful ideas I came up with later: + +-Auto-reconnect on kick +-Stock/News ticker (I don't want it, but some people do) +-Play games through the same gaim plugin + + This one I think is one of my crazier ideas that I would only come up + with this early in the morning. This plugin would somehow determine if + the other person is using the same plugin. If s/he is, it would allow + the people to play a game against each other, like checkers. It could + be done by watching the messages passed and intercepting ones that + relate to the game/plugin. Conversation could even continue as usual. + What gets really warped is then you could write plugins for that + plugin for various games (checkers, chess, hearts (4 people!)). I have + no desire of trying this one, help yourself. + +There's going to be a few plugins that are going to ship with gaim by default +eventually, probably. This would be a good thing to put in the PATCHES thing +over at sourceforge.net diff -r 5ca21b68eb29 -r 9f6ce50ffb78 plugins/HOWTO --- a/plugins/HOWTO Sun Apr 09 08:25:15 2000 +0000 +++ b/plugins/HOWTO Sun Apr 09 11:18:25 2000 +0000 @@ -3,7 +3,7 @@ First off, before you do anything else, in all of the files for your plugin, put the lines -#define GAIM_PLUGIN +#define GAIM_PLUGINS #include "gaim.h" I mean this. Without this, all kinds of things will not work correctly. If you @@ -14,13 +14,19 @@ Ok, now you're ready to write the plugin. -The only function that is required is gaim_plugin_init(). This gets called as -soon as it gets loaded (sort of - man dlopen for more details). If your -function never returns, it will crash gaim! If your plugin uses up all the -memory in the system, it will crash gaim! Once your plugin gets loaded, it -effectively becomes a part of gaim, and anything that goes wrong will look +The only function that is required is gaim_plugin_init(void *). This gets +called as soon as it gets loaded (sort of - man dlopen for more details). If +your function never returns, it will crash gaim! If your plugin uses up all +the memory in the system, it will crash gaim! Once your plugin gets loaded, +it effectively becomes a part of gaim, and anything that goes wrong will look like it is a problem with gaim itself. I write bugfree code! :) Therefore, it -is your problem, not mine. +is your problem, not mine. (I'm usually nice and willing to help you with your +problems though.) + +The void * that gets passed to gaim_plugin_init is the handle for the plugin. +DO NOT CHANGE THIS POINTER! Bad things will happen. You've been warned. It's +needed for connecting to signals and things. It's a good idea to remember it +somehow. You can basically do anything you want in the plugin. You can make function calls, change public widgets, display new widgets, things like that. But the diff -r 5ca21b68eb29 -r 9f6ce50ffb78 plugins/Makefile --- a/plugins/Makefile Sun Apr 09 08:25:15 2000 +0000 +++ b/plugins/Makefile Sun Apr 09 11:18:25 2000 +0000 @@ -1,11 +1,11 @@ CC = gcc -CFLAGS = -Wall -LDFLAGS = -ggdb +CFLAGS = -Wall `gnome-config --cflags gtk` -I../src +LDFLAGS = -ggdb `gnome-config --libs gtk` -shared all: simple.so gaiminc.so simple.so: simple.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -Wl,-soname,$@ -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$@ -o $@ $< gaiminc.so: gaiminc.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -Wl,-soname,$@ -o $@ $< -I../src `gnome-config --cflags --libs gtk gnome gnomeui` + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$@ -o $@ $< diff -r 5ca21b68eb29 -r 9f6ce50ffb78 plugins/SIGNALS --- a/plugins/SIGNALS Sun Apr 09 08:25:15 2000 +0000 +++ b/plugins/SIGNALS Sun Apr 09 11:18:25 2000 +0000 @@ -10,21 +10,35 @@ To add a signal handler, call the fuction gaim_signal_connect with the following arguments: -enum gaim_event, void *, void * +void *, enum gaim_event, void *, void * + +The first arg is the handle that was passed to gaim_signal_init. You did + save it, right? +The second arg is hopefully obvious. +The third arg is a pointer to a function that takes various args + depending on which event you're dealing with. +The fourth arg is any data you want to send to your function, as a final + argument. -The first arg is hopefully obvious. -The second arg is a pointer to a function that takes various args - depending on which event you're dealing with. -The third arg is any data you want to send to your function, as a final - argument. +To remove a signal handler, call the function gaim_signal_disconnect with the +following arguments: + +void *, enum gaim_event, void * + +The first arg is the handle that was passed to gaim_signal_init. +The second arg is hopefully obvious. +The third arg is a pointer to the function you attached. + +Note that it deletes *all* functions matching the function you pass, not just +one. Sorry, that's just the way it works. So here are the args that get passed to your functions in various events: event_signon: - char *name + (none) - 'name' is your username. (Note that this can be returned through - other methods.) + Note that you can get the username (which would probably be the only + useful information here) from other places. (Read gaim.h for details). event_signoff: (none) @@ -37,6 +51,8 @@ message they sent. Note that you can modify these values. (You are encouraged to do so!) + Note that *other* plugins can also modify these values, so you should + check that they are not NULL, and try not to leave them as NULL. event_im_send: char **who, char **text diff -r 5ca21b68eb29 -r 9f6ce50ffb78 plugins/gaiminc.c --- a/plugins/gaiminc.c Sun Apr 09 08:25:15 2000 +0000 +++ b/plugins/gaiminc.c Sun Apr 09 11:18:25 2000 +0000 @@ -1,12 +1,47 @@ +#define GAIM_PLUGINS + #include #include #include #include +#include #include "gaim.h" -void gaim_plugin_init() { +void echo_hi(void *m) { + /* this doesn't do much, just lets you know who we are :) */ + show_about(NULL, NULL); } -void write_to_conv(struct conversation *c, char *what, int flags) { - printf("this got called\n"); +void reverse(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; + char tmp; + l = strlen(*message); + + if (!strcmp(*who, current_user->username)) + return; + + for (i = 0; i < l/2; i++) { + tmp = (*message)[i]; + (*message)[i] = (*message)[l - i - 1]; + (*message)[l - i - 1] = tmp; + } } + +void bud(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); +} + +void gaim_plugin_init(void *handle) { + /* this is for doing something fun when we sign on */ + gaim_signal_connect(handle, event_signon, echo_hi, NULL); + + /* this is for doing something fun when we get a message */ + gaim_signal_connect(handle, event_im_recv, reverse, NULL); + + /* this is for doing something fun when a buddy comes online */ + gaim_signal_connect(handle, event_buddy_signon, bud, NULL); +} diff -r 5ca21b68eb29 -r 9f6ce50ffb78 plugins/simple.c --- a/plugins/simple.c Sun Apr 09 08:25:15 2000 +0000 +++ b/plugins/simple.c Sun Apr 09 11:18:25 2000 +0000 @@ -1,15 +1,22 @@ +#define GAIM_PLUGINS + #include +#include "gaim.h" -void gaim_plugin_init() { +static void *handle = NULL; + +void gaim_plugin_init(void *h) { printf("plugin loaded.\n"); + handle = h; } void gaim_plugin_remove() { printf("plugin unloaded.\n"); + handle = NULL; } char *name() { - return "Simple plugin"; + return "Simple Plugin Version 1.0"; } char *description() { diff -r 5ca21b68eb29 -r 9f6ce50ffb78 src/aim.c --- a/src/aim.c Sun Apr 09 08:25:15 2000 +0000 +++ b/src/aim.c Sun Apr 09 11:18:25 2000 +0000 @@ -153,6 +153,23 @@ signoff, NULL); #endif + +#ifdef GAIM_PLUGINS + { + GList *c = callbacks; + struct gaim_callback *g; + void (*function)(void *); + while (c) { + g = (struct gaim_callback *)c->data; + if (g->event == event_signon && g->function != NULL) { + function = g->function; + (*function)(g->data); + } + c = c->next; + } + } +#endif + running = FALSE; return; } diff -r 5ca21b68eb29 -r 9f6ce50ffb78 src/buddy.c --- a/src/buddy.c Sun Apr 09 08:25:15 2000 +0000 +++ b/src/buddy.c Sun Apr 09 11:18:25 2000 +0000 @@ -304,6 +304,21 @@ void signoff() { GList *mem; + +#ifdef GAIM_PLUGINS + GList *c = callbacks; + struct gaim_callback *g; + void (*function)(void *); + while (c) { + g = (struct gaim_callback *)c->data; + if (g->event == event_signoff && g->function != NULL) { + function = g->function; + (*function)(g->data); + } + c = c->next; + } +#endif + while(groups) { mem = ((struct group *)groups->data)->members; while(mem) { @@ -1359,6 +1374,20 @@ if (!GTK_WIDGET_VISIBLE(b->item)) { +#ifdef GAIM_PLUGINS + GList *c = callbacks; + struct gaim_callback *g; + void (*function)(char *, void *); + while (c) { + g = (struct gaim_callback *)c->data; + if (g->event == event_buddy_signon && + g->function != NULL) { + function = g->function; + (*function)(b->name, g->data); + } + c = c->next; + } +#endif play_sound(BUDDY_ARRIVE); @@ -1437,6 +1466,20 @@ } else { if (GTK_WIDGET_VISIBLE(b->item)) { +#ifdef GAIM_PLUGINS + GList *c = callbacks; + struct gaim_callback *g; + void (*function)(char *, void *); + while (c) { + g = (struct gaim_callback *)c->data; + if (g->event == event_buddy_signoff && + g->function != NULL) { + function = g->function; + (*function)(b->name, g->data); + } + c = c->next; + } +#endif play_sound(BUDDY_LEAVE); pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm, NULL, (gchar **)logout_icon_xpm); diff -r 5ca21b68eb29 -r 9f6ce50ffb78 src/gaim.h --- a/src/gaim.h Sun Apr 09 08:25:15 2000 +0000 +++ b/src/gaim.h Sun Apr 09 11:18:25 2000 +0000 @@ -19,6 +19,9 @@ * */ +#include +#include +#include #ifdef USE_APPLET #include #endif /* USE_APPLET */ @@ -124,6 +127,25 @@ char *description; void *handle; }; + +enum gaim_event { + event_signon = 0, + event_signoff, + event_im_recv, + event_im_send, + event_buddy_signon, + event_buddy_signoff, + /* any others? it's easy to add... */ +}; + +struct gaim_callback { + void *handle; + enum gaim_event event; + void *function; + void *data; +}; + +extern GList *callbacks; #endif struct buddy { @@ -268,7 +290,7 @@ #define TYPE_SIGNOFF 4 #define TYPE_KEEPALIVE 5 -#define REVISION "gaim:$Revision: 100 $" +#define REVISION "gaim:$Revision: 104 $" #define FLAPON "FLAPON\r\n\r\n" #define ROAST "Tic/Toc" @@ -543,6 +565,8 @@ extern void load_plugin (GtkWidget *, gpointer); extern void unload_plugin(GtkWidget *, gpointer); extern void show_plugins (GtkWidget *, gpointer); +extern void gaim_signal_connect(void *, enum gaim_event, void *, void *); +extern void gaim_signal_disconnect(void *, enum gaim_event, void *); #endif /* Functions in prefs.c */ diff -r 5ca21b68eb29 -r 9f6ce50ffb78 src/plugins.c --- a/src/plugins.c Sun Apr 09 08:25:15 2000 +0000 +++ b/src/plugins.c Sun Apr 09 11:18:25 2000 +0000 @@ -44,7 +44,11 @@ #include -/* ------------------ Local Variables -------------------------*/ +/* ------------------ Global Variables ----------------------- */ + +GList *callbacks = NULL; + +/* ------------------ Local Variables ------------------------ */ static GtkWidget *plugin_dialog = NULL; static GList *plugins = NULL; @@ -53,12 +57,15 @@ static GtkWidget *plugtext; static GtkWidget *plugwindow; -/* --------------- Function Declarations -------------------- */ +/* --------------- Function Declarations --------------------- */ void load_plugin (GtkWidget *, gpointer); void unload_plugin(GtkWidget *, gpointer); void show_plugins (GtkWidget *, gpointer); + void gaim_signal_connect (void *, enum gaim_event, void *, void *); + void gaim_signal_disconnect(void *, enum gaim_event, void *); + static void destroy_plugins (GtkWidget *, gpointer); static void load_which_plugin(GtkWidget *, gpointer); static void unload (GtkWidget *, gpointer); @@ -140,7 +147,7 @@ } plugins = g_list_append(plugins, plug); - (*gaim_plugin_init)(); + (*gaim_plugin_init)(plug->handle); cfunc = dlsym(plug->handle, "name"); if ((error = dlerror()) == NULL) @@ -299,6 +306,8 @@ struct gaim_plugin *p; void (*gaim_plugin_remove)(); char *error; + GList *c = callbacks; + struct gaim_callback *g; i = GTK_LIST(pluglist)->selection; @@ -309,6 +318,14 @@ gaim_plugin_remove = dlsym(p->handle, "gaim_plugin_remove"); if ((error = dlerror()) == NULL) (*gaim_plugin_remove)(); + while (c) { + g = (struct gaim_callback *)c->data; + if (g->handle == p->handle) { + callbacks = g_list_remove(callbacks, c); + g_free(g); + } + c = c->next; + } dlclose(p->handle); plugins = g_list_remove(plugins, p); @@ -334,4 +351,28 @@ plugwindow = NULL; } +void gaim_signal_connect(void *handle, enum gaim_event which, + void *func, void *data) { + struct gaim_callback *call = g_malloc(sizeof *call); + call->handle = handle; + call->event = which; + call->function = func; + call->data = data; + + callbacks = g_list_append(callbacks, call); +} + +void gaim_signal_disconnect(void *handle, enum gaim_event which, void *func) { + GList *c = callbacks; + struct gaim_callback *g = NULL; + while (c) { + g = (struct gaim_callback *)c->data; + if (handle == g->handle && func == g->function) { + callbacks = g_list_remove(callbacks, g); + g_free(g); + } + c = c->next; + } +} + #endif /* GAIM_PLUGINS */ diff -r 5ca21b68eb29 -r 9f6ce50ffb78 src/server.c --- a/src/server.c Sun Apr 09 08:25:15 2000 +0000 +++ b/src/server.c Sun Apr 09 11:18:25 2000 +0000 @@ -83,7 +83,7 @@ gettimeofday(&lag_tv, NULL); if (!(general_options & OPT_GEN_SHOW_LAGMETER)) - serv_send_im(current_user->username, LAGOMETER_STR, 1); + serv_send_im(current_user->username, LAGOMETER_STR, 0); if (report_idle != IDLE_GAIM) return TRUE; @@ -137,12 +137,31 @@ void serv_send_im(char *name, char *message, int away) { char buf[MSG_LEN - 7]; + +#ifdef GAIM_PLUGINS + GList *c = callbacks; + struct gaim_callback *g; + void (*function)(char **, char **, void *); + while (c) { + g = (struct gaim_callback *)c->data; + if (g->event == event_im_send && g->function != NULL) { + function = g->function; + /* I can guarantee you this is wrong */ + (*function)(&name, &message, g->data); + } + c = c->next; + } + /* make sure no evil plugin is trying to crash gaim */ + if (message == NULL) + return; +#endif + #ifndef USE_OSCAR g_snprintf(buf, MSG_LEN - 8, "toc_send_im %s \"%s\"%s", normalize(name), message, ((away) ? " auto" : "")); sflap_send(buf, strlen(buf), TYPE_DATA); #else - aim_send_im(NULL, normalize(name), ((away) ? AIM_IMFLAGS_AWAY : 0), message); + aim_send_im(NULL, normalize(name), ((away) ? 0 : AIM_IMFLAGS_AWAY), message); #endif if (!away) serv_touch_idle(); @@ -451,6 +470,24 @@ int new_conv = 0; char *nname; +#ifdef GAIM_PLUGINS + GList *c = callbacks; + struct gaim_callback *g; + void (*function)(char **, char **, void *); + while (c) { + g = (struct gaim_callback *)c->data; + if (g->event == event_im_recv && g->function != NULL) { + function = g->function; + /* I can guarantee you this is wrong */ + (*function)(&name, &message, g->data); + } + c = c->next; + } + /* make sure no evil plugin is trying to crash gaim */ + if (message == NULL) + return; +#endif + nname = g_strdup(normalize(name)); if (!strcasecmp(normalize(name), nname)) {