changeset 391:be408b41c172

[gaim-migrate @ 401] Plugins got updated. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Mon, 12 Jun 2000 11:30:05 +0000
parents 0890c6250e7e
children df5127560034
files ChangeLog plugins/ChangeLog plugins/HOWTO plugins/Makefile.am plugins/SIGNALS plugins/error.c plugins/spellchk.c src/buddy.c src/buddy_chat.c src/conversation.c src/dialogs.c src/gaim.h src/plugins.c src/server.c
diffstat 14 files changed, 396 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Jun 12 08:11:26 2000 +0000
+++ b/ChangeLog	Mon Jun 12 11:30:05 2000 +0000
@@ -1,6 +1,7 @@
 GAIM: The Pimpin' Penguin IM Clone thats good for the soul! 
 
 version 0.9.20:
+	* More plugin events, more plugin features
 
 version 0.9.19 (06/09/2000):
 	* Graphical Smiley Faces
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ChangeLog	Mon Jun 12 11:30:05 2000 +0000
@@ -0,0 +1,23 @@
+version 0.9.20:
+	It's 3 am the night before finals, it's obviously a good time to hack
+	gaim.
+
+	The first thing to note is that there are about 9 new events plugins
+	can attach to, most of them dealing with chat, since I know that was a
+	big thing that was missing. Please note that I was nice and decided to
+	tack these extra events onto the end of the enum, which means that
+	plugins do not have to be recompiled in order for them to still work.
+
+	The big thing to note is that gaim_plugin_init no longer returns void,
+	but int.  If it returns 0, gaim interprets this as there being no
+	error, and continues with loading as normal. (This should be backwards-
+	compatible: returning 0 is the equivalent of returning void.) If it
+	returns a non-zero number, there was an error loading detected by the
+	plugin. At that point, gaim will try to clean things up by removing any
+	callbacks that have been added by the plugin. It will then try to call
+	the plugin's gaim_plugin_error function, if there is one. The function
+	should take an int (the int returned by gaim_plugin_init) and return a
+	char*. If the char* is not NULL, it is displayed by gaim as an error
+	message.  The plugin is then unloaded and closed and life goes back to
+	normal. If any of that was confusing, it was confusing to me, too. I
+	added a plugin, error.c, which should help clear things up.
--- a/plugins/HOWTO	Mon Jun 12 08:11:26 2000 +0000
+++ b/plugins/HOWTO	Mon Jun 12 11:30:05 2000 +0000
@@ -28,6 +28,11 @@
 needed for connecting to signals and things. It's a good idea to remember it
 somehow.
 
+gaim_plugin_init should return an int. If the int it returns is anything other
+than 0, it is interpreted as an error, and gaim_plugin_error is called. See
+the ChangeLog file in this directory for more details, and error.c for an
+example.
+
 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
 really neat thing is you can do things at events. For example, when one of
--- a/plugins/Makefile.am	Mon Jun 12 08:11:26 2000 +0000
+++ b/plugins/Makefile.am	Mon Jun 12 11:30:05 2000 +0000
@@ -13,5 +13,6 @@
 clean distclean clean-recursive distclean-recursive:
 	$(RM) $(plugin_DATA)
 endif
-EXTRA_DIST = CRAZY HOWTO SIGNALS autorecon.c filectl.c gaiminc.c \
-	iconaway.c lagmeter.c notify.c simple.c spellchk.c toc_commands.c
+EXTRA_DIST = ChangeLog CRAZY HOWTO SIGNALS autorecon.c error.c filectl.c \
+	gaiminc.c iconaway.c lagmeter.c notify.c simple.c spellchk.c \
+	toc_commands.c
--- a/plugins/SIGNALS	Mon Jun 12 08:11:26 2000 +0000
+++ b/plugins/SIGNALS	Mon Jun 12 11:30:05 2000 +0000
@@ -9,7 +9,17 @@
 	event_buddy_signoff,
 	event_buddy_away,
 	event_buddy_back,
