Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision f5c0d8e4dd3ce01945a6334a5d87c89a9f43b16b)
+++ bitlbee.h	(revision 0c85c08d210e16bb10dc283b4a1478ce53c0c1b1)
@@ -142,5 +142,4 @@
 #include "misc.h"
 #include "proxy.h"
-#include "otr.h"
 
 typedef struct global {
@@ -154,5 +153,4 @@
 	char *helpfile;
 	int restart;
-	OtrlMessageAppOps otr_ops;   /* collects interface functions required by OTR */
 } global_t;
 
Index: irc.c
===================================================================
--- irc.c	(revision f5c0d8e4dd3ce01945a6334a5d87c89a9f43b16b)
+++ irc.c	(revision 0c85c08d210e16bb10dc283b4a1478ce53c0c1b1)
@@ -29,4 +29,5 @@
 
 GSList *irc_connection_list;
+GSList *irc_plugins;
 
 static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
@@ -42,4 +43,5 @@
 	char *host = NULL, *myhost = NULL;
 	irc_user_t *iu;
+	GSList *l;
 	set_t *s;
 	bee_t *b;
@@ -164,4 +166,11 @@
 	nogaim_init();
 	
+	for( l = irc_plugins; l; l = l->next )
+	{
+		irc_plugin_t *p = l->data;
+		if( p->irc_new )
+			p->irc_new( irc );
+	}
+	
 	return irc;
 }
@@ -207,7 +216,16 @@
 void irc_free( irc_t * irc )
 {
+	GSList *l;
+	
 	irc->status |= USTATUS_SHUTDOWN;
 	
 	log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
+	
+	for( l = irc_plugins; l; l = l->next )
+	{
+		irc_plugin_t *p = l->data;
+		if( p->irc_free )
+			p->irc_free( irc );
+	}
 	
 	if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) ) 
@@ -932,2 +950,7 @@
 	return SET_INVALID;
 }
+
+void register_irc_plugin( const struct irc_plugin *p )
+{
+	irc_plugins = g_slist_prepend( irc_plugins, (gpointer) p );
+}
Index: irc.h
===================================================================
--- irc.h	(revision f5c0d8e4dd3ce01945a6334a5d87c89a9f43b16b)
+++ irc.h	(revision 0c85c08d210e16bb10dc283b4a1478ce53c0c1b1)
@@ -26,6 +26,4 @@
 #ifndef _IRC_H
 #define _IRC_H
-
-#include "otr.h"
 
 #define IRC_MAX_LINE 512
@@ -88,5 +86,6 @@
 	gint login_source_id; /* To slightly delay some events at login time. */
 	
-	otr_t *otr;            /* OTR state and book keeping */
+	struct otr *otr; /* OTR state and book keeping, used by the OTR plugin.
+	                    TODO: Some mechanism for plugindata. */
 	
 	struct bee *b;
@@ -221,4 +220,24 @@
 } irc_channel_del_user_type_t;
 
+/* These are a glued a little bit to the core/bee layer and a little bit to
+   IRC. The first user is OTR, and I guess at some point we'll get to shape
+   this a little bit more as other uses come up. */
+typedef struct irc_plugin
+{
+	/* Called at the end of irc_new(). Can be used to add settings, etc. */
+	gboolean (*irc_new)( irc_t *irc );
+	/* At the end of irc_free(). */
+	void (*irc_free)( irc_t *irc );
+	
+	/* Called by bee_irc_user_privmsg_cb(). Return NULL if you want to
+	   abort sending the msg. */
+	char* (*filter_msg_out)( irc_user_t *iu, const char *msg, int flags );
+	/* Called by bee_irc_user_msg(). Return NULL if you swallowed the
+	   message and don't want anything to go to the user. */
+	char* (*filter_msg_in)( irc_user_t *iu, const char *msg, int flags );
+} irc_plugin_t;
+
+extern GSList *irc_plugins; /* struct irc_plugin */
+
 /* irc.c */
 extern GSList *irc_connection_list;
@@ -245,4 +264,6 @@
 
 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv );
+
+void register_irc_plugin( const struct irc_plugin *p );
 
 /* irc_channel.c */
Index: otr.c
===================================================================
--- otr.c	(revision f5c0d8e4dd3ce01945a6334a5d87c89a9f43b16b)
+++ otr.c	(revision 0c85c08d210e16bb10dc283b4a1478ce53c0c1b1)
@@ -109,4 +109,6 @@
 } pair_t;	
 
+static OtrlMessageAppOps otr_ops;   /* collects interface functions required by OTR */
+
 
 /** misc. helpers/subroutines: **/
@@ -174,4 +176,7 @@
 OtrlPrivKey *match_privkey(irc_t *irc, const char **args);
 
