Index: account.c
===================================================================
--- account.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ account.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -28,5 +28,5 @@
 #include "account.h"
 
-account_t *account_add( irc_t *irc, int protocol, char *user, char *pass )
+account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
 {
 	account_t *a;
@@ -42,5 +42,5 @@
 	}
 	
-	a->protocol = protocol;
+	a->prpl = prpl;
 	a->user = g_strdup( user );
 	a->pass = g_strdup( pass );
@@ -66,5 +66,5 @@
 	for( a = irc->accounts; a; a = a->next )
 	{
-		if( g_strcasecmp( id, proto_name[a->protocol] ) == 0 )
+		if( g_strcasecmp( id, a->prpl->name ) == 0 )
 		{
 			if( !ret )
@@ -124,7 +124,7 @@
 	}
 	
-	if( proto_prpl[a->protocol]->login == NULL )
+	if (a->prpl == NULL )
 	{
-		irc_usermsg( irc, "Support for protocol %s is not included in this BitlBee", proto_name[a->protocol] );
+		irc_usermsg( irc, "Support for protocol %s is not included in this BitlBee", a->prpl->name );
 		return;
 	}
@@ -134,5 +134,5 @@
 	u = g_new0 ( struct aim_user, 1 );
 	u->irc = irc;
-	u->protocol = a->protocol;
+	u->prpl = a->prpl;
 	strncpy( u->username, a->user, sizeof( u->username ) - 1 );
 	strncpy( u->password, a->pass, sizeof( u->password ) - 1 );
@@ -142,5 +142,5 @@
 	a->reconnect = 0;
 	
-	proto_prpl[a->protocol]->login( u );
+	a->prpl->login( u );
 }
 
Index: account.h
===================================================================
--- account.h	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ account.h	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -29,5 +29,5 @@
 typedef struct account
 {
-	int protocol;
+	struct prpl *prpl;
 	char *user;
 	char *pass;
@@ -41,5 +41,5 @@
 } account_t;
 
-account_t *account_add( irc_t *irc, int protocol, char *user, char *pass );
+account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass );
 account_t *account_get( irc_t *irc, char *id );
 void account_del( irc_t *irc, account_t *acc );
Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ bitlbee.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -236,9 +236,24 @@
 }
 
+/* DO NOT USE THIS FUNCTION IN NEW CODE. This 
+ * function is here merely because the save/load code still uses 
+ * ids rather then names */
+struct prpl *find_protocol_by_id(int id)
+{
+	switch (id) {
+	case 1: return find_protocol("oscar");
+	case 4: return find_protocol("msn");
+	case 2: return find_protocol("yahoo");
+	case 8: return find_protocol("jabber");
+	default: break;
+	}
+	return NULL;
+}
+
 int bitlbee_load( irc_t *irc, char* password )
 {
 	char s[512];
 	char *line;
-	int proto;
+	char proto[20];
 	char nick[MAX_NICK_LENGTH+1];
 	FILE *fp;
@@ -275,8 +290,20 @@
 	fp = fopen( s, "r" );
 	if( !fp ) return( 0 );
-	while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 )
-	{
+	while( fscanf( fp, "%s %s %s", s, proto, nick ) > 0 )
+	{
+		struct prpl *prpl;
+
+		prpl = find_protocol(proto);
+
+		/* Older files saved the protocol number rather then the protocol name */
+		if (!prpl && atoi(proto)) {
+			prpl = find_protocol_by_id(atoi(proto));
+		}
+
+		if (!prpl)
+			continue;
+
 		http_decode( s );
-		nick_set( irc, s, proto, nick );
+		nick_set( irc, s, prpl, nick );
 	}
 	fclose( fp );
@@ -333,5 +360,5 @@
 		s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
 		http_encode( s );
-		g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", n->proto, n->nick );
+		g_snprintf( s + strlen( s ), 510 - strlen( s ), " %s %s", n->proto->name, n->nick );
 		if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
 		{
@@ -375,9 +402,9 @@
 	for( a = irc->accounts; a; a = a->next )
 	{
-		if( a->protocol == PROTO_OSCAR || a->protocol == PROTO_ICQ || a->protocol == PROTO_TOC )
+		if( !strcmp( a->prpl->name, "oscar" ) )
 			g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
 		else
 			g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
-			            proto_name[a->protocol], a->user, a->pass, a->server ? a->server : "" );
+			            a->prpl->name, a->user, a->pass, a->server ? a->server : "" );
 		
 		line = obfucrypt( irc, s );
Index: commands.c
===================================================================
--- commands.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ commands.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -184,5 +184,5 @@
 	if( g_strcasecmp( cmd[1], "add" ) == 0 )
 	{
-		int prot;
+		struct prpl *prpl;
 		
 		if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL )
@@ -192,9 +192,7 @@
 		}
 		