-	event_blist_update
+	event_blist_update,
+	event_chat_invited,
+	event_chat_join,
+	event_chat_leave,
+	event_chat_buddy_join,
+	event_chat_buddy_leave,
+	event_chat_recv,
+	event_chat_send,
+	event_warned,
+	event_error,
+	event_quit
 };
 
 To add a signal handler, call the fuction gaim_signal_connect with the
@@ -103,3 +113,72 @@
 	
 	This event is called when the buddylist is updated (automatically every
 	20 seconds)
+
+event_chat_invited:
+	char *who, char *room, char *message
+
+	'who' is who invited you to a chat room.
+	'room' is the room they invited you to.
+	'message' is the (optional) message they sent to invite you, and may be
+	an empty string.
+
+event_chat_join:
+	char *room
+
+	'room' is the chat room that you have just joined.
+
+event_chat_leave:
+	char *room
+
+	'room' is the chat room that you have just left.
+
+event_chat_buddy_join:
+	char *room, char *who
+
+	'room' is the room the person joined.
+	'who' is the screenname of the person who joined.
+
+event_chat_buddy_leave:
+	char *room, char *who
+
+	'room' is the room the person left.
+	'who' is the screenname of the person who left.
+
+event_chat_recv:
+	char *room, char *who, char *text
+
+	'room' should be obvious by now.
+	'who' should be too.
+	'text' is the message that got sent.
+
+	Note that because of the bizarre way chat works, you also receive
+	messages that you send. I didn't design it, AOL did.
+
+event_chat_send:
+	char *room, char **text
+
+	'room'. Need I say more.
+	'text' is what you're about to say, linkified/HTML-ized, but not
+	TOC-escaped.
+
+event_warned:
+	char *who, int level
+
+	'who' is who warned you. Note that this can be NULL, indicating either
+	an anonymous warning, or your warning level has dropped.
+	'level' is your new warning level.
+
+event_error:
+	int error
+
+	'error' is the number of the error as defined by the TOC PROTOCOL
+	document, which can be found in the docs/ directory of the source
+	tree. Note that if the person is using Oscar, this number can often
+	be misleading, as not all the errors have been worked out, and some
+	do not translate to TOC error codes cleanly.
+
+event_quit:
+	(none)
+
+	Called when gaim quits normally. If gaim dies or is killed, this won't
+	be called. It's not my fault, it's Seg's.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/error.c	Mon Jun 12 11:30:05 2000 +0000
@@ -0,0 +1,44 @@
+#define GAIM_PLUGINS
+#include "gaim.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+int gaim_plugin_init(void *handle) {
+	int error;
+
+	/* so here, we load any callbacks, do the normal stuff */
+
+	srand(time(NULL));
+	error = rand() % 3;
+	/* there's a 1 in 3 chance there *won't* be an error :) */
+	return error;
+}
+
+void gaim_plugin_remove() {
+	/* this only gets called if we get loaded successfully, and then
+	 * unloaded. */
+}
+
+char *gaim_plugin_error(int error) {
+	/* by the time we've gotten here, all our callbacks are removed.
+	 * we just have to deal with what the error was (as defined by us)
+	 * 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;
+	case 2:
+		return "Internal plugin error: exiting.";
+	}
+	/* we should never get here */
+	return NULL;
+}
+
+char *name() {
+	return "Error Tester";
+}
+
+char *description() {
+	return "A nice little program that causes error messages";
+}
--- a/plugins/spellchk.c	Mon Jun 12 08:11:26 2000 +0000
+++ b/plugins/spellchk.c	Mon Jun 12 11:30:05 2000 +0000
@@ -140,6 +140,7 @@
 	load_conf();
 
 	gaim_signal_connect(handle, event_im_send, substitute_words, NULL);
