changeset 94:9f6ce50ffb78

[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 <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 09 Apr 2000 11:18:25 +0000
parents 5ca21b68eb29
children 19cffb5bd129
files configure.in plugins/CRAZY plugins/HOWTO plugins/Makefile plugins/SIGNALS plugins/gaiminc.c plugins/simple.c src/aim.c src/buddy.c src/gaim.h src/plugins.c src/server.c
diffstat 12 files changed, 279 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- 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"
--- 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
--- 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
--- 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 $@ $<
--- 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
--- 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 <gtk/gtk.h>
 #include <time.h>
 #include <stdio.h>
 #include <fcntl.h>
+#include <string.h>
 #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);
+}
--- 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 <stdio.h>
+#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() {
--- 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;
 }
--- 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);
--- 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 <gtk/gtk.h>
+#include <time.h>
+#include <stdio.h>
 #ifdef USE_APPLET
 #include <applet-widget.h>
 #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 */
--- 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 <dlfcn.h>
 
-/* ------------------ 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 */
--- 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)) {