-		for( prot = 0; prot < PROTO_MAX; prot ++ )
-			if( proto_name[prot] && *proto_name[prot] && g_strcasecmp( proto_name[prot], cmd[2] ) == 0 )
-				break;
-		
-		if( ( prot == PROTO_MAX ) || ( proto_prpl[prot] == NULL ) )
+		prpl = find_protocol(cmd[2]);
+		
+		if( prpl == NULL )
 		{
 			irc_usermsg( irc, "Unknown protocol" );
@@ -202,11 +200,5 @@
 		}
 
-		if( prot == PROTO_OSCAR && cmd[5] == NULL )
-		{
-			irc_usermsg( irc, "Not enough parameters" );
-			return( 0 );
-		}
-		
-		a = account_add( irc, prot, cmd[3], cmd[4] );
+		a = account_add( irc, prpl, cmd[3], cmd[4] );
 		
 		if( cmd[5] )
@@ -252,8 +244,5 @@
 				con = "";
 			
-			if( a->protocol == PROTO_OSCAR || a->protocol == PROTO_ICQ || a->protocol == PROTO_TOC )
-				irc_usermsg( irc, "%2d. OSCAR, %s on %s%s", i, a->user, a->server, con );
-			else
-				irc_usermsg( irc, "%2d. %s, %s%s", i, proto_name[a->protocol], a->user, con );
+			irc_usermsg( irc, "%2d. %s, %s%s", i, a->prpl->name, a->user, con );
 			
 			i ++;
@@ -372,5 +361,5 @@
 		else
 		{
-			nick_set( irc, cmd[2], a->gc->protocol, cmd[3] );
+			nick_set( irc, cmd[2], a->gc->prpl, cmd[3] );
 		}
 	}
@@ -453,5 +442,5 @@
 	else if( u->send_handler == buddy_send_handler )
 	{
-		nick_set( irc, u->handle, u->gc->protocol, cmd[2] );
+		nick_set( irc, u->handle, u->gc->prpl, cmd[2] );
 	}
 	
@@ -664,5 +653,5 @@
 	if( online == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && !u->away )
 	{
-		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, proto_name[u->gc->user->protocol] );
+		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
 		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, "Online" );
 		n_online ++;
@@ -671,5 +660,5 @@
 	if( away == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && u->away )
 	{
-		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, proto_name[u->gc->user->protocol] );
+		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
 		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, u->away );
 		n_away ++;
@@ -678,5 +667,5 @@
 	if( offline == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && !u->online )
 	{
-		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, proto_name[u->gc->user->protocol] );
+		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
 		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, "Offline" );
 		n_offline ++;
@@ -739,5 +728,5 @@
 	for( num = 0; q; q = q->next, num ++ )
 		if( q->gc ) /* Not necessary yet, but it might come later */
-			irc_usermsg( irc, "%d, %s(%s): %s", num, proto_name[q->gc->protocol], q->gc->username, q->question );
+			irc_usermsg( irc, "%d, %s(%s): %s", num, q->gc->prpl->name, q->gc->username, q->question );
 		else
 			irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