+	gaim_signal_connect(handle, event_chat_send, substitute_words, NULL);
 }
 
 void gaim_plugin_remove() {
--- a/src/buddy.c	Mon Jun 12 08:11:26 2000 +0000
+++ b/src/buddy.c	Mon Jun 12 11:30:05 2000 +0000
@@ -27,6 +27,9 @@
 #include <applet-widget.h>
 #include "gnome_applet_mgr.h"
 #endif /* USE_APPLET */
+#ifdef GAIM_PLUGINS
+#include <dlfcn.h>
+#endif /* GAIM_PLUGINS */
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -1069,6 +1072,40 @@
 
 void do_quit()
 {
+#ifdef GAIM_PLUGINS
+	GList *c;
+	struct gaim_callback *g;
+	struct gaim_plugin *p;
+	void (*function)(void *);
+	void (*gaim_plugin_remove)();
+	char *error;
+
+	/* first we tell those who have requested it we're quitting */
+	c = callbacks;
+	while (c) {
+		g = (struct gaim_callback *)c->data;
+		if (g->event == event_quit && g->function != NULL) {
+			function = g->function;
+			(*function)(g->data);
+		}
+		c = c->next;
+	}
+
+	/* then we remove everyone in a mass suicide */
+	c = plugins;
+	while (c) {
+		p = (struct gaim_plugin *)c->data;
+		gaim_plugin_remove = dlsym(p->handle, "gaim_plugin_remove");
+		if ((error = (char *)dlerror()) == NULL)
+			(*gaim_plugin_remove)();
+		/* we don't need to worry about removing callbacks since
+		 * there won't be any more chance to call them back :) */
+		dlclose(p->handle);
+		g_free(p->filename); /* why do i bother? */
+		g_free(p);
+	}
+#endif
+
 	exit(0);
 }
 
--- a/src/buddy_chat.c	Mon Jun 12 08:11:26 2000 +0000
+++ b/src/buddy_chat.c	Mon Jun 12 11:30:05 2000 +0000
@@ -399,6 +399,28 @@
 		linkify_text(buf);
 	}
 
+#ifdef GAIM_PLUGINS
+	{
+	GList *c = callbacks;
+	struct gaim_callback *g;
+	void (*function)(char *, char **, void *);
+	char *buffy = g_strdup(buf);
+	while (c) {
+		g = (struct gaim_callback *)c->data;
+		if (g->event == event_chat_send && g->function != NULL) {
+			function = g->function;
+			(*function)(b->name, &buffy, g->data);
+		}
+		c = c->next;
+	}
+	if (!buffy)
+		return;
+	g_snprintf(buf, sizeof buf, "%s", buffy);
+	g_free(buffy);
+	}
+#endif
+
+
         escape_text(buf);
         serv_chat_send(b->id, buf);
         
@@ -518,6 +540,20 @@
 {
         char *name = g_strdup(buddy);
 
+#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_chat_buddy_join && g->function != NULL) {
+			function = g->function;
+			(*function)(b->name, name, g->data);
+		}
+		c = c->next;
+	}
+#endif
+
         b->in_room = g_list_append(b->in_room, name);
 
         update_chat_list(b);
