changeset 3572:bdd0bebd2d04

[gaim-migrate @ 3670] Phase II. No longer do you have to worry about protocol plugins. When Gaim probes plugins on load, it will detect protocol plugins and add them to the list of available protocols. When you try to log an account on with one of them, Gaim will automatically load the plugin--when no more accounts need the protocol--Gaim will automatically unload it. Protocol plugins are no longer available in the plugins ui, and no protocols are compiled statically by default. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Mon, 30 Sep 2002 01:05:18 +0000
parents a88c62c5b7da
children 163205125ee2
files configure.ac configure.in src/away.c src/buddy_chat.c src/conversation.c src/dialogs.c src/module.c src/multi.c src/perl.c src/protocols/gg/gg.c src/protocols/icq/gaim_icq.c src/protocols/irc/irc.c src/protocols/jabber/jabber.c src/protocols/msn/msn.c src/protocols/napster/napster.c src/protocols/oscar/oscar.c src/protocols/toc/toc.c src/protocols/yahoo/yahoo.c src/protocols/zephyr/zephyr.c src/prpl.c src/prpl.h src/server.c src/util.c
diffstat 23 files changed, 296 insertions(+), 494 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Sun Sep 29 17:00:14 2002 +0000
+++ b/configure.ac	Mon Sep 30 01:05:18 2002 +0000
@@ -67,7 +67,7 @@
 AM_CONDITIONAL(DISTRIB, test "x$enable_distrib" = "xyes")
 AC_ARG_ENABLE(multi,   [  --disable-multi         disable multiple connections],,enable_multi=yes)
 AC_ARG_ENABLE(prpls,   [  --disable-prpls         don't build dynamic protocol plugins],,enable_prpls=yes)
-AC_ARG_WITH(static-prpls,    [  --with-static-prpls     link in certain protocols statically],[STATIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`],STATIC_PRPLS="oscar")
+AC_ARG_WITH(static-prpls,    [  --with-static-prpls     link in certain protocols statically],[STATIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`],STATIC_PRPLS="")
 if test "x$STATIC_PRPLS" = "xall" ; then
 	STATIC_PRPLS="gg irc jabber msn napster oscar toc yahoo zephyr"
 fi
@@ -78,7 +78,7 @@
 for i in $STATIC_PRPLS ; do
 	STATIC_LINK_LIBS="$STATIC_LINK_LIBS protocols/$i/lib$i.a"
 	extern_init="$extern_init extern void ${i}_init(struct prpl *);"
-	load_proto="$load_proto load_protocol(${i}_init, sizeof(struct prpl));"
+	load_proto="$load_proto load_protocol(${i}_init);"
 	case $i in
 		gg) static_gg=yes ;;
 		irc) static_irc=yes ;;