@@ -787,5 +776,5 @@
 	for( n = gc->irc->nicks; n; n = n->next )
 	{
-		if( n->proto == gc->protocol && !user_findhandle( gc, n->handle ) )
+		if( n->proto == gc->prpl && !user_findhandle( gc, n->handle ) )
 		{
 	                gc->prpl->add_buddy( gc, n->handle );
Index: configure
===================================================================
--- configure	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ configure	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -14,4 +14,5 @@
 datadir='$prefix/share/bitlbee/'
 config='/var/lib/bitlbee/'
+plugindir='$prefix/lib/bitlbee'
 
 msn=1
@@ -45,4 +46,5 @@
 --mandir=...						$mandir
 --datadir=...						$datadir
+--plugindir=...						$plugindir
 --config=...						$config
 
@@ -73,4 +75,5 @@
 datadir=`eval echo "$datadir/" | sed 's/\/\{1,\}/\//g'`
 config=`eval echo "$config/" | sed 's/\/\{1,\}/\//g'`
+plugindir=`eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g'`
 
 cat<<EOF>Makefile.settings
@@ -81,4 +84,5 @@
 MANDIR=$mandir
 DATADIR=$datadir
+PLUGINDIR=$plugindir
 CONFIG=$config
 
@@ -101,4 +105,5 @@
 #define ETCDIR "$etcdir"
 #define VARDIR "$datadir"
+#define PLUGINDIR "$plugindir"
 #define ARCH "$arch"
 #define CPU "$cpu"
@@ -141,6 +146,6 @@
 if type pkg-config > /dev/null 2>/dev/null && pkg-config glib-2.0; then
 	cat<<EOF>>Makefile.settings
-EFLAGS+=`pkg-config --libs glib-2.0`
-CFLAGS+=`pkg-config --cflags glib-2.0`
+EFLAGS+=`pkg-config --libs glib-2.0 gmodule-2.0`
+CFLAGS+=`pkg-config --cflags glib-2.0 gmodule-2.0`
 EOF
 	echo '#define GLIB2' >> config.h
Index: doc/example_plugin.c
===================================================================
--- doc/example_plugin.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
+++ doc/example_plugin.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -0,0 +1,13 @@
+/* 
+ * This is the most simple possible BitlBee plugin. To use, compile it as 
+ * a shared library and place it in the plugin directory: 
+ *
+ * gcc -o example.so -shared example.c
+ * cp example.so /usr/local/lib/bitlbee
+ */
+#include <stdio.h>
+
+void init_plugin(void)
+{
+	printf("I am a BitlBee plugin!\n");
+}
Index: irc.c
===================================================================
--- irc.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ irc.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -1165,5 +1165,5 @@
 		if( u->gc )
 			irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->user->username,
-			           *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", proto_name[u->gc->user->protocol] );
+			           *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", u->gc->prpl->name );
 		else
 			irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
Index: nick.c
===================================================================
--- nick.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ nick.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -27,5 +27,5 @@
 #include "bitlbee.h"
 
-void nick_set( irc_t *irc, char *handle, int proto, char *nick )
+void nick_set( irc_t *irc, char *handle, struct prpl *proto, char *nick )
 {
 	nick_t *m = NULL, *n = irc->nicks;
@@ -56,5 +56,5 @@
 }
 
-char *nick_get( irc_t *irc, char *handle, int proto, const char *realname )
+char *nick_get( irc_t *irc, char *handle, struct prpl *proto, const char *realname )
 {
 	static char nick[MAX_NICK_LENGTH+1];
Index: nick.h
===================================================================
--- nick.h	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ nick.h	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -27,11 +27,11 @@
 {
 	char *handle;
-	int proto;
+	struct prpl *proto;
 	char *nick;
 	struct __NICK *next;
 } nick_t;
 
-void nick_set( irc_t *irc, char *handle, int proto, char *nick );
-char *nick_get( irc_t *irc, char *handle, int proto, const char *realname );
+void nick_set( irc_t *irc, char *handle, struct prpl *proto, char *nick );
+char *nick_get( irc_t *irc, char *handle, struct prpl *proto, const char *realname );
 void nick_del( irc_t *irc, char *nick );
 void nick_strip( char *nick );
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ protocols/jabber/jabber.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -157,9 +157,4 @@
 #define JCS_CLOSED  3	/* closed */
 
-
-static char *jabber_name()
-{
-	return "Jabber";
-}
 
 #define STATE_EVT(arg) if(gjc->on_state) { (gjc->on_state)(gjc, (arg) ); }
@@ -2365,11 +2360,11 @@
 }
 
-static struct prpl *my_protocol = NULL;
-
-void jabber_init(struct prpl *ret)
-{
+
+void jabber_init()
+{
+	struct prpl *ret = g_new0(struct prpl, 1);
+
 	/* the NULL's aren't required but they're nice to have */
-	ret->protocol = PROTO_JABBER;
-	ret->name = jabber_name;
+	ret->name = "jabber";
 	ret->away_states = jabber_away_states;
 	ret->actions = jabber_actions;
@@ -2395,4 +2390,4 @@
 	ret->cmp_buddynames = g_strcasecmp;
 
-	my_protocol = ret;
-}
+	register_protocol (ret);
+}
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ protocols/msn/msn.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -26,6 +26,4 @@
 #include "nogaim.h"
 #include "msn.h"
-
-static struct prpl *my_protocol = NULL;
 
 static void msn_login( struct aim_user *acct )
@@ -375,7 +373,8 @@
 }
 
-void msn_init(struct prpl *ret)
-{
-	ret->protocol = PROTO_MSN;
+void msn_init()
+{
+	struct prpl *ret = g_new0(struct prpl, 1);
+	ret->name = "msn";
 	ret->login = msn_login;
 	ret->close = msn_close;
@@ -400,4 +399,4 @@
 	ret->cmp_buddynames = g_strcasecmp;
 
-	my_protocol = ret;
-}
+	register_protocol(ret);
+}
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ protocols/nogaim.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -39,7 +39,4 @@
 #include <iconv.h>
 
-struct prpl *proto_prpl[PROTO_MAX];
-char proto_name[PROTO_MAX][8] = { "TOC", "OSCAR", "YAHOO", "ICQ", "MSN", "", "", "", "JABBER", "", "", "", "", "", "", "" };
-
 static char *proto_away_alias[7][5] =
 {
@@ -58,28 +55,93 @@
 GSList *connections;
 
+gboolean load_plugin(char *path)
+{
+	void (*init_function) (void);
+	
+	GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);
+
+	if(!mod) {
+		log_message(LOGLVL_ERROR, "Can't find `%s', not loading", path);
+		return FALSE;
+	}
+
+	if(!g_module_symbol(mod,"init_plugin",(gpointer *) &init_function)) {
+		log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path);
+		return FALSE;
+	}
+
+	init_function();
+
+	return TRUE;
+}
 
 /* nogaim.c */
 