@@ -533,6 +569,20 @@
 {	
         GList *names = b->in_room;
 
+#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_chat_buddy_leave && g->function != NULL) {
+			function = g->function;
+			(*function)(b->name, buddy, g->data);
+		}
+		c = c->next;
+	}
+#endif
+
         while(names) {
                 if (!strcasecmp((char *)names->data, buddy)) {
                         b->in_room = g_list_remove(b->in_room, names->data);
--- a/src/conversation.c	Mon Jun 12 08:11:26 2000 +0000
+++ b/src/conversation.c	Mon Jun 12 11:30:05 2000 +0000
@@ -473,18 +473,21 @@
 		GList *ca = callbacks;
 		struct gaim_callback *g;
 		void (*function)(char *, char **, void *);
+		char *buffy = g_strdup(buf);
 		while (ca) {
 			g = (struct gaim_callback *)(ca->data);
 			if (g->event == event_im_send && g->function != NULL) {
 				function = g->function;
-				(*function)(c->name, &buf, g->data);
+				(*function)(c->name, &buffy, g->data);
 			}
 			ca = ca->next;
 		}
-		if (buf == NULL) {
+		if (!buffy) {
 			g_free(buf2);
 			return;
 		}
+		g_snprintf(buf, BUF_LONG, "%s", buffy);
+		g_free(buffy);
 	}
 #endif
         
--- a/src/dialogs.c	Mon Jun 12 08:11:26 2000 +0000
+++ b/src/dialogs.c	Mon Jun 12 11:30:05 2000 +0000
@@ -309,7 +309,8 @@
         g_list_free(dialogwindows);
         dialogwindows = NULL;
 
-	do_im_back(NULL, NULL);
+	if (awaymessage)
+		do_im_back(NULL, NULL);
 
         if (imdialog) {
                 destroy_dialog(NULL, imdialog);
@@ -450,14 +451,28 @@
 
 
 
-void show_error_dialog(char *c)
+void show_error_dialog(char *d)
 {
 
-	int no = atoi(c);
+	int no = atoi(d);
 	char *w = strtok(NULL, ":");
 	char buf[256];
 	char buf2[32];
  	
+#ifdef GAIM_PLUGINS
+	GList *c = callbacks;
+	struct gaim_callback *g;
+	void (*function)(int, void *);
+	while (c) {
+		g = (struct gaim_callback *)c->data;
+		if (g->event == event_error && g->function != NULL) {
+			function = g->function;
+			(*function)(no, g->data);
+		}
+		c = c->next;
+	}
+#endif
+
 	
         switch(no) {
         case 69:
--- a/src/gaim.h	Mon Jun 12 08:11:26 2000 +0000
+++ b/src/gaim.h	Mon Jun 12 11:30:05 2000 +0000
@@ -158,6 +158,16 @@
 	event_buddy_away,
 	event_buddy_back,
 	event_blist_update,
+	event_chat_invited,
+	event_chat_join,
+	event_chat_leave,
+	event_chat_buddy_join,
+	event_chat_buddy_leave,
+	event_chat_recv,
+	event_chat_send,
+	event_warned,
+	event_error,
+	event_quit,
 	/* any others? it's easy to add... */
 };
 
@@ -376,7 +386,7 @@
 #define TYPE_SIGNOFF   4
 #define TYPE_KEEPALIVE 5
 
-#define REVISION "gaim:$Revision: 385 $"
+#define REVISION "gaim:$Revision: 401 $"
 #define FLAPON "FLAPON\r\n\r\n"
 
 #define ROAST "Tic/Toc"
--- a/src/plugins.c	Mon Jun 12 08:11:26 2000 +0000
+++ b/src/plugins.c	Mon Jun 12 11:30:05 2000 +0000
@@ -138,9 +138,12 @@
 
 void load_plugin(char *filename) {
 	struct gaim_plugin *plug;
-	void (*gaim_plugin_init)();
+	int (*gaim_plugin_init)();
+	char *(*gaim_plugin_error)(int);
 	char *(*cfunc)();
 	char *error;
+	int retval;
+	char *plugin_error;
 
 	if (filename == NULL) return;
 	plug = g_malloc(sizeof *plug);
@@ -172,8 +175,39 @@
 		return;
 	}
 
+	retval = (*gaim_plugin_init)(plug->handle);
+	sprintf(debug_buff, "loaded plugin returned %d\n", retval);
+	debug_print(debug_buff);
+	if (retval) {
+		GList *c = callbacks;
+		struct gaim_callback *g;
+		while (c) {
+			g = (struct gaim_callback *)c->data;
+			if (g->handle == plug->handle) {
+				callbacks = g_list_remove(callbacks, c->data);
+				sprintf(debug_buff, "Removing callback, %d remain\n",
+						g_list_length(callbacks));
+				debug_print(debug_buff);
+				c = callbacks;
+				if (c == NULL) {
+					break;
+				}
+			} else {
+				c = c->next;
+			}
+		}
+		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);
+		return;
+	}
+
 	plugins = g_list_append(plugins, plug);
-	(*gaim_plugin_init)(plug->handle);
 
 	cfunc = dlsym(plug->handle, "name");
 	if ((error = (char *)dlerror()) == NULL)
--- a/src/server.c	Mon Jun 12 08:11:26 2000 +0000
+++ b/src/server.c	Mon Jun 12 11:30:05 2000 +0000
@@ -631,18 +631,22 @@
 	GList *c = callbacks;
 	struct gaim_callback *g;
 	void (*function)(char **, char **, void *);
+	char *buffy = g_strdup(message);
+	char *angel = g_strdup(name);
 	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);
+			(*function)(&angel, &buffy, g->data);
 		}
 		c = c->next;
 	}