+/* functions to be called for certain events */
+static const struct irc_plugin otr_plugin;
+
 
 /*** routines declared in otr.h: ***/
@@ -182,37 +187,50 @@
 	
 	/* fill global OtrlMessageAppOps */
-	global.otr_ops.policy = &op_policy;
-	global.otr_ops.create_privkey = &op_create_privkey;
-	global.otr_ops.is_logged_in = &op_is_logged_in;
-	global.otr_ops.inject_message = &op_inject_message;
-	global.otr_ops.notify = NULL;
-	global.otr_ops.display_otr_message = &op_display_otr_message;
-	global.otr_ops.update_context_list = NULL;
-	global.otr_ops.protocol_name = NULL;
-	global.otr_ops.protocol_name_free = NULL;
-	global.otr_ops.new_fingerprint = &op_new_fingerprint;
-	global.otr_ops.write_fingerprints = &op_write_fingerprints;
-	global.otr_ops.gone_secure = &op_gone_secure;
-	global.otr_ops.gone_insecure = &op_gone_insecure;
-	global.otr_ops.still_secure = &op_still_secure;
-	global.otr_ops.log_message = &op_log_message;
-	global.otr_ops.max_message_size = &op_max_message_size;
-	global.otr_ops.account_name = &op_account_name;
-	global.otr_ops.account_name_free = NULL;
+	otr_ops.policy = &op_policy;
+	otr_ops.create_privkey = &op_create_privkey;
+	otr_ops.is_logged_in = &op_is_logged_in;
+	otr_ops.inject_message = &op_inject_message;
+	otr_ops.notify = NULL;
+	otr_ops.display_otr_message = &op_display_otr_message;
+	otr_ops.update_context_list = NULL;
+	otr_ops.protocol_name = NULL;
+	otr_ops.protocol_name_free = NULL;
+	otr_ops.new_fingerprint = &op_new_fingerprint;
+	otr_ops.write_fingerprints = &op_write_fingerprints;
+	otr_ops.gone_secure = &op_gone_secure;
+	otr_ops.gone_insecure = &op_gone_insecure;
+	otr_ops.still_secure = &op_still_secure;
+	otr_ops.log_message = &op_log_message;
+	otr_ops.max_message_size = &op_max_message_size;
+	otr_ops.account_name = &op_account_name;
+	otr_ops.account_name_free = NULL;
 	
 	root_command_add( "otr", 1, cmd_otr, 0 );
-}
-
-otr_t *otr_new(void)
-{
-	otr_t *otr = g_new0(otr_t, 1);
-
-	otr->us = otrl_userstate_create();
-	
-	return otr;
-}
-
-void otr_free(otr_t *otr)
-{
+	register_irc_plugin( &otr_plugin );
+}
+
+gboolean otr_irc_new(irc_t *irc)
+{
+	set_t *s;
+	GSList *l;
+	
+	irc->otr = g_new0(otr_t, 1);
+	irc->otr->us = otrl_userstate_create();
+	
+	s = set_add( &irc->b->set, "otr_color_encrypted", "true", set_eval_bool, irc );
+	
+	s = set_add( &irc->b->set, "otr_policy", "oppurtunistic", set_eval_list, irc );
+	l = g_slist_prepend( NULL, "never" );
+	l = g_slist_prepend( l, "opportunistic" );
+	l = g_slist_prepend( l, "manual" );
+	l = g_slist_prepend( l, "always" );
+	s->eval_data = l;
+	
+	return TRUE;
+}
+
+void otr_irc_free(irc_t *irc)
+{
+	otr_t *otr = irc->otr;
 	otrl_userstate_free(otr->us);
 	if(otr->keygen) {
@@ -339,5 +357,5 @@
 	}
 	
-	ignore_msg = otrl_message_receiving(irc->otr->us, &global.otr_ops, ic,
+	ignore_msg = otrl_message_receiving(irc->otr->us, &otr_ops, ic,
 		ic->acc->user, ic->acc->prpl->name, handle, msg, &newmsg,
 		&tlvs, NULL, NULL);
@@ -393,5 +411,5 @@
 	}
 	
-	st = otrl_message_sending(irc->otr->us, &global.otr_ops, ic,
+	st = otrl_message_sending(irc->otr->us, &otr_ops, ic,
 		ic->acc->user, ic->acc->prpl->name, handle,
 		msg, NULL, &otrmsg, NULL, NULL);
@@ -409,5 +427,5 @@
 			return 1;
 		}
-		st = otrl_message_fragment_and_send(&global.otr_ops, ic, ctx,
+		st = otrl_message_fragment_and_send(&otr_ops, ic, ctx,
 			otrmsg, OTRL_FRAGMENT_SEND_ALL, NULL);
 		otrl_message_free(otrmsg);
@@ -420,4 +438,10 @@
 	return st;
 }
+
+static const struct irc_plugin otr_plugin =
+{
+	otr_irc_new,
+	otr_irc_free,
+};
 
 static void cmd_otr(irc_t *irc, char **args)
@@ -663,5 +687,5 @@
 	}
 	