+GList *protocols = NULL;
+  
+void register_protocol (struct prpl *p)
+{
+	protocols = g_list_append(protocols, p);
+}
+
+ 
+struct prpl *find_protocol(const char *name)
+{
+	GList *gl;
+	for (gl = protocols; gl; gl = gl->next) 
+ 	{
+ 		struct prpl *proto = gl->data;
+ 		if(!g_strcasecmp(proto->name, name)) 
+			return proto;
+ 	}
+ 	return NULL;
+}
+
+/* nogaim.c */
 void nogaim_init()
 {
-	proto_prpl[PROTO_MSN] = g_new0 ( struct prpl, 1 );
+	GDir *dir;
+	GError *error = NULL;
+
 #ifdef WITH_MSN
-	msn_init( proto_prpl[PROTO_MSN] );
+	extern void msn_init();
+	msn_init();
 #endif
 
-	proto_prpl[PROTO_OSCAR] = g_new0( struct prpl, 1 );
 #ifdef WITH_OSCAR
-	oscar_init( proto_prpl[PROTO_OSCAR] );
+	extern void oscar_init();
+	oscar_init();
 #endif
 	
-	proto_prpl[PROTO_YAHOO] = g_new0( struct prpl, 1 );
 #ifdef WITH_YAHOO
-	byahoo_init( proto_prpl[PROTO_YAHOO] );
+	extern void byahoo_init();
+	byahoo_init();
 #endif
 	
-	proto_prpl[PROTO_JABBER] = g_new0( struct prpl, 1 );
 #ifdef WITH_JABBER
-	jabber_init( proto_prpl[PROTO_JABBER] );
+	extern void jabber_init();
+	jabber_init();
 #endif
+
+	dir = g_dir_open(PLUGINDIR, 0, &error);
+
+	if (dir) {
+		const gchar *entry;
+		char *path;
+
+		while ((entry = g_dir_read_name(dir))) {
+			path = g_build_filename(PLUGINDIR, entry, NULL);
+			if(!path) {
+				log_message(LOGLVL_WARNING, "Can't build path for %s\n", entry);
+				continue;
+			}
+
+			load_plugin(path);
+
+			g_free(path);
+		}
+
+		g_dir_close(dir);
+	}
 }
 