--- a/configure.in	Sun Sep 29 17:00:14 2002 +0000
+++ b/configure.in	Mon Sep 30 01:05:18 2002 +0000
@@ -66,7 +66,7 @@
 AM_CONDITIONAL(DISTRIB, test "x$enable_distrib" = "xyes")
 AC_ARG_ENABLE(multi,   [  --disable-multi         disable multiple connections],,enable_multi=yes)
 AC_ARG_ENABLE(prpls,   [  --disable-prpls         don't build dynamic protocol plugins],,enable_prpls=yes)
-AC_ARG_WITH(static-prpls,    [  --with-static-prpls     link in certain protocols statically],[STATIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`],STATIC_PRPLS="oscar")
+AC_ARG_WITH(static-prpls,    [  --with-static-prpls     link in certain protocols statically],[STATIC_PRPLS=`echo $withval | $sedpath 's/,/ /g'`],STATIC_PRPLS="")
 if test "x$STATIC_PRPLS" = "xall" ; then
 	STATIC_PRPLS="gg irc jabber msn napster oscar toc yahoo zephyr"
 fi
--- a/src/away.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/away.c	Mon Sep 30 01:05:18 2002 +0000
@@ -464,7 +464,7 @@
 				}
 
 				g_snprintf(buf, sizeof(buf), "%s (%s)",
-					   gc->username, gc->prpl->name());
+					   gc->username, gc->prpl->name);
 				menuitem = gtk_menu_item_new_with_label(buf);
 				gtk_menu_append(GTK_MENU(awaymenu), menuitem);
 				gtk_widget_show(menuitem);
--- a/src/buddy_chat.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/buddy_chat.c	Mon Sep 30 01:05:18 2002 +0000
@@ -217,7 +217,7 @@
 			continue;
 		if (!joinchatgc)
 			joinchatgc = g;
-		g_snprintf(buf, sizeof buf, "%s (%s)", g->username, g->prpl->name());
+		g_snprintf(buf, sizeof buf, "%s (%s)", g->username, g->prpl->name);
 		opt = gtk_menu_item_new_with_label(buf);
 		gtk_object_set_user_data(GTK_OBJECT(opt), g);
 		gtk_signal_connect(GTK_OBJECT(opt), "activate", GTK_SIGNAL_FUNC(joinchat_choose), g);
--- a/src/conversation.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/conversation.c	Mon Sep 30 01:05:18 2002 +0000
@@ -2480,7 +2480,7 @@
 
 		while (g) {
 			c = (struct gaim_connection *)g->data;
-			g_snprintf(buf, sizeof buf, "%s (%s)", c->username, c->prpl->name());
+			g_snprintf(buf, sizeof buf, "%s (%s)", c->username, c->prpl->name);
 			opt = gtk_menu_item_new_with_label(buf);
 			gtk_object_set_user_data(GTK_OBJECT(opt), cnv);
 			gtk_signal_connect(GTK_OBJECT(opt), "activate",
--- a/src/dialogs.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/dialogs.c	Mon Sep 30 01:05:18 2002 +0000
@@ -834,7 +834,7 @@
 
 		while (g) {
 			c = (struct gaim_connection *)g->data;
-			g_snprintf(buf, sizeof(buf), "%s (%s)", c->username, c->prpl->name());
+			g_snprintf(buf, sizeof(buf), "%s (%s)", c->username, c->prpl->name);
 			opt = gtk_menu_item_new_with_label(buf);
 			gtk_object_set_user_data(GTK_OBJECT(opt), info);
 
@@ -1045,7 +1045,7 @@
 	while (g) {
 		c = (struct gaim_connection *)g->data;
 		g_snprintf(buf, sizeof(buf), "%s (%s)", 
-				c->username, c->prpl->name());
+				c->username, c->prpl->name);
 		opt = gtk_menu_item_new_with_label(buf);
 		gtk_object_set_user_data(GTK_OBJECT(opt), b);
 		gtk_signal_connect(GTK_OBJECT(opt), "activate",
@@ -1321,7 +1321,7 @@
 		c = c->next;
 		if (!gc->prpl->set_permit_deny)
 			continue;
-		g_snprintf(buf, sizeof buf, "%s (%s)", gc->username, gc->prpl->name());
+		g_snprintf(buf, sizeof buf, "%s (%s)", gc->username, gc->prpl->name);
 		opt = gtk_menu_item_new_with_label(buf);
 		gtk_signal_connect(GTK_OBJECT(opt), "activate", GTK_SIGNAL_FUNC(deny_gc_opt), gc);
 		gtk_widget_show(opt);
@@ -1649,7 +1649,7 @@
 	while (u) {
 		a = (struct aim_user *)u->data;
 		p = (struct prpl *)find_prpl(a->protocol);
-		g_snprintf(buf, sizeof buf, "%s (%s)", a->username, (p && p->name)?p->name():"Unknown");
+		g_snprintf(buf, sizeof buf, "%s (%s)", a->username, (p && p->name)?p->name:"Unknown");
 		opt = gtk_menu_item_new_with_label(buf);
 		gtk_object_set_user_data(GTK_OBJECT(opt), a);
 		gtk_signal_connect(GTK_OBJECT(opt), "activate", GTK_SIGNAL_FUNC(pounce_choose), b);
@@ -3345,7 +3345,7 @@
 
 	while (g) {
 		c = (struct gaim_connection *)g->data;
-		g_snprintf(buf, sizeof buf, "%s (%s)", c->username, c->prpl->name());
+		g_snprintf(buf, sizeof buf, "%s (%s)", c->username, c->prpl->name);
 		opt = gtk_menu_item_new_with_label(buf);
 		gtk_signal_connect(GTK_OBJECT(opt), "activate", GTK_SIGNAL_FUNC(set_import_gc), c);
 		gtk_widget_show(opt);
--- a/src/module.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/module.c	Mon Sep 30 01:05:18 2002 +0000
@@ -35,6 +35,7 @@
 #endif
 
 #include "gaim.h"
+#include "prpl.h"
 
 #include <string.h>
 #include <sys/time.h>
@@ -92,7 +93,9 @@
 	int l;
 #if GAIM_PLUGINS     
 	char *(*gaim_plugin_init)(GModule *);
+	char *(*gaim_prpl_init)(struct prpl *);
 	char *(*cfunc)();
+	struct prpl * new_prpl;
 	struct gaim_plugin_description *(*desc)();
 	GModule *handle;
 #endif
@@ -111,6 +114,25 @@
 						debug_printf("%s is unloadable: %s\n", file, g_module_error());
 						continue;
 					}
+					if (g_module_symbol(handle, "gaim_prpl_init", (gpointer *)&gaim_prpl_init)) {
+						plug = g_new0(struct gaim_plugin, 1);
+						g_snprintf(plug->path, sizeof(plug->path), path);
+						plug->type = plugin;
+
+						new_prpl = g_new0(struct prpl, 1);
+						new_prpl->plug = plug;
+						gaim_prpl_init(new_prpl);
+						if (new_prpl->protocol == PROTO_ICQ ||
+						    find_prpl(new_prpl->protocol)) {
+							/* Nothing to see here--move along, move along */
+							unload_protocol(new_prpl);
+							continue;
+						}
+						protocols = g_slist_insert_sorted(protocols, new_prpl, (GCompareFunc)proto_compare);
+						g_module_close(handle);
+						continue;
+					}
+					
 					if (!g_module_symbol(handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) {
 						debug_printf("%s is unloadable %s\n", file, g_module_error());
 						g_module_close(handle);
--- a/src/multi.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/multi.c	Mon Sep 30 01:05:18 2002 +0000
@@ -155,7 +155,7 @@
 {
 	struct prpl *p = find_prpl(proto);
 	if (p && p->name)
-		return p->name();
+		return p->name;
 	else
 		return "Unknown";
 }
@@ -396,7 +396,7 @@
 		if (!found)
 			count++;
 		if (e->name)
-			opt = gtk_menu_item_new_with_label(e->name());
+			opt = gtk_menu_item_new_with_label(e->name);
 		else
 			opt = gtk_menu_item_new_with_label("Unknown");
 		gtk_object_set_user_data(GTK_OBJECT(opt), u);
@@ -655,12 +655,12 @@
 	if (!p->user_opts)
 		return;
 
-	tmp = op = p->user_opts();
+	tmp = op = p->user_opts;
 
 	if (!op)
 		return;
 
-	g_snprintf(buf, sizeof(buf), "%s Options", p->name());
+	g_snprintf(buf, sizeof(buf), "%s Options", p->name);
 	u->proto_frame = gtk_frame_new(buf);
 	gtk_box_pack_start(GTK_BOX(box), u->proto_frame, FALSE, FALSE, 0);
 	gtk_widget_show(u->proto_frame);
@@ -693,8 +693,7 @@
 		gtk_widget_show(entry);
 
 		u->opt_entries = g_list_append(u->opt_entries, entry);
-
-		g_free(puo);
+		
 		op = op->next;
 	}
 
@@ -705,7 +704,6 @@
 		gtk_widget_show(u->register_user);
 	}
 
-	g_list_free(tmp);
 }
 
 static void show_acct_mod(struct aim_user *a)
@@ -1166,7 +1164,7 @@
 		return;
 	i = gtk_clist_find_row_from_data(GTK_CLIST(list), gc->user);
 	gtk_clist_set_text(GTK_CLIST(list), i, 1, "Yes");
-	gtk_clist_set_text(GTK_CLIST(list), i, 3, gc->prpl->name());
+	gtk_clist_set_text(GTK_CLIST(list), i, 3, gc->prpl->name);
 
 	return;
 }
@@ -1324,7 +1322,7 @@
 		meter->gc = gc;
 		meters = g_slist_append(meters, meter);
 
-		g_snprintf(buf, sizeof(buf), "%s Signing On (using %s)", gc->username, gc->prpl->name());
+		g_snprintf(buf, sizeof(buf), "%s Signing On (using %s)", gc->username, gc->prpl->name);
 	}
 
 	gtk_progress_bar_update(GTK_PROGRESS_BAR(meter->progress), howfar / LOGIN_STEPS);
--- a/src/perl.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/perl.c	Mon Sep 30 01:05:18 2002 +0000
@@ -550,7 +550,7 @@
 		{
 			struct gaim_connection *gc = (struct gaim_connection *)SvIV(ST(1));
 			if (g_slist_find(connections, gc))
-				XST_mPV(i++, gc->prpl->name());
+				XST_mPV(i++, gc->prpl->name);
 			else
 				XST_mPV(i++, "Unknown");
 		}
--- a/src/protocols/gg/gg.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/gg/gg.c	Mon Sep 30 01:05:18 2002 +0000
@@ -1,6 +1,6 @@
 /*
  * gaim - Gadu-Gadu Protocol Plugin
- * $Id: gg.c 3516 2002-08-29 01:47:15Z seanegan $
+ * $Id: gg.c 3670 2002-09-30 01:05:18Z seanegan $
  *
  * Copyright (C) 2001 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
  * 
@@ -99,10 +99,6 @@
 	int type;
 };
 
-static char *agg_name()
-{
-	return "Gadu-Gadu";
-}
 
 static gchar *charset_convert(const gchar *locstr, const char *encsrc, const char *encdst)
 {
@@ -308,20 +304,6 @@
 	return m;
 }
 
-static GList *agg_user_opts()
-{
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = _("Nick:");
-	puo->def = _("Gadu-Gadu User");
-	puo->pos = USEROPT_NICK;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 static void main_callback(gpointer data, gint source, GaimInputCondition cond)
 {
 	struct gaim_connection *gc = data;
@@ -1241,14 +1223,14 @@
 
 void gg_init(struct prpl *ret)
 {
+	struct proto_user_opt *puo;
 	ret->protocol = PROTO_GADUGADU;
 	ret->options = 0;
-	ret->name = agg_name;
+	ret->name = g_strdup("Gadu-Gadu");
 	ret->list_icon = agg_list_icon;
 	ret->away_states = agg_away_states;
 	ret->actions = agg_actions;
 	ret->do_action = agg_do_action;
-	ret->user_opts = agg_user_opts;
 	ret->buddy_menu = agg_buddy_menu;
 	ret->chat_info = NULL;
 	ret->login = agg_login;
@@ -1278,32 +1260,22 @@
 	ret->chat_send = NULL;
 	ret->keepalive = agg_keepalive;
 	ret->normalize = NULL;
+     
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup(_("Nick:"));
+	puo->def = g_strdup(_("Gadu-Gadu User"));
+	puo->pos = USEROPT_NICK;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
 	my_protocol = ret;
 }
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
-{
-	load_protocol(gg_init, sizeof(struct prpl));
-	return NULL;
-}
-
-void gaim_plugin_remove()
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	struct prpl *p = find_prpl(PROTO_GADUGADU);
-	if (p == my_protocol)
-		unload_protocol(p);
-}
-
-char *name()
-{
-	return "Gadu-Gadu";
-}
-
-char *description()
-{
-	return PRPL_DESC("Gadu-Gadu");
+	gg_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
 
 #endif
--- a/src/protocols/icq/gaim_icq.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/icq/gaim_icq.c	Mon Sep 30 01:05:18 2002 +0000
@@ -23,10 +23,6 @@
 
 static guint ack_timer = 0;
 
-static char *icq_name() {
-	return "ICQ";
-}
-
 static void icq_do_log(icq_Link *link, time_t time, unsigned char level, const char *log) {
 	debug_printf("ICQ debug %d: %s", level, log);
 }
@@ -474,19 +470,6 @@
 	return m;
 }
 
-static GList *icq_user_opts() {
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Nick:";
-	puo->def = "Gaim User";
-	puo->pos = USEROPT_NICK;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 static GList *icq_away_states(struct gaim_connection *gc) {
 	GList *m = NULL;
 
@@ -504,12 +487,12 @@
 static struct prpl *my_protocol = NULL;
 
 void icq_init(struct prpl *ret) {
+	struct proto_user_opt *puo;
 	ret->protocol = PROTO_ICQ;
-	ret->name = icq_name;
+	ret->name = g_strdup("ICQ");
 	ret->list_icon = icq_list_icon;
 	ret->away_states = icq_away_states;
 	ret->buddy_menu = icq_buddy_menu;
-	ret->user_opts = icq_user_opts;
 	ret->login = icq_login;
 	ret->close = icq_close;
 	ret->send_im = icq_send_msg;
@@ -520,6 +503,12 @@
 	ret->set_away = icq_set_away;
 	ret->keepalive = icq_keepalive;
 
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Nick:");
+	puo->def = g_strdup("Gaim User");
+	puo->pos = USEROPT_NICK;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
 	my_protocol = ret;
 
 	icq_SocketNotify = icq_sock_notify;
@@ -528,27 +517,9 @@
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	load_protocol(icq_init, sizeof(struct prpl));
-	return NULL;
-}
-
-void gaim_plugin_remove()
-{
-	struct prpl *p = find_prpl(PROTO_ICQ);
-	if (p == my_protocol)
-		unload_protocol(p);
+	icq_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
-
-char *name()
-{
-	return "ICQ";
-}
-
-char *description()
-{
-	return PRPL_DESC("ICQ");
-}
-
 #endif
--- a/src/protocols/irc/irc.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/irc/irc.c	Mon Sep 30 01:05:18 2002 +0000
@@ -101,11 +101,6 @@
 	return NULL;
 }
 
-static char *irc_name()
-{
-	return "IRC";
-}
-
 static int irc_write(int fd, char *data, int len)
 {
 	debug_printf("IRC C: %s", data);
@@ -1401,26 +1396,6 @@
 	g_free(gc->proto_data);
 }
 
-static GList *irc_user_opts()
-{
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Server:";
-	puo->def = "irc.openprojects.net";
-	puo->pos = USEROPT_SERV;
-	m = g_list_append(m, puo);
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Port:";
-	puo->def = "6667";
-	puo->pos = USEROPT_PORT;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 static void set_mode_3(struct gaim_connection *gc, char *who, int sign, int mode,
 			int start, int end, char *word[])
 {
@@ -1987,10 +1962,10 @@
 
 void irc_init(struct prpl *ret)
 {
+	struct proto_user_opt *puo;
 	ret->protocol = PROTO_IRC;
 	ret->options = OPT_PROTO_CHAT_TOPIC | OPT_PROTO_NO_PASSWORD;
-	ret->name = irc_name;
-	ret->user_opts = irc_user_opts;
+	ret->name = g_strdup("IRC");
 	ret->list_icon = irc_list_icon;
 	ret->login = irc_login;
 	ret->close = irc_close;
@@ -2007,32 +1982,28 @@
 	ret->buddy_menu = irc_buddy_menu;
 	ret->chat_invite = irc_chat_invite;
 	ret->convo_closed = irc_convo_closed;
-	my_protocol = ret;
+
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Server:");
+	puo->def = g_strdup("irc.openprojects.net");
+	puo->pos = USEROPT_SERV;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Port:");
+	puo->def = g_strdup("6667");
+	puo->pos = USEROPT_PORT;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
+       	my_protocol = ret;
 }
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
-{
-	load_protocol(irc_init, sizeof(struct prpl));
-	return NULL;
-}
-
-void gaim_plugin_remove()
+void *gaim_prpl_init(struct prpl* prpl)
 {
-	struct prpl *p = find_prpl(PROTO_IRC);
-	if (p == my_protocol)
-		unload_protocol(p);
-}
-
-char *name()
-{
-	return "IRC";
-}
-
-char *description()
-{
-	return PRPL_DESC("IRC");
+	irc_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
 
 #endif
--- a/src/protocols/jabber/jabber.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/jabber/jabber.c	Mon Sep 30 01:05:18 2002 +0000
@@ -225,11 +225,6 @@
 #define JCS_CLOSED  3	/* closed */
 
 
-static char *jabber_name()
-{
-	return "Jabber";
-}
-
 #define STATE_EVT(arg) if(gjc->on_state) { (gjc->on_state)(gjc, (arg) ); }
 
 static void jabber_handlevcard(gjconn, xmlnode, char *);
@@ -3193,20 +3188,6 @@
 	gjab_send_raw(jd->gjc, "  \t  ");
 }
 
-static GList *jabber_user_opts()
-{
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Port:";
-	puo->def = "5222";
-	puo->pos = USEROPT_PORT;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 /*---------------------------------------*/
 /* Jabber "set info" (vCard) support     */
 /*---------------------------------------*/
@@ -3982,16 +3963,16 @@
 void jabber_init(struct prpl *ret)
 {
 	/* the NULL's aren't required but they're nice to have */
+	struct proto_user_opt *puo;
 	ret->protocol = PROTO_JABBER;
 	ret->options = OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_CHAT_TOPIC;
-	ret->name = jabber_name;
+	ret->name = g_strdup("Jabber");
 	ret->list_icon = jabber_list_icon;
 	ret->away_states = jabber_away_states;
 	ret->actions = jabber_actions;
 	ret->do_action = jabber_do_action;
 	ret->buddy_menu = jabber_buddy_menu;
 	ret->edit_buddy_menu = jabber_edit_buddy_menu;
-	ret->user_opts = jabber_user_opts;
 	ret->login = jabber_login;
 	ret->close = jabber_close;
 	ret->send_im = jabber_send_im;
@@ -4028,33 +4009,22 @@
 	ret->send_typing = jabber_send_typing;
 	ret->convo_closed = jabber_convo_closed;
 	ret->rename_group = jabber_rename_group;
+       
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Port:");
+	puo->def = g_strdup("5222");
+	puo->pos = USEROPT_PORT;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
 
 	my_protocol = ret;
 }
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
-{
-	load_protocol(jabber_init, sizeof(struct prpl));
-	return NULL;
-}
-
-void gaim_plugin_remove()
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	struct prpl *p = find_prpl(PROTO_JABBER);
-	if (p == my_protocol)
-		unload_protocol(p);
-}
-
-char *name()
-{
-	return "Jabber";
-}
-
-char *description()
-{
-	return PRPL_DESC("Jabber");
+	jabber_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
 
 #endif
--- a/src/protocols/msn/msn.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/msn/msn.c	Mon Sep 30 01:05:18 2002 +0000
@@ -153,10 +153,6 @@
 			while (*(tmp) && isspace(*(tmp))) \
 				(tmp)++;
 
-static char *msn_name()
-{
-	return "MSN";
-}
 
 static char *msn_normalize(const char *s)
 {
@@ -2404,26 +2400,6 @@
 		g_free(b->proto_data);
 }
 
-static GList *msn_user_opts()
-{
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Server:";
-	puo->def = MSN_SERVER;
-	puo->pos = USEROPT_MSNSERVER;
-	m = g_list_append(m, puo);
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Port:";
-	puo->def = "1863";
-	puo->pos = USEROPT_MSNPORT;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 GSList *msn_smiley_list() 
 { 
 	GSList *smilies = NULL;
@@ -2530,9 +2506,10 @@
 
 void msn_init(struct prpl *ret)
 {
+	struct proto_user_opt *puo;
 	ret->protocol = PROTO_MSN;
 	ret->options = OPT_PROTO_MAIL_CHECK;
-	ret->name = msn_name;
+	ret->name = g_strdup("MSN");
 	ret->list_icon = msn_list_icon;
 	ret->buddy_menu = msn_buddy_menu;
 	ret->login = msn_login;
@@ -2559,17 +2536,28 @@
 	ret->rem_deny = msn_rem_deny;
 	ret->buddy_free = msn_buddy_free;
 	ret->smiley_list = msn_smiley_list;
-	ret->user_opts = msn_user_opts;
+
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Server:");
+	puo->def = g_strdup(MSN_SERVER);
+	puo->pos = USEROPT_MSNSERVER;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Port:");
+	puo->def = g_strdup("1863");
+	puo->pos = USEROPT_MSNPORT;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
 
 	my_protocol = ret;
 }
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	load_protocol(msn_init, sizeof(struct prpl));
-	return NULL;
+	msn_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
 
 void gaim_plugin_remove()
--- a/src/protocols/napster/napster.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/napster/napster.c	Mon Sep 30 01:05:18 2002 +0000
@@ -63,12 +63,6 @@
 	GSList *channels;
 };
 
-static char *nap_name()
-{
-	return "Napster";
-}
-
-
 /* FIXME: Make this use va_arg stuff */
 static void nap_write_packet(struct gaim_connection *gc, unsigned short command, const char *message)
 {
@@ -550,27 +544,6 @@
 	}
 }
 
-
-static GList *nap_user_opts()
-{
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Server:";
-	puo->def = NAP_SERVER;
-	puo->pos = USEROPT_NAPSERVER;
-	m = g_list_append(m, puo);
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Port:";
-	puo->def = "8888";
-	puo->pos = USEROPT_NAPPORT;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 static char** nap_list_icon(int uc)
 {
 	return napster_xpm;
@@ -580,10 +553,24 @@
 
 void napster_init(struct prpl *ret)
 {
+	struct proto_user_opt *puo;
+	ret->add_buddies = nap_add_buddies;
+	ret->remove_buddy = nap_remove_buddy;
+	ret->add_permit = NULL;
+	ret->rem_permit = NULL;
+	ret->add_deny = NULL;
+	ret->rem_deny = NULL;
+	ret->warn = NULL;
+	ret->chat_info = nap_chat_info;
+	ret->join_chat = nap_join_chat;
+	ret->chat_invite = NULL;
+	ret->chat_leave = nap_chat_leave;
+	ret->chat_whisper = NULL;
+	ret->chat_send = nap_chat_send;
+	ret->keepalive = NULL;
 	ret->protocol = PROTO_NAPSTER;
-	ret->name = nap_name;
+	ret->name = g_strdup("Napster");
 	ret->list_icon = nap_list_icon;
-	ret->user_opts = nap_user_opts;
 	ret->login = nap_login;
 	ret->close = nap_close;
 	ret->send_im = nap_send_im;
@@ -611,32 +598,26 @@
 	ret->chat_send = nap_chat_send;
 	ret->keepalive = NULL;
 
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Server:");
+	puo->def = g_strdup(NAP_SERVER);
+	puo->pos = USEROPT_NAPSERVER;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Port:");
+	puo->def = g_strdup("8888");
+	puo->pos = USEROPT_NAPPORT;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
 	my_protocol = ret;
 }
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule * handle)
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	load_protocol(napster_init, sizeof(struct prpl));
-	return NULL;
-}
-
-void gaim_plugin_remove()
-{
-	struct prpl *p = find_prpl(PROTO_NAPSTER);
-	if (p == my_protocol)
-		unload_protocol(p);
+	napster_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
-
-char *name()
-{
-	return "Napster";
-}
-
-char *description()
-{
-	return PRPL_DESC("Napster");
-}
-
 #endif
--- a/src/protocols/oscar/oscar.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/oscar/oscar.c	Mon Sep 30 01:05:18 2002 +0000
@@ -2723,10 +2723,6 @@
 	aim_flap_nop(odata->sess, odata->conn);
 }
 
-static char *oscar_name() {
-	return "AIM / ICQ";
-}
-
 static int oscar_send_typing(struct gaim_connection *gc, char *name, int typing) {
 	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
 	struct direct_im *dim = find_direct_im(odata, name);
@@ -3743,26 +3739,6 @@
 	return m;
 }
 
-static GList *oscar_user_opts()
-{
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Auth Host:";
-	puo->def = "login.oscar.aol.com";
-	puo->pos = USEROPT_AUTH;
-	m = g_list_append(m, puo);
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Auth Port:";
-	puo->def = "5190";
-	puo->pos = USEROPT_AUTHPORT;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 static void oscar_set_permit_deny(struct gaim_connection *gc) {
 	struct oscar_data *od = (struct oscar_data *)gc->proto_data;
 	if (od->icq) {
@@ -3983,16 +3959,16 @@
 static struct prpl *my_protocol = NULL;
 
 void oscar_init(struct prpl *ret) {
+	struct proto_user_opt *puo;
 	ret->protocol = PROTO_OSCAR;
 	ret->options = OPT_PROTO_BUDDY_ICON | OPT_PROTO_IM_IMAGE;
-	ret->name = oscar_name;
+	ret->name = g_strdup("Oscar");
 	ret->list_icon = oscar_list_icon;
 	ret->away_states = oscar_away_states;
 	ret->actions = oscar_actions;
 	ret->do_action = oscar_do_action;
 	ret->buddy_menu = oscar_buddy_menu;
 	ret->edit_buddy_menu = oscar_edit_buddy_menu;
-	ret->user_opts = oscar_user_opts;
 	ret->login = oscar_login;
 	ret->close = oscar_close;
 	ret->send_im = oscar_send_im;
@@ -4027,32 +4003,27 @@
 	ret->keepalive = oscar_keepalive;
 	ret->convo_closed = oscar_convo_closed;
 
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Auth Host:");
+	puo->def = g_strdup("login.oscar.aol.com");
+	puo->pos = USEROPT_AUTH;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Auth Port:");
+	puo->def = g_strdup("5190");
+	puo->pos = USEROPT_AUTHPORT;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
 	my_protocol = ret;
 }
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
-{
-	load_protocol(oscar_init, sizeof(struct prpl));
-	return NULL;
-}
-
-void gaim_plugin_remove()
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	struct prpl *p = find_prpl(PROTO_OSCAR);
-	if (p == my_protocol)
-		unload_protocol(p);
-}
-
-char *name()
-{
-	return "Oscar";
-}
-
-char *description()
-{
-	return PRPL_DESC("Oscar");
+	oscar_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
 
 #endif
--- a/src/protocols/toc/toc.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/toc/toc.c	Mon Sep 30 01:05:18 2002 +0000
@@ -927,11 +927,6 @@
 	}
 }
 
-static char *toc_name()
-{
-	return "TOC";
-}
-
 static int toc_send_im(struct gaim_connection *gc, char *name, char *message, int len, int flags)
 {
 	char buf[BUF_LEN * 2];
@@ -1230,26 +1225,6 @@
 	return m;
 }
 
-static GList *toc_user_opts()
-{
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "TOC Host:";
-	puo->def = "toc.oscar.aol.com";
-	puo->pos = USEROPT_AUTH;
-	m = g_list_append(m, puo);
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "TOC Port:";
-	puo->def = "9898";
-	puo->pos = USEROPT_AUTHPORT;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 static void toc_add_permit(struct gaim_connection *gc, char *who)
 {
 	char buf2[BUF_LEN * 2];
@@ -1382,16 +1357,16 @@
 static struct prpl *my_protocol = NULL;
 
 void toc_init(struct prpl *ret)
-{
+{	
+	struct proto_user_opt *puo;
 	ret->protocol = PROTO_TOC;
 	ret->options = OPT_PROTO_CORRECT_TIME;
-	ret->name = toc_name;
+	ret->name = g_strdup("TOC");
 	ret->list_icon = toc_list_icon;
 	ret->away_states = toc_away_states;
 	ret->actions = toc_actions;
 	ret->do_action = toc_do_action;
 	ret->buddy_menu = toc_buddy_menu;
-	ret->user_opts = toc_user_opts;
 	ret->login = toc_login;
 	ret->close = toc_close;
 	ret->send_im = toc_send_im;
@@ -1421,32 +1396,27 @@
 	ret->chat_send = toc_chat_send;
 	ret->keepalive = toc_keepalive;
 
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("TOC Host:");
+	puo->def = g_strdup("toc.oscar.aol.com");
+	puo->pos = USEROPT_AUTH;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("TOC Port:");
+	puo->def = g_strdup("9898");
+	puo->pos = USEROPT_AUTHPORT;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
 	my_protocol = ret;
 }
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
-{
-	load_protocol(toc_init, sizeof(struct prpl));
-	return NULL;
-}
-
-void gaim_plugin_remove()
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	struct prpl *p = find_prpl(PROTO_TOC);
-	if (p == my_protocol)
-		unload_protocol(p);
-}
-
-char *name()
-{
-	return "TOC";
-}
-
-char *description()
-{
-	return PRPL_DESC("TOC");
+	toc_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
 
 #endif
--- a/src/protocols/yahoo/yahoo.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/yahoo/yahoo.c	Mon Sep 30 01:05:18 2002 +0000
@@ -173,10 +173,6 @@
 	GSList *hash;
 };
 
-static char *yahoo_name() {
-	return "Yahoo";
-}
-
 #define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4)
 
 static struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id)
@@ -1128,26 +1124,6 @@
 	return m;
 }
 
-static GList *yahoo_user_opts()
-{
-	GList *m = NULL;
-	struct proto_user_opt *puo;
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Pager Host:";
-	puo->def = YAHOO_PAGER_HOST;
-	puo->pos = USEROPT_PAGERHOST;
-	m = g_list_append(m, puo);
-
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = "Pager Port:";
-	puo->def = "5050";
-	puo->pos = USEROPT_PAGERPORT;
-	m = g_list_append(m, puo);
-
-	return m;
-}
-
 static void yahoo_act_id(gpointer data, char *entry)
 {
 	struct gaim_connection *gc = data;
@@ -1435,10 +1411,10 @@
 static struct prpl *my_protocol = NULL;
 
 void yahoo_init(struct prpl *ret) {
+	struct proto_user_opt *puo;
 	ret->protocol = PROTO_YAHOO;
 	ret->options = OPT_PROTO_MAIL_CHECK;
-	ret->name = yahoo_name;
-	ret->user_opts = yahoo_user_opts;
+	ret->name = g_strdup("Yahoo");
 	ret->login = yahoo_login;
 	ret->close = yahoo_close;
 	ret->buddy_menu = yahoo_buddy_menu;
@@ -1455,32 +1431,27 @@
 	ret->send_typing = yahoo_send_typing;
 	ret->smiley_list = yahoo_smiley_list;
 
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Pager Host:");
+	puo->def = g_strdup(YAHOO_PAGER_HOST);
+	puo->pos = USEROPT_PAGERHOST;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
+	puo = g_new0(struct proto_user_opt, 1);
+	puo->label = g_strdup("Pager Port:");
+	puo->def = g_strdup("5050");
+	puo->pos = USEROPT_PAGERPORT;
+	ret->user_opts = g_list_append(ret->user_opts, puo);
+
 	my_protocol = ret;
 }
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
-{
-	load_protocol(yahoo_init, sizeof(struct prpl));
-	return NULL;
-}
-
-void gaim_plugin_remove()
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	struct prpl *p = find_prpl(PROTO_YAHOO);
-	if (p == my_protocol)
-		unload_protocol(p);
-}
-
-char *name()
-{
-	return "Yahoo";
-}
-
-char *description()
-{
-	return PRPL_DESC("Yahoo");
+	yahoo_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
 
 #endif
--- a/src/protocols/zephyr/zephyr.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/protocols/zephyr/zephyr.c	Mon Sep 30 01:05:18 2002 +0000
@@ -62,11 +62,6 @@
 	int id;
 };
 
-static char *zephyr_name()
-{
-	return "Zephyr";
-}
-
 #define z_call(func)		if (func != ZERR_NONE)\
 					return;
 #define z_call_r(func)		if (func != ZERR_NONE)\
@@ -945,7 +940,7 @@
 {
 	ret->protocol = PROTO_ZEPHYR;
 	ret->options = OPT_PROTO_NO_PASSWORD;
-	ret->name = zephyr_name;
+	ret->name = g_strdup("Zephyr");
 	ret->login = zephyr_login;
 	ret->close = zephyr_close;
 	ret->add_buddy = zephyr_add_buddy;
@@ -966,27 +961,11 @@
 
 #ifndef STATIC
 
-char *gaim_plugin_init(GModule *handle)
+void *gaim_prpl_init(struct prpl *prpl)
 {
-	load_protocol(zephyr_init, sizeof(struct prpl));
-	return NULL;
+	zephyr_init(prpl);
+	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
 }
 
-void gaim_plugin_remove()
-{
-	struct prpl *p = find_prpl(PROTO_ZEPHYR);
-	if (p == my_protocol)
-		unload_protocol(p);
-}
-
-char *name()
-{
-	return "Zephyr";
-}
-
-char *description()
-{
-	return PRPL_DESC("Zephyr");
-}
 
 #endif
--- a/src/prpl.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/prpl.c	Mon Sep 30 01:05:18 2002 +0000
@@ -32,6 +32,7 @@
 GSList *protocols = NULL;
 
 GtkWidget *protomenu = NULL;
+int prpl_accounts[PROTO_UNTAKEN];
 
 struct _prompt {
 	GtkWidget *window;
@@ -56,30 +57,39 @@
 	return NULL;
 }
 
-static gint proto_compare(struct prpl *a, struct prpl *b)
+gint proto_compare(struct prpl *a, struct prpl *b)
 {
 	/* neg if a before b, 0 if equal, pos if a after b */
 	return a->protocol - b->protocol;
 }
 
-void load_protocol(proto_init pi, int size)
+#ifdef GAIM_PLUGINS
+gboolean load_prpl(struct prpl *p)
+{
+	char *(*gaim_prpl_init)(struct prpl *);
+	debug_printf("Loading protocol %d\n", p->protocol);
+
+	if (!p->plug)
+		return TRUE;
+	
+	p->plug->handle = g_module_open(p->plug->path, 0);
+	if (!p->plug->handle) {
+		debug_printf("%s is unloadable: %s\n", p->plug->path, g_module_error());
+		return TRUE;
+	}
+
+	if (!g_module_symbol(p->plug->handle, "gaim_prpl_init", (gpointer *)&gaim_prpl_init)) {
+		return TRUE;
+	}
+
+	gaim_prpl_init(p);
+	return FALSE;
+}
+#endif
+
+void load_protocol(proto_init pi)
 {
 	struct prpl *p;
-	struct prpl *old;
-	if (size != sizeof(struct prpl)) {
-		do_error_dialog(_("Incompatible protocol detected."),
-				_("You have attempted to load a protocol which was not compiled"
-				  " from the same version of the source as this application was."
-				  " Unfortunately, because it is not the same version I cannot"
-				  " safely tell you which one it was. Needless to say, it was not"
-				  " successfully loaded."), GAIM_ERROR);
-		return;
-	}
-	
-	p = g_new0(struct prpl, 1);
-	pi(p);
-	if ((old = find_prpl(p->protocol)) != NULL)
-		unload_protocol(old);
 
 	if (p->protocol == PROTO_ICQ) 
 		do_error_dialog(_("Libicq.so detected."),
@@ -89,31 +99,26 @@
 				  "It is reccomended that you use the AIM/ICQ protocol to connect to ICQ"),
 				GAIM_WARNING);
 
-
 	protocols = g_slist_insert_sorted(protocols, p, (GCompareFunc)proto_compare);
 	regenerate_user_list();
 }
 
 void unload_protocol(struct prpl *p)
 {
-	GSList *c = connections;
-	struct gaim_connection *g;
+	GList *c;
+	struct proto_user_opt *puo;
+	if (p->name)
+		g_free(p->name);
+	c = p->user_opts;
 	while (c) {
-		g = (struct gaim_connection *)c->data;
-		if (g->prpl == p) {
-			char buf[256];
-			g_snprintf(buf, sizeof buf, _("%s was using %s, which got removed."
-						      " %s is now offline."), g->username,
-				   p->name(), g->username);
-			do_error_dialog(buf, NULL, GAIM_ERROR);
-			signoff(g);
-			c = connections;
-		} else
-			c = c->next;
+		puo = c->data;
+		g_free(puo->label);
+		g_free(puo->def);
+		g_free(puo);
+		c = c->next;
 	}
-	protocols = g_slist_remove(protocols, p);
-	g_free(p);
-	regenerate_user_list();
+	g_list_free(p->user_opts);
+	p->user_opts = NULL;
 }
 
 STATIC_PROTO_INIT
@@ -321,7 +326,7 @@
 				continue;
 			}
 
-			g_snprintf(buf, sizeof(buf), "%s (%s)", gc->username, gc->prpl->name());
+			g_snprintf(buf, sizeof(buf), "%s (%s)", gc->username, gc->prpl->name);
 			menuitem = gtk_menu_item_new_with_label(buf);
 			gtk_menu_append(GTK_MENU(protomenu), menuitem);
 			gtk_widget_show(menuitem);
--- a/src/prpl.h	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/prpl.h	Mon Sep 30 01:05:18 2002 +0000
@@ -41,6 +41,8 @@
 #define PROTO_NAPSTER	9
 #define PROTO_ZEPHYR   10
 #define PROTO_GADUGADU 11
+#define PROTO_UNTAKEN  17
+
 /* DON'T TAKE AN UNASSIGNED NUMBER! Talk to Rob or Sean if you'd like
  * to create a new PRPL. */
 
@@ -86,7 +88,8 @@
 struct prpl {
 	int protocol;
 	int options;
-	char *(* name)();
+	struct gaim_plugin *plug;
+	char *name;
 
 	/* for ICQ and Yahoo, who have off/on per-conversation options */
 	/* char *checkbox; this should be per-connection */
@@ -96,8 +99,8 @@
 	GList *(* away_states)(struct gaim_connection *gc);
 	GList *(* actions)();
 	void   (* do_action)(struct gaim_connection *, char *);
-	/* user_opts returns a GList* of g_malloc'd struct proto_user_opts */
-	GList *(* user_opts)();
+	/* user_opts is a GList* of g_malloc'd struct proto_user_opts */
+	GList *user_opts;
 	GList *(* buddy_menu)(struct gaim_connection *, char *);
 	GList *(* edit_buddy_menu)(struct gaim_connection *, char *);
 	GList *(* chat_info)(struct gaim_connection *);
@@ -180,13 +183,16 @@
 };
 
 extern GSList *protocols;
+extern prpl_accounts[];
 
 /* this is mostly just for aim.c, when it initializes the protocols */
 extern void static_proto_init();
 
 /* this is what should actually load the protocol. pass it the protocol's initializer */
-extern void load_protocol(proto_init, int);
+extern gboolean load_prpl(struct prpl *);
+extern void load_protocol(proto_init);
 extern void unload_protocol(struct prpl *);
+extern gint proto_compare(struct prpl *, struct prpl *);
 
 extern struct prpl *find_prpl(int);
 extern void do_proto_menu();
--- a/src/server.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/server.c	Mon Sep 30 01:05:18 2002 +0000
@@ -47,13 +47,25 @@
 	if (user->gc != NULL)
 		return;
 
+#ifdef GAIM_PLUGINS
+	if (p->plug) { /* This protocol is a plugin */
+		prpl_accounts[p->protocol]++;
+		debug_printf("Protocol %s is now being used by %d connections.\n", p->name, prpl_accounts[p->protocol]);
+		if (!p->plug->handle) { /* But the protocol isn't yet loaded. */
+			unload_protocol(p); /* Unload it to free the old name and options */
+			if (load_prpl(p)) /* And load the plugin */
+				return;
+		}
+	}
+#endif
+
 	if (p && p->login) {
 		if (!strlen(user->password) && !(p->options & OPT_PROTO_NO_PASSWORD)) {
 			do_error_dialog(_("Please enter your password"), NULL, GAIM_ERROR);
 			return;
 		}
 
-		debug_printf(PACKAGE " " VERSION " logging in %s using %s\n", user->username, p->name());
+		debug_printf(PACKAGE " " VERSION " logging in %s using %s\n", user->username, p->name);
 		user->connecting = TRUE;
 		connecting_count++;
 		debug_printf("connecting_count: %d\n", connecting_count);
@@ -84,6 +96,7 @@
 
 void serv_close(struct gaim_connection *gc)
 {
+	struct prpl *prpl;
 	while (gc->buddy_chats) {
 		struct conversation *b = gc->buddy_chats->data;
 		gc->buddy_chats = g_slist_remove(gc->buddy_chats, b);
@@ -99,9 +112,23 @@
 
 	if (gc->prpl && gc->prpl->close)
 		gc->prpl->close(gc);
-
+	
+	prpl = gc->prpl;
 	account_offline(gc);
 	destroy_gaim_conn(gc);
+
+#ifdef GAIM_PLUGINS
+	if (prpl->plug) { /* This is a plugin */
+		prpl_accounts[prpl->protocol]--;
+		debug_printf("Prpl %s is now being used by %d accounts\n", prpl->name, prpl_accounts[prpl->protocol]);
+		if (prpl_accounts[prpl->protocol] == 0) { /* We don't need this protocol anymore */
+			debug_printf("Throwing out prpl %s\n", prpl->name);
+			g_module_close(prpl->plug->handle);
+			prpl->plug->handle = NULL;
+		}
+	}
+#endif
+		
 }
 
 void serv_touch_idle(struct gaim_connection *gc)
--- a/src/util.c	Sun Sep 29 17:00:14 2002 +0000
+++ b/src/util.c	Mon Sep 30 01:05:18 2002 +0000
@@ -1002,32 +1002,32 @@
 		switch (what) {
 		case log_signon:
 			g_snprintf(text, sizeof(text), "+++ %s (%s) signed on @ %s",
-				   gc->username, gc->prpl->name(), full_date());
+				   gc->username, gc->prpl->name, full_date());
 			g_snprintf(html, sizeof(html), "<B>%s</B>", text);
 			break;
 		case log_signoff:
 			g_snprintf(text, sizeof(text), "+++ %s (%s) signed off @ %s",
-				   gc->username, gc->prpl->name(), full_date());
+				   gc->username, gc->prpl->name, full_date());
 			g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
 			break;
 		case log_away:
 			g_snprintf(text, sizeof(text), "+++ %s (%s) changed away state @ %s",
-				   gc->username, gc->prpl->name(), full_date());
+				   gc->username, gc->prpl->name, full_date());
 			g_snprintf(html, sizeof(html), "<FONT COLOR=OLIVE>%s</FONT>", text);
 			break;
 		case log_back:
 			g_snprintf(text, sizeof(text), "+++ %s (%s) came back @ %s",
-				   gc->username, gc->prpl->name(), full_date());
+				   gc->username, gc->prpl->name, full_date());
 			g_snprintf(html, sizeof(html), "%s", text);
 			break;
 		case log_idle:
 			g_snprintf(text, sizeof(text), "+++ %s (%s) became idle @ %s",
-				   gc->username, gc->prpl->name(), full_date());
+				   gc->username, gc->prpl->name, full_date());
 			g_snprintf(html, sizeof(html), "<FONT COLOR=GRAY>%s</FONT>", text);
 			break;
 		case log_unidle:
 			g_snprintf(text, sizeof(text), "+++ %s (%s) returned from idle @ %s",
-				   gc->username, gc->prpl->name(), full_date());
+				   gc->username, gc->prpl->name, full_date());
 			g_snprintf(html, sizeof(html), "%s", text);
 			break;
 		case log_quit:
@@ -1039,33 +1039,33 @@
 		switch (what) {
 		case log_signon:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s (%s) signed on @ %s",
-				   gc->username, gc->prpl->name(), who->show, who->name, full_date());
+				   gc->username, gc->prpl->name, who->show, who->name, full_date());
 			g_snprintf(html, sizeof(html), "<B>%s</B>", text);
 			break;
 		case log_signoff:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s (%s) signed off @ %s",
-				   gc->username, gc->prpl->name(), who->show, who->name, full_date());
+				   gc->username, gc->prpl->name, who->show, who->name, full_date());
 			g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
 			break;
 		case log_away:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s (%s) went away @ %s",
-				   gc->username, gc->prpl->name(), who->show, who->name, full_date());
+				   gc->username, gc->prpl->name, who->show, who->name, full_date());
 			g_snprintf(html, sizeof(html), "<FONT COLOR=OLIVE>%s</FONT>", text);
 			break;
 		case log_back:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s (%s) came back @ %s",
-				   gc->username, gc->prpl->name(), who->show, who->name, full_date());
+				   gc->username, gc->prpl->name, who->show, who->name, full_date());
 			g_snprintf(html, sizeof(html), "%s", text);
 			break;
 		case log_idle:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s (%s) became idle @ %s",
-				   gc->username, gc->prpl->name(), who->show, who->name, full_date());
+				   gc->username, gc->prpl->name, who->show, who->name, full_date());
 			g_snprintf(html, sizeof(html), "<FONT COLOR=GRAY>%s</FONT>", text);
 			break;
 		case log_unidle:
 			g_snprintf(text, sizeof(text),
 				   "%s (%s) reported that %s (%s) returned from idle @ %s", gc->username,
-				   gc->prpl->name(), who->show, who->name, full_date());
+				   gc->prpl->name, who->show, who->name, full_date());
 			g_snprintf(html, sizeof(html), "%s", text);
 			break;
 		default:
@@ -1077,33 +1077,33 @@
 		switch (what) {
 		case log_signon:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s signed on @ %s",
-				   gc->username, gc->prpl->name(), who->name, full_date());
+				   gc->username, gc->prpl->name, who->name, full_date());
 			g_snprintf(html, sizeof(html), "<B>%s</B>", text);
 			break;
 		case log_signoff:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s signed off @ %s",
-				   gc->username, gc->prpl->name(), who->name, full_date());
+				   gc->username, gc->prpl->name, who->name, full_date());
 			g_snprintf(html, sizeof(html), "<I><FONT COLOR=GRAY>%s</FONT></I>", text);
 			break;
 		case log_away:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s went away @ %s",
-				   gc->username, gc->prpl->name(), who->name, full_date());
+				   gc->username, gc->prpl->name, who->name, full_date());
 			g_snprintf(html, sizeof(html), "<FONT COLOR=OLIVE>%s</FONT>", text);
 			break;
 		case log_back:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s came back @ %s",
-				   gc->username, gc->prpl->name(), who->name, full_date());
+				   gc->username, gc->prpl->name, who->name, full_date());
 			g_snprintf(html, sizeof(html), "%s", text);
 			break;
 		case log_idle:
 			g_snprintf(text, sizeof(text), "%s (%s) reported that %s became idle @ %s",
-				   gc->username, gc->prpl->name(), who->name, full_date());
+				   gc->username, gc->prpl->name, who->name, full_date());
 			g_snprintf(html, sizeof(html), "<FONT COLOR=GRAY>%s</FONT>", text);
 			break;
 		case log_unidle:
 			g_snprintf(text, sizeof(text),
 				   "%s (%s) reported that %s returned from idle @ %s", gc->username,
-				   gc->prpl->name(), who->name, full_date());
+				   gc->prpl->name, who->name, full_date());
 			g_snprintf(html, sizeof(html), "%s", text);
 			break;
 		default: