diff src/module.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
children 6e637ad18494
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/module.c	Sat Sep 29 23:06:30 2001 +0000
@@ -0,0 +1,516 @@
+/*
+ * gaim
+ *
+ * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ----------------
+ * The Plug-in plug
+ *
+ * Plugin support is currently being maintained by Mike Saraf
+ * msaraf@dwc.edu
+ *
+ * Well, I didn't see any work done on it for a while, so I'm going to try
+ * my hand at it. - Eric warmenhoven@yahoo.com
+ *
+ * Mike is my roomate.  I can assure you that he's lazy :-P  -- Rob rob@marko.net
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef GAIM_PLUGINS
+
+#include <string.h>
+#include <sys/time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "gaim.h"
+
+/* ------------------ Global Variables ----------------------- */
+
+GList *plugins = NULL;
+GList *callbacks = NULL;
+
+/* --------------- Function Declarations --------------------- */
+
+struct gaim_plugin *  load_plugin(char *);
+              void  unload_plugin(struct gaim_plugin *p);
+struct gaim_plugin *reload_plugin(struct gaim_plugin *p);
+
+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 Function Declarations ------------- */
+
+static void plugin_remove_callbacks(GModule *);
+
+/* ------------------ Code Below ---------------------------- */
+
+struct gaim_plugin *load_plugin(char *filename)
+{
+	struct gaim_plugin *plug;
+	GList *c = plugins;
+	char *(*gaim_plugin_init)(GModule *);
+	char *(*cfunc)();
+	char *error;
+	char *retval;
+
+	if (!g_module_supported())
+		return NULL;
+	if (filename && !strlen(filename))
+		return NULL;
+
+	while (filename && c) {
+		plug = (struct gaim_plugin *)c->data;
+		if (!strcmp(filename, g_module_name(plug->handle))) {
+			/* just need to reload plugin */
+			return reload_plugin(plug);
+		} else
+			c = g_list_next(c);
+	}
+	plug = g_malloc(sizeof *plug);
+
+	debug_printf("Loading %s\n", filename);
+	plug->handle = g_module_open(filename, 0);
+	if (!plug->handle) {
+		error = (char *)g_module_error();
+		do_error_dialog(error, _("Plugin Error"));
+		g_free(plug);
+		return NULL;
+	}
+
+	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 NULL;
+	}
+
+	retval = (*gaim_plugin_init)(plug->handle);
+	debug_printf("loaded plugin returned %s\n", retval ? retval : "NULL");
+	if (retval) {
+		plugin_remove_callbacks(plug->handle);
+		do_error_dialog(retval, _("Plugin Error"));
+		g_module_close(plug->handle);
+		g_free(plug);
+		return NULL;
+	}
+
+	plugins = g_list_append(plugins, plug);
+
+	if (g_module_symbol(plug->handle, "name", (gpointer *)&cfunc)) {
+		plug->name = (*cfunc)();
+	} else {
+		plug->name = NULL;
+	}
+
+	if (g_module_symbol(plug->handle, "description", (gpointer *)&cfunc))
+		plug->description = (*cfunc)();
+	else
+		plug->description = NULL;
+
+	save_prefs();
+	return plug;
+}
+
+static void unload_gaim_plugin(struct gaim_plugin *p)
+{
+	void (*gaim_plugin_remove)();
+
+	debug_printf("Unloading %s\n", g_module_name(p->handle));
+
+	/* Attempt to call the plugin's remove function (if there) */
+	if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
+		(*gaim_plugin_remove)();
+
+	plugin_remove_callbacks(p->handle);
+
+	plugins = g_list_remove(plugins, p);
+	g_free(p);
+	save_prefs();
+}
+
+void unload_plugin(struct gaim_plugin *p)
+{
+	GModule *handle = p->handle;
+	unload_gaim_plugin(p);
+	g_module_close(handle);
+}
+
+static gboolean unload_timeout(gpointer handle)
+{
+	g_module_close(handle);
+	return FALSE;
+}
+
+void gaim_plugin_unload(GModule *handle)
+{
+	g_timeout_add(5000, unload_timeout, handle);
+}
+
+/* Do unload/load cycle of plugin. */
+struct gaim_plugin *reload_plugin(struct gaim_plugin *p)
+{
+	char file[1024];
+	GModule *handle = p->handle;
+
+	strncpy(file, g_module_name(handle), sizeof(file));
+	file[sizeof(file) - 1] = '\0';
+
+	debug_printf("Reloading %s\n", file);
+
+	/* Unload */
+	unload_plugin(p);
+
+	/* Load */
+	return load_plugin(file);
+}
+
+/* Remove all callbacks associated with plugin handle */
+static void plugin_remove_callbacks(GModule *handle)
+{
+	GList *c = callbacks;
+	struct gaim_callback *g;
+
+	debug_printf("%d callbacks to search\n", g_list_length(callbacks));
+
+	while (c) {
+		g = (struct gaim_callback *)c->data;
+		if (g->handle == handle) {
+			c = g_list_next(c);
+			callbacks = g_list_remove(callbacks, (gpointer)g);
+			debug_printf("Removing callback, %d remain\n", g_list_length(callbacks));
+		} else
+			c = g_list_next(c);
+	}
+}
+
+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;
+	call->event = which;
+	call->function = func;
+	call->data = data;
+
+	callbacks = g_list_append(callbacks, call);
+	debug_printf("Adding callback %d\n", g_list_length(callbacks));
+}
+
+void gaim_signal_disconnect(GModule *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, c->data);
+			g_free(g);
+			c = callbacks;
+			if (c == NULL)
+				break;
+		}
+		c = g_list_next(c);
+	}
+}
+
+#endif /* GAIM_PLUGINS */
+
+static char *event_name(enum gaim_event event)
+{
+	static char buf[128];
+	switch (event) {
+	case event_signon:
+		sprintf(buf, "event_signon");
+		break;
+	case event_signoff:
+		sprintf(buf, "event_signoff");
+		break;
+	case event_away:
+		sprintf(buf, "event_away");
+		break;
+	case event_back:
+		sprintf(buf, "event_back");
+		break;
+	case event_im_recv:
+		sprintf(buf, "event_im_recv");
+		break;
+	case event_im_send:
+		sprintf(buf, "event_im_send");
+		break;
+	case event_buddy_signon:
+		sprintf(buf, "event_buddy_signon");
+		break;
+	case event_buddy_signoff:
+		sprintf(buf, "event_buddy_signoff");
+		break;
+	case event_buddy_away:
+		sprintf(buf, "event_buddy_away");
+		break;
+	case event_buddy_back:
+		sprintf(buf, "event_buddy_back");
+		break;
+	case event_buddy_idle:
+		sprintf(buf, "event_buddy_idle");
+		break;
+	case event_buddy_unidle:
+		sprintf(buf, "event_buddy_unidle");
+		break;
+	case event_blist_update:
+		sprintf(buf, "event_blist_update");
+		break;
+	case event_chat_invited:
+		sprintf(buf, "event_chat_invited");
+		break;
+	case event_chat_join:
+		sprintf(buf, "event_chat_join");
+		break;
+	case event_chat_leave:
+		sprintf(buf, "event_chat_leave");
+		break;
+	case event_chat_buddy_join:
+		sprintf(buf, "event_chat_buddy_join");
+		break;
+	case event_chat_buddy_leave:
+		sprintf(buf, "event_chat_buddy_leave");
+		break;
+	case event_chat_recv:
+		sprintf(buf, "event_chat_recv");
+		break;
+	case event_chat_send:
+		sprintf(buf, "event_chat_send");
+		break;
+	case event_warned:
+		sprintf(buf, "event_warned");
+		break;
+	case event_error:
+		sprintf(buf, "event_error");
+		break;
+	case event_quit:
+		sprintf(buf, "event_quit");
+		break;
+	case event_new_conversation:
+		sprintf(buf, "event_new_conversation");
+		break;
+	case event_set_info:
+		sprintf(buf, "event_set_info");
+		break;
+	case event_draw_menu:
+		sprintf(buf, "event_draw_menu");
+		break;
+	case event_im_displayed_sent:
+		sprintf(buf, "event_im_displayed_sent");
+		break;
+	case event_im_displayed_rcvd:
+		sprintf(buf, "event_im_displayed_rcvd");
+		break;
+	case event_chat_send_invite:
+		sprintf(buf, "event_chat_send_invite");
+		break;
+	default:
+		sprintf(buf, "event_unknown");
+		break;
+	}
+	return buf;
+}
+
+int plugin_event(enum gaim_event event, void *arg1, void *arg2, void *arg3, void *arg4)
+{
+#ifdef USE_PERL
+	char buf[BUF_LONG];
+#endif
+#ifdef GAIM_PLUGINS
+	GList *c = callbacks;
+	struct gaim_callback *g;
+
+	while (c) {
+		void (*zero)(void *);
+		void (*one)(void *, void *);
+		void (*two)(void *, void *, void *);
+		void (*three)(void *, void *, void *, void *);
+		void (*four)(void *, void *, void *, void *, void *);
+
+		g = (struct gaim_callback *)c->data;
+		if (g->event == event && g->function !=NULL) {
+			switch (event) {
+
+				/* no args */
+			case event_blist_update:
+			case event_quit:
+				zero = g->function;
+				(*zero)(g->data);
+				break;
+
+				/* one arg */
+			case event_signon:
+			case event_signoff:
+			case event_new_conversation:
+			case event_error:
+				one = g->function;
+				(*one)(arg1, g->data);
+				break;
+
+				/* two args */
+			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_chat_leave:
+			case event_set_info:
+			case event_draw_menu:
+				two = g->function;
+				(*two)(arg1, arg2, g->data);
+				break;
+
+				/* three args */
+			case event_im_send:
+			case event_im_displayed_sent:
+			case event_chat_join:
+			case event_chat_buddy_join:
+			case event_chat_buddy_leave:
+			case event_chat_send:
+			case event_away:
+			case event_back:
+			case event_warned:
+				three = g->function;
+				(*three)(arg1, arg2, arg3, g->data);
+				break;
+
+				/* four args */
+			case event_im_recv:
+			case event_chat_recv:
+			case event_im_displayed_rcvd:
+			case event_chat_send_invite:
+			case event_chat_invited:
+				four = g->function;
+				(*four)(arg1, arg2, arg3, arg4, g->data);
+				break;
+
+			default:
+				debug_printf("unknown event %d\n", event);
+				break;
+			}
+		}
+		c = c->next;
+	}
+#endif /* GAIM_PLUGINS */
+#ifdef USE_PERL
+	switch (event) {
+	case event_signon:
+	case event_signoff:
+	case event_away:
+	case event_back:
+		g_snprintf(buf, sizeof buf, "%lu", (unsigned long)arg1);
+		break;
+	case event_im_recv:
+		g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
+			   *(char **)arg2 ? *(char **)arg2 : "(null)",
+			   *(char **)arg3 ? *(char **)arg3 : "(null)");
+		break;
+	case event_im_send:
+		g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
+			   (char *)arg2, *(char **)arg3 ? *(char **)arg3 : "(null)");
+		break;
+	case event_buddy_signon:
+	case event_buddy_signoff:
+	case event_set_info:
+	case event_buddy_away:
+	case event_buddy_back:
+	case event_buddy_idle:
+	case event_buddy_unidle:
+		g_snprintf(buf, sizeof buf, "%lu \"%s\"", (unsigned long)arg1, (char *)arg2);
+		break;
+	case event_chat_invited:
+		g_snprintf(buf, sizeof buf, "%lu \"%s\" \"%s\" %s", (unsigned long)arg1,
+				(char *)arg2, (char *)arg3, arg4 ? (char *)arg4 : "");
+		break;
+	case event_chat_join:
+	case event_chat_buddy_join:
+	case event_chat_buddy_leave:
+		g_snprintf(buf, sizeof buf, "%lu %d \"%s\"", (unsigned long)arg1,
+				(int)arg2, (char *)arg3);
+		break;
+	case event_chat_leave:
+		g_snprintf(buf, sizeof buf, "%lu %d", (unsigned long)arg1, (int)arg2);
+		break;
+	case event_chat_recv:
+		g_snprintf(buf, sizeof buf, "%lu %d \"%s\" %s", (unsigned long)arg1,
+				(int)arg2, (char *)arg3, (char *)arg4 ? (char *)arg4 : "(null)");
+		break;
+	case event_chat_send_invite:
+		g_snprintf(buf, sizeof buf, "%lu %d \"%s\" %s", (unsigned long)arg1,
+				(int)arg2, (char *)arg3, *(char **)arg4 ? *(char **)arg4 : "(null)");
+		break;
+	case event_chat_send:
+		g_snprintf(buf, sizeof buf, "%lu %d %s", (unsigned long)arg1, (int)arg2,
+				*(char **)arg3 ? *(char **)arg3 : "(null)");
+		break;
+	case event_warned:
+		g_snprintf(buf, sizeof buf, "%lu \"%s\" %d", (unsigned long)arg1,
+				arg2 ? (char *)arg2 : "", (int)arg3);
+		break;
+	case event_quit:
+		buf[0] = 0;
+		break;
+	case event_new_conversation:
+		g_snprintf(buf, sizeof buf, "\"%s\"", (char *)arg1);
+		break;
+	case event_im_displayed_sent:
+		g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
+				(char *)arg2, *(char **)arg3 ? *(char **)arg3 : "(null)");
+		break;
+	case event_im_displayed_rcvd:
+		g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
+				(char *)arg2, (char *)arg3 ? (char *)arg3 : "(null)");
+		break;
+	default:
+		return 0;
+	}
+	return perl_event(event_name(event), buf);
+#else
+	return 0;
+#endif
+}
+
+/* Calls the gaim_plugin_remove function in any loaded plugin that has one */
+#ifdef GAIM_PLUGINS
+void remove_all_plugins()
+{
+	GList *c = plugins;
+	struct gaim_plugin *p;
+	void (*gaim_plugin_remove)();
+
+	while (c) {
+		p = (struct gaim_plugin *)c->data;
+		if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
+			(*gaim_plugin_remove)();
+		g_free(p);
+		c = c->next;
+	}
+}
+#endif