@@ -172,6 +234,5 @@
 	gc = g_new0( struct gaim_connection, 1 );
 	
-	gc->protocol = user->protocol;
-	gc->prpl = proto_prpl[gc->protocol];
+	gc->prpl = user->prpl;
 	g_snprintf( gc->username, sizeof( gc->username ), "%s", user->username );
 	g_snprintf( gc->password, sizeof( gc->password ), "%s", user->password );
@@ -254,12 +315,12 @@
 	/* Try to find a different connection on the same protocol. */
 	for( a = gc->irc->accounts; a; a = a->next )
-		if( proto_prpl[a->protocol] == gc->prpl && a->gc != gc )
+		if( a->prpl == gc->prpl && a->gc != gc )
 			break;
 	
 	/* If we found one, add the screenname to the acc_id. */
 	if( a )
-		g_snprintf( acc_id, 32, "%s(%s)", proto_name[gc->protocol], gc->username );
+		g_snprintf( acc_id, 32, "%s(%s)", gc->prpl->name, gc->username );
 	else
-		g_snprintf( acc_id, 32, "%s", proto_name[gc->protocol] );
+		g_snprintf( acc_id, 32, "%s", gc->prpl->name );
 	
 	irc_usermsg( gc->irc, "%s - %s", acc_id, msg );
@@ -295,5 +356,5 @@
 	if( u && u->away ) proto_away( gc, u->away );
 	
-	if( gc->protocol == PROTO_ICQ )
+ 	if( !strcmp(gc->prpl->name, "icq") )
 	{
 		for( u = gc->irc->users; u; u = u->next )
@@ -423,5 +484,5 @@
 	
 	memset( nick, 0, MAX_NICK_LENGTH + 1 );
-	strcpy( nick, nick_get( gc->irc, handle, gc->protocol, realname ) );
+	strcpy( nick, nick_get( gc->irc, handle, gc->prpl, realname ) );
 	
 	u = user_add( gc->irc, nick );
@@ -447,5 +508,5 @@
 	else
 	{
-		u->host = g_strdup( proto_name[gc->user->protocol] );
+		u->host = g_strdup( gc->user->prpl->name );
 		u->user = g_strdup( handle );
 	}
@@ -576,9 +637,9 @@
 	}
 	
-	if( ( type & UC_UNAVAILABLE ) && ( gc->protocol == PROTO_OSCAR || gc->protocol == PROTO_TOC ) )
+	if( ( type & UC_UNAVAILABLE ) && ( !strcmp(gc->prpl->name, "oscar") || !strcmp(gc->prpl->name, "icq")) )
 	{
 		u->away = g_strdup( "Away" );
 	}