-	otrl_message_disconnect(irc->otr->us, &global.otr_ops,
+	otrl_message_disconnect(irc->otr->us, &otr_ops,
 		u->bu->ic, u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, u->bu->handle);
 	
@@ -721,5 +745,5 @@
 			"SMP already in phase %d, sending abort before reinitiating",
 			ctx->smstate->nextExpected+1);
-		otrl_message_abort_smp(irc->otr->us, &global.otr_ops, u->bu->ic, ctx);
+		otrl_message_abort_smp(irc->otr->us, &otr_ops, u->bu->ic, ctx);
 		otrl_sm_state_free(ctx->smstate);
 	}
@@ -729,5 +753,5 @@
 	if(ctx->smstate->secret == NULL) {
 		irc_usermsg(irc, "smp: initiating with %s...", u->nick);
-		otrl_message_initiate_smp(irc->otr->us, &global.otr_ops,
+		otrl_message_initiate_smp(irc->otr->us, &otr_ops,
 			u->bu->ic, ctx, (unsigned char *)args[2], strlen(args[2]));
 		/* smp is now in EXPECT2 */
@@ -736,5 +760,5 @@
 		   received the SMP1, so let's issue a response */
 		irc_usermsg(irc, "smp: responding to %s...", u->nick);
-		otrl_message_respond_smp(irc->otr->us, &global.otr_ops,
+		otrl_message_respond_smp(irc->otr->us, &otr_ops,
 			u->bu->ic, ctx, (unsigned char *)args[2], strlen(args[2]));
 		/* smp is now in EXPECT3 */
@@ -1050,5 +1074,5 @@
 	irc_t *irc = ic->bee->ui_data;
 	OtrlUserState us = irc->otr->us;
-	OtrlMessageAppOps *ops = &global.otr_ops;
+	OtrlMessageAppOps *ops = &otr_ops;
 	OtrlTLV *tlv = NULL;
 	ConnContext *context;
Index: otr.h
===================================================================
--- otr.h	(revision f5c0d8e4dd3ce01945a6334a5d87c89a9f43b16b)
+++ otr.h	(revision 0c85c08d210e16bb10dc283b4a1478ce53c0c1b1)
@@ -72,8 +72,4 @@
 void otr_init(void);
 
-/* called from irc_new()/irc_free() */
-otr_t *otr_new();
-void otr_free(otr_t *otr);
-
 /* called by storage_* functions */
 void otr_load(struct irc *irc);
@@ -98,6 +94,4 @@
 typedef void *OtrlMessageAppOps;
 
-#define otr_init() {}
-#define otr_new() (NULL)
 #define otr_free(otr) {}
 #define otr_load(irc) {}
Index: storage.c
===================================================================
--- storage.c	(revision f5c0d8e4dd3ce01945a6334a5d87c89a9f43b16b)
+++ storage.c	(revision 0c85c08d210e16bb10dc283b4a1478ce53c0c1b1)
@@ -28,5 +28,4 @@
 #define BITLBEE_CORE
 #include "bitlbee.h"
-#include "otr.h"
 
 extern storage_t storage_text;
@@ -115,8 +114,7 @@
 
 		status = st->load(irc, password);
-		if (status == STORAGE_OK) {
-			otr_load(irc);
+		if (status == STORAGE_OK)
 			return status;
-		}
+		
 		if (status != STORAGE_NO_SUCH_USER) 
 			return status;
@@ -139,6 +137,5 @@
 		return STORAGE_NO_SUCH_USER;
 	}
-
-	otr_save(irc);
+	
 	st = ((storage_t *)global.storage->data)->save(irc, overwrite);
 	
@@ -166,7 +163,4 @@
 			ret = status;
 	}
-	if (ret == STORAGE_OK) {
-		otr_remove(nick);
-	}
 	
 	return ret;
@@ -182,12 +176,10 @@
 	storage_t *primary_storage = gl->data;
 	irc_t *irc;
-	
+
 	/* First, try to rename in the current write backend, assuming onick 
 	 * is stored there */
 	status = primary_storage->rename(onick, nnick, password);
-	if (status != STORAGE_NO_SUCH_USER) {
-		otr_rename(onick, nnick);
+	if (status != STORAGE_NO_SUCH_USER)
 		return status;
-	}
 
 	/* Try to load from a migration backend and save to the current backend. 
@@ -213,5 +205,4 @@
 
 	storage_remove(onick, password);
-	otr_rename(onick, nnick);
 
 	return STORAGE_OK;