-	/* make sure no evil plugin is trying to crash gaim */
-	if (message == NULL)
+	if (!buffy || !angel)
 		return;
+	g_snprintf(message, strlen(message) + 1, "%s", buffy);
+	g_free(buffy);
+	g_snprintf(name, strlen(name) + 1, "%s", angel);
+	g_free(angel);
 #endif
 
 	nname = g_strdup(normalize(name));
@@ -834,6 +838,20 @@
         GtkWidget *d, *label, *close;
 
 
+#ifdef GAIM_PLUGINS
+	GList *c = callbacks;
+	struct gaim_callback *g;
+	void (*function)(char *, int, void *);
+	while (c) {
+		g = (struct gaim_callback *)c->data;
+		if (g->event == event_warned && g->function != NULL) {
+			function = g->function;
+			(*function)(name, lev, g->data);
+		}
+		c = c->next;
+	}
+#endif
+
         g_snprintf(buf2, 1023, "You have just been warned by %s.\nYour new warning level is %d./%%",
                    ((name == NULL) ? "an anonymous person" : name) , lev);
 
@@ -889,6 +907,20 @@
         char buf2[BUF_LONG];
 
 
+#ifdef GAIM_PLUGINS
+	GList *c = callbacks;
+	struct gaim_callback *g;
+	void (*function)(char *, char *, char *, void *);
+	while (c) {
+		g = (struct gaim_callback *)c->data;
+		if (g->event == event_chat_invited && g->function != NULL) {
+			function = g->function;
+			(*function)(who, name, message, g->data);
+		}
+		c = c->next;
+	}
+#endif
+
         g_snprintf(buf2, sizeof(buf2), "User '%s' invites you to buddy chat room: '%s'\n%s", who, name, message);
 
         d = gtk_dialog_new();
@@ -930,6 +962,20 @@
 {
         struct buddy_chat *b;
 
+#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_chat_join && g->function != NULL) {
+			function = g->function;
+			(*function)(name, g->data);
+		}
+		c = c->next;
+	}
+#endif
+
         b = (struct buddy_chat *)g_new0(struct buddy_chat, 1);
         buddy_chats = g_list_append(buddy_chats, b);
 
@@ -958,6 +1004,22 @@
         if (!b)
                 return;
 
+#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_chat_leave && g->function != NULL) {
+			function = g->function;
+			(*function)(b->name, g->data);
+		}
+		c = c->next;
+	}
+	}
+#endif
+
 	sprintf(debug_buff, "Leaving room %s.\n", b->name);
 	debug_print(debug_buff);
 
@@ -983,6 +1045,22 @@
         if (!b)
                 return;
         
+#ifdef GAIM_PLUGINS
+	{
+	GList *c = callbacks;
+	struct gaim_callback *g;
+	void (*function)(char *, char *, char *, void *);
+	while (c) {
+		g = (struct gaim_callback *)c->data;
+		if (g->event == event_chat_recv && g->function != NULL) {
+			function = g->function;
+			(*function)(b->name, who, message, g->data);
+		}
+		c = c->next;
+	}
+	}
+#endif
+
         if (whisper)
                 w = WFLAG_WHISPER;
         else