-	else if( ( type & UC_UNAVAILABLE ) && ( gc->protocol == PROTO_JABBER ) )
+	else if( ( type & UC_UNAVAILABLE ) && ( !strcmp(gc->prpl->name, "jabber") ) )
 	{
 		if( type & UC_DND )
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ protocols/nogaim.h	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -72,5 +72,4 @@
 	/* we need to do either oscar or TOC */
 	/* we make this as an int in case if we want to add more protocols later */
-	int protocol;
 	struct prpl *prpl;
 	guint32 flags;
@@ -152,5 +151,5 @@
 	char user_info[2048];
 	int options;
-	int protocol;
+	struct prpl *prpl;
 	/* prpls can use this to save information about the user,
 	 * like which server to connect to, etc */
@@ -161,8 +160,26 @@
 };
 
+struct ft 
+{
+	const char *filename;
+	
+	/* Total number of bytes in file */
+	size_t total_bytes;
+	
+	/* Current number of bytes received */
+	size_t cur_bytes;
+};
+
+struct ft_request 
+{
+	const char *filename;
+	struct gaim_connection *gc;
+};
+
+typedef void (*ft_recv_handler) (struct ft *, void *data, size_t len);
+
 struct prpl {
-	int protocol;
 	int options;
-	char *(* name)();
+	const char *name;
 
 	/* for ICQ and Yahoo, who have off/on per-conversation options */
@@ -217,4 +234,9 @@
 	void (* group_buddy)	(struct gaim_connection *, char *who, char *old_group, char *new_group);
 
+	/* file transfers */
+	struct ft_send_req *(* req_send_file) (struct gaim_connection *, const char *file);
+	void (* send_file_part) (struct gaim_connection *, struct ft*, void *data, size_t length);
+	void (* accept_recv_file) (struct gaim_connection *, struct ft*, ft_recv_handler);
+
 	void (* buddy_free)	(struct buddy *);
 
@@ -223,20 +245,4 @@
 	int (* cmp_buddynames) (const char *who1, const char *who2);
 };
-
-#define PROTO_TOC	0
-#define PROTO_OSCAR	1
-#define PROTO_YAHOO	2
-#define PROTO_ICQ	3
-#define PROTO_MSN	4
-#define PROTO_IRC	5
-#define PROTO_FTP	6
-#define PROTO_VGATE	7
-#define PROTO_JABBER	8
-#define PROTO_NAPSTER	9
-#define PROTO_ZEPHYR	10
-#define PROTO_GADUGADU	11
-#define PROTO_MAX	16
-
-extern char proto_name[PROTO_MAX][8];
 
 #define UC_UNAVAILABLE  1
@@ -249,5 +255,6 @@
 
 G_MODULE_EXPORT GSList *get_connections();
-extern struct prpl *proto_prpl[16];
+G_MODULE_EXPORT struct prpl *find_protocol(const char *name);
+G_MODULE_EXPORT void register_protocol(struct prpl *);
 
 /* nogaim.c */
@@ -319,23 +326,9 @@
 G_MODULE_EXPORT void info_string_append(GString *str, char *newline, char *name, char *value);
 
-#ifdef WITH_MSN
-/* msn.c */
-G_MODULE_EXPORT void msn_init( struct prpl *ret );
-#endif
-
-#ifdef WITH_OSCAR
-/* oscar.c */
-G_MODULE_EXPORT void oscar_init( struct prpl *ret );
-#endif
-
-#ifdef WITH_JABBER
-/* jabber.c */
-G_MODULE_EXPORT void jabber_init( struct prpl *ret );
-#endif
-
-#ifdef WITH_YAHOO
-/* yahoo.c */
-G_MODULE_EXPORT void byahoo_init( struct prpl *ret );
-#endif
+/* file transfers */
+G_MODULE_EXPORT void ft_progress( struct ft *, int);
+G_MODULE_EXPORT void ft_incoming( struct ft_request * );
+G_MODULE_EXPORT void ft_accepted( struct ft_request *, struct ft *);
+G_MODULE_EXPORT void ft_denied( struct ft_request *, const char *reason);
 
 /* prefs.c */
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ protocols/oscar/oscar.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -358,8 +358,6 @@
 		odata->icq = TRUE;
 		/* this is odd but it's necessary for a proper do_import and do_export */
