diff src/plugins.c @ 1047:ece2d1543b20

[gaim-migrate @ 1057] Plugins now use GModule. Protocol plugins can be dynamically updated. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Wed, 01 Nov 2000 22:30:36 +0000
parents 67ed2ee5be9f
children d50d3abb9eb7
line wrap: on
line diff
--- 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;