-		gc->protocol = PROTO_ICQ;
 		gc->password[8] = 0;
 	} else {
-		gc->protocol = PROTO_TOC;
 		gc->flags |= OPT_CONN_HTML;
 	}
@@ -2484,8 +2482,8 @@
 }
 
-static struct prpl *my_protocol = NULL;
-
-void oscar_init(struct prpl *ret) {
-	ret->protocol = PROTO_OSCAR;
+void oscar_init() 
+{
+	struct prpl *ret = g_new0(struct prpl, 1);
+	ret->name = "oscar";
 	ret->away_states = oscar_away_states;
 	ret->login = oscar_login;
@@ -2505,7 +2503,6 @@
 	ret->cmp_buddynames = aim_sncmp;
 	ret->get_status_string = oscar_get_status_string;
-
 	ret->send_typing = oscar_send_typing;
 
-	my_protocol = ret;
-}
+	register_protocol(ret);
+}
Index: protocols/proxy.c
===================================================================
--- protocols/proxy.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ protocols/proxy.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -50,14 +50,4 @@
 #define GAIM_ERR_COND   (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
 
-/*FIXME*		
-	#ifndef _WIN32
-		if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
-			closesocket(fd);
-			g_free(phb);
-			return -1;
-		}
-		fcntl(fd, F_SETFL, 0);
-#endif*/
-
 char proxyhost[128] = "";
 int proxyport = 0;
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ protocols/yahoo/yahoo.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -64,10 +64,4 @@
 };
 
-static char *yahoo_name()
-{
-	return "Yahoo";
-}
-
-static struct prpl *my_protocol = NULL;
 static GSList *byahoo_inputs = NULL;
 static int byahoo_chat_id = 0;
@@ -396,13 +390,12 @@
 }
 
-void byahoo_init( struct prpl *ret )
-{
-	ret->protocol = PROTO_YAHOO;
-	ret->name = yahoo_name;
+void byahoo_init( )
+{
+	struct prpl *ret = g_new0(struct prpl, 1);
+	ret->name = "yahoo";
 	
 	ret->login = byahoo_login;
 	ret->close = byahoo_close;
 	ret->send_im = byahoo_send_im;
-	ret->send_typing = byahoo_send_typing;
 	ret->get_info = byahoo_get_info;
 	ret->away_states = byahoo_away_states;
@@ -412,4 +405,5 @@
 	ret->remove_buddy = byahoo_remove_buddy;
 	ret->get_status_string = byahoo_get_status_string;
+	ret->send_typing = byahoo_send_typing;
 	
 	ret->chat_send = byahoo_chat_send;
@@ -419,5 +413,5 @@
 	ret->cmp_buddynames = g_strcasecmp;
 	
-	my_protocol = ret;
+	register_protocol(ret);
 }
 
@@ -433,5 +427,5 @@
 		yd = gc->proto_data;
 		
-		if( gc->protocol == PROTO_YAHOO && yd->y2_id == id )
+		if( !strcmp(gc->prpl->name, "yahoo") && yd->y2_id == id )
 			return( gc );
 	}
Index: unix.c
===================================================================
--- unix.c	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ unix.c	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -47,6 +47,7 @@
 	
 	log_init( );
-	nogaim_init( );
-	
+
+	nogaim_init();
+
 	CONF_FILE = g_strdup( CONF_FILE_DEF );
 	
Index: url.h
===================================================================
--- url.h	(revision dfde8e08f71cfd24c9c247962bb4ddbed0b089fa)
+++ url.h	(revision b20b32f0785f9a1eff448382a98e64812469e112)
@@ -26,5 +26,6 @@
 #include "bitlbee.h"
 
-#define PROTO_HTTP	2
+#define PROTO_FTP		1
+#define PROTO_HTTP		2
 #define PROTO_SOCKS4	3
 #define PROTO_SOCKS5	4
