Index: irc.c
===================================================================
--- irc.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ irc.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -102,6 +102,5 @@
 
 	irc_connection_list = g_slist_append( irc_connection_list, irc );
-	
-	set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
+
 	set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
 	set_add( &irc->set, "auto_reconnect", "false", set_eval_bool, irc );
@@ -115,5 +114,7 @@
 	set_add( &irc->set, "handle_unknown", "root", NULL, irc );
 	set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
-	set_add( &irc->set, "ops", "both", set_eval_ops, irc );
+	set_add( &irc->set, "op_buddies", "false", set_eval_op_buddies, irc );
+	set_add( &irc->set, "op_root", "true", set_eval_op_root, irc );
+	set_add( &irc->set, "op_user", "true", set_eval_op_user, irc );
 	set_add( &irc->set, "password", NULL, passchange, irc );
 	set_add( &irc->set, "private", "true", set_eval_bool, irc );
@@ -124,4 +125,5 @@
 	set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
 	set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
+	set_add( &irc->set, "voice_buddies", "notaway",  set_eval_voice_buddies, irc );
 	
 	conf_loaddefaults( irc );
@@ -643,5 +645,6 @@
 	char namelist[385] = "";
 	struct groupchat *c = NULL;
-	char *ops = set_getstr( &irc->set, "ops" );
+	char *oo = set_getstr(&irc->set, "op_buddies");
+	char *vo = set_getstr(&irc->set, "voice_buddies");
 	
 	/* RFCs say there is no error reply allowed on NAMES, so when the
@@ -658,8 +661,11 @@
 			}
 			
-			if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )
+			if( u->ic && !u->away && !strcmp(vo, "notaway") )
 				strcat( namelist, "+" );
-			else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||
-			         ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) )
+			else if( ( strcmp( u->nick, irc->mynick ) == 0 && set_getbool(&irc->set, "op_root") ) ||
+			         ( strcmp( u->nick, irc->nick ) == 0 && set_getbool(&irc->set, "op_user") ) ||
+			         ( !u->away && !strcmp(oo, "notaway") ) ||
+			         ( u->encrypted>1 && !strcmp(oo, "trusted") ) ||
+			         ( u->encrypted && !strcmp(oo, "encrypted") ) )
 				strcat( namelist, "@" );
 			
@@ -674,7 +680,8 @@
 		/* root and the user aren't in the channel userlist but should
 		   show up in /NAMES, so list them first: */
-		sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick,
-		                                 strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );
-		
+		sprintf( namelist, "%s%s %s%s ", set_getbool(&irc->set, "op_root") ? "@" : "", irc->mynick,
+		                                 set_getbool(&irc->set, "op_user") ? "@" : "", irc->nick );
+		
+		/* TODO: Honor op/voice_buddies in chats?! */
 		for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )
 		{
Index: irc.h
===================================================================
--- irc.h	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ irc.h	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -30,5 +30,5 @@
 
 #define IRC_MAX_LINE 512
-#define IRC_MAX_ARGS 8
+#define IRC_MAX_ARGS 16
 
 #define IRC_LOGIN_TIMEOUT 60
Index: lib/misc.c
===================================================================
--- lib/misc.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ lib/misc.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -143,4 +143,5 @@
 	char *s = out, *cs;
 	int i, matched;
+	int taglen;
 	
 	memset( out, 0, strlen( in ) + 1 );
@@ -159,7 +160,16 @@
 				in ++;
 			
+			taglen = in-cs-1;   /* not <0 because the above loop runs at least once */
 			if( *in )
 			{
-				if( g_strncasecmp( cs+1, "br", 2) == 0 )
+				if( g_strncasecmp( cs+1, "b", taglen) == 0 )
+					*(s++) = '\x02';
+				else if( g_strncasecmp( cs+1, "/b", taglen) == 0 )
+					*(s++) = '\x02';
+				else if( g_strncasecmp( cs+1, "i", taglen) == 0 )
+					*(s++) = '\x1f';
+				else if( g_strncasecmp( cs+1, "/i", taglen) == 0 )
+					*(s++) = '\x1f';
+				else if( g_strncasecmp( cs+1, "br", 2) == 0 )
 					*(s++) = '\n';
 				in ++;
Index: otr.c
===================================================================
--- otr.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ otr.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -35,6 +35,4 @@
 void op_gone_secure(void *opdata, ConnContext *context);
 
-void op_gone_secure(void *opdata, ConnContext *context);
-
 void op_gone_insecure(void *opdata, ConnContext *context);
 
@@ -53,5 +51,6 @@
 void cmd_otr_abort(irc_t *irc, char **args); /* TODO: does this cmd even make sense? */
 void cmd_otr_request(irc_t *irc, char **args); /* TODO: do we even need this? */
-void cmd_otr_auth(irc_t *irc, char **args);
+void cmd_otr_smp(irc_t *irc, char **args);
+void cmd_otr_trust(irc_t *irc, char **args);
 /* TODO: void cmd_otr_affirm(irc_t *irc, char **args); */
 void cmd_otr_fprints(irc_t *irc, char **args);
@@ -62,5 +61,6 @@
 	{ "abort",    1, &cmd_otr_abort,    0 },
 	{ "request",  1, &cmd_otr_request,  0 },
-	{ "auth",     2, &cmd_otr_auth,     0 },
+	{ "smp",      2, &cmd_otr_smp,      0 },
+	{ "trust",    6, &cmd_otr_trust,    0 },
 	{ "fprints",  0, &cmd_otr_fprints,  0 },
 	{ "info",     1, &cmd_otr_info,     0 },
@@ -97,9 +97,19 @@
 	const char *protocol);
 
-/* determine the nick for a given handle/protocol pair */
+/* determine the nick for a given handle/protocol pair
+   returns "handle/protocol" if not found */
 const char *peernick(irc_t *irc, const char *handle, const char *protocol);
+
+/* determine the user_t for a given handle/protocol pair
+   returns NULL if not found */
+user_t *peeruser(irc_t *irc, const char *handle, const char *protocol);
 
 /* handle SMP TLVs from a received message */
 void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs);
+
+/* update op/voice flag of given user according to encryption state and settings
+   returns 0 if neither op_buddies nor voice_buddies is set to "encrypted",
+   i.e. msgstate should be announced seperately */
+int otr_update_modeflags(irc_t *irc, user_t *u);
 
 /* show the list of fingerprints associated with a given context */
@@ -239,6 +249,13 @@
 	
     if(!g_mutex_trylock(ic->irc->otr_mutex)) {
-    	/* TODO: queue msgs received during keygen for later */
-		irc_usermsg(ic->irc, "msg from %s during keygen - dropped",
+    	user_t *u = user_findhandle(ic, handle);
+    	
+    	/* fallback for non-otr clients */
+    	if(u && !u->encrypted) {
+    		return g_strdup(msg);
+    	}
+    	
+    	/* TODO: queue msgs received during keygen for later? */
+		irc_usermsg(ic->irc, "otr msg from %s during keygen - dropped",
 			peernick(ic->irc, handle, ic->acc->prpl->name));
 		return NULL;
@@ -283,12 +300,22 @@
 int otr_send_message(struct im_connection *ic, const char *handle, const char *msg, int flags)
 {	
-    int st;
-    char *otrmsg = NULL;
-    ConnContext *ctx = NULL;
-    
+	int st;
+	char *otrmsg = NULL;
+	ConnContext *ctx = NULL;
+	
     if(!g_mutex_trylock(ic->irc->otr_mutex)) {
-    	irc_usermsg(ic->irc, "msg to %s during keygen - not sent",
-    		peernick(ic->irc, handle, ic->acc->prpl->name));
-    	return 1;
+		user_t *u = user_findhandle(ic, handle);
+    	
+		/* Fallback for non-otr clients.
+		   Yes, we must be very sure this doesn't send stuff in the clear where it
+		   shouldn't... */
+		if(u && !u->encrypted) {
+			return ic->acc->prpl->buddy_msg(ic, (char *)handle, (char *)msg, flags);
+		}
+		
+		/* otherwise refuse to send */
+		irc_usermsg(ic->irc, "otr msg to %s not sent during keygen",
+			peernick(ic->irc, handle, ic->acc->prpl->name));
+		return 1;
     }
     
@@ -414,12 +441,15 @@
 
 int op_display_otr_message(void *opdata, const char *accountname,
-	const char *protocol, const char *username, const char *msg)
+	const char *protocol, const char *username, const char *message)
 {
 	struct im_connection *ic = check_imc(opdata, accountname, protocol);
-
-	log_message(LOGLVL_DEBUG, "op_display_otr_message '%s' '%s' '%s' '%s'", accountname, protocol, username, msg);
-
-	irc_usermsg(ic->irc, "%s", msg);
-
+	char *msg = g_strdup(message);
+
+	log_message(LOGLVL_DEBUG, "op_display_otr_message '%s' '%s' '%s' '%s'", accountname, protocol, username, message);
+
+	strip_html(msg);
+	irc_usermsg(ic->irc, "otr: %s", msg);
+
+	g_free(msg);
 	return 0;
 }
@@ -452,9 +482,21 @@
 	struct im_connection *ic =
 		check_imc(opdata, context->accountname, context->protocol);
+	user_t *u;
 
 	log_message(LOGLVL_DEBUG, "op_gone_secure '%s' '%s' '%s'", context->accountname, context->protocol, context->username);
 
-	irc_usermsg(ic->irc, "conversation with %s is now off the record",
-		peernick(ic->irc, context->username, context->protocol));
+	u = peeruser(ic->irc, context->username, context->protocol);
+	if(!u) {
+		log_message(LOGLVL_ERROR,
+			"BUG: otr.c: op_gone_secure: user_t for %s/%s not found!",
+			context->username, context->protocol);
+		return;
+	}
+	if(context->active_fingerprint->trust[0])
+		u->encrypted = 2;
+	else
+		u->encrypted = 1;
+	if(!otr_update_modeflags(ic->irc, u))
+		irc_usermsg(ic->irc, "conversation with %s is now off the record", u->nick);
 }
 
@@ -463,9 +505,18 @@
 	struct im_connection *ic =
 		check_imc(opdata, context->accountname, context->protocol);
+	user_t *u;
 
 	log_message(LOGLVL_DEBUG, "op_gone_insecure '%s' '%s' '%s'", context->accountname, context->protocol, context->username);
 
-	irc_usermsg(ic->irc, "conversation with %s is now in the clear",
-		peernick(ic->irc, context->username, context->protocol));
+	u = peeruser(ic->irc, context->username, context->protocol);
+	if(!u) {
+		log_message(LOGLVL_ERROR,
+			"BUG: otr.c: op_gone_insecure: user_t for %s/%s not found!",
+			context->username, context->protocol);
+		return;
+	}
+	u->encrypted = 0;
+	if(!otr_update_modeflags(ic->irc, u))
+		irc_usermsg(ic->irc, "conversation with %s is now in the clear", u->nick);
 }
 
@@ -474,27 +525,39 @@
 	struct im_connection *ic =
 		check_imc(opdata, context->accountname, context->protocol);
+	user_t *u;
 
 	log_message(LOGLVL_DEBUG, "op_still_secure '%s' '%s' '%s' is_reply=%d",
 		context->accountname, context->protocol, context->username, is_reply);
 
-	irc_usermsg(ic->irc, "otr connection with %s has been refreshed",
-		peernick(ic->irc, context->username, context->protocol));
+	u = peeruser(ic->irc, context->username, context->protocol);
+	if(!u) {
+		log_message(LOGLVL_ERROR,
+			"BUG: otr.c: op_still_secure: user_t for %s/%s not found!",
+			context->username, context->protocol);
+		return;
+	}
+	if(context->active_fingerprint->trust[0])
+		u->encrypted = 2;
+	else
+		u->encrypted = 1;
+	if(!otr_update_modeflags(ic->irc, u))
+		irc_usermsg(ic->irc, "otr connection with %s has been refreshed", u->nick);
 }
 
 void op_log_message(void *opdata, const char *message)
 {
-	log_message(LOGLVL_INFO, "%s", message);
+	char *msg = g_strdup(message);
+	
+	strip_html(msg);
+	log_message(LOGLVL_INFO, "otr: %s", msg);
+	g_free(msg);
 }
 
 int op_max_message_size(void *opdata, ConnContext *context)
 {
-	/* TODO: make max_message_size a property of the prpl.
-	         the values here are taken from the libotr UPGRADING file */
-	if(!strcmp(context->protocol, "msn"))
-		return 1409;
-	if(!strcmp(context->protocol, "yahoo"))
-		return 832;
-	if(!strcmp(context->protocol, "oscar"))
-		return 2343;
+	struct im_connection *ic =
+		check_imc(opdata, context->accountname, context->protocol);
+
+	return ic->acc->prpl->mms;
 }
 
@@ -542,5 +605,5 @@
 }
 
-void cmd_otr_auth(irc_t *irc, char **args)
+void cmd_otr_smp(irc_t *irc, char **args)
 {
 	user_t *u;
@@ -589,4 +652,78 @@
 }
 
+int hexval(char a)
+{
+	int x=tolower(a);
+	
+	if(x>='a' && x<='f')
+		x = x - 'a' + 10;
+	else if(x>='0' && x<='9')
+		x = x - '0';
+	else
+		return -1;
+	
+	return x;
+}
+
+void cmd_otr_trust(irc_t *irc, char **args)
+{
+	user_t *u;
+	ConnContext *ctx;
+	unsigned char raw[20];
+	Fingerprint *fp;
+	int i,j;
+	
+	u = user_find(irc, args[1]);
+	if(!u || !u->ic) {
+		irc_usermsg(irc, "%s: unknown user", args[1]);
+		return;
+	}
+	
+	ctx = otrl_context_find(irc->otr_us, u->handle,
+		u->ic->acc->user, u->ic->acc->prpl->name, 0, NULL, NULL, NULL);
+	if(!ctx) {
+		irc_usermsg(irc, "%s: no otr context with user", args[1]);
+		return;
+	}
+	
+	/* convert given fingerprint to raw representation */
+	for(i=0; i<5; i++) {
+		for(j=0; j<4; j++) {
+			char *p = args[2+i]+(2*j);
+			char *q = p+1;
+			int x, y;
+			
+			if(!*p || !*q) {
+				irc_usermsg(irc, "failed: truncated fingerprint block %d", i+1);
+				return;
+			}
+			
+			x = hexval(*p);
+			y = hexval(*q);
+			if(x<0) {
+				irc_usermsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+1, i+1);
+				return;
+			}
+			if(y<0) {
+				irc_usermsg(irc, "failed: %d. hex digit of block %d out of range", 2*j+2, i+1);
+				return;
+			}
+
+			raw[i*4+j] = x*16 + y;
+		}
+	}
+	fp = otrl_context_find_fingerprint(ctx, raw, 0, NULL);
+	if(!fp) {
+		irc_usermsg(irc, "failed: no such fingerprint for %s", args[1]);
+	} else {
+		char *trust = args[7] ? args[7] : "affirmed";
+		otrl_context_set_trust(fp, trust);
+		irc_usermsg(irc, "fingerprint match, trust set to \"%s\"", trust);
+		if(u->encrypted)
+			u->encrypted = 2;
+		otr_update_modeflags(irc, u);
+	}
+}
+
 void cmd_otr_fprints(irc_t *irc, char **args)
 {
@@ -649,5 +786,5 @@
 		u->ic->acc->user, u->ic->acc->prpl->name, 0, NULL, NULL, NULL);
 	if(!ctx) {
-		irc_usermsg(irc, "no otr info on %s", args[1]);
+		irc_usermsg(irc, "no otr context with %s", args[1]);
 		return;
 	}
@@ -672,16 +809,19 @@
 	irc_usermsg(irc, "  otr offer status: %s", offer_status);
 	irc_usermsg(irc, "  connection state: %s", message_state);
-	irc_usermsg(irc, "  protocol version: %d", ctx->protocol_version);
-	fp = ctx->active_fingerprint;
-	if(!fp) {
-		irc_usermsg(irc, "  active f'print:   none");
-	} else {
-		otrl_privkey_hash_to_human(human, fp->fingerprint);
-		if(!fp->trust || fp->trust[0] == '\0') {
-			trust="untrusted";
+	
+	if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+		irc_usermsg(irc, "  protocol version: %d", ctx->protocol_version);
+		fp = ctx->active_fingerprint;
+		if(!fp) {
+			irc_usermsg(irc, "  active f'print:   none?");
 		} else {
-			trust=fp->trust;
-		}
-		irc_usermsg(irc, "  active f'print:   %s (%s)", human, trust);
+			otrl_privkey_hash_to_human(human, fp->fingerprint);
+			if(!fp->trust || fp->trust[0] == '\0') {
+				trust="untrusted";
+			} else {
+				trust=fp->trust;
+			}
+			irc_usermsg(irc, "  active f'print:   %s (%s)", human, trust);
+		}
 	}
 }
@@ -809,10 +949,8 @@
 }
 
-const char *peernick(irc_t *irc, const char *handle, const char *protocol)
+user_t *peeruser(irc_t *irc, const char *handle, const char *protocol)
 {
 	user_t *u;
-	static char fallback[512];
-	
-	g_snprintf(fallback, 511, "%s/%s", handle, protocol);
+	
 	for(u=irc->users; u; u=u->next) {
 		struct prpl *prpl;
@@ -822,9 +960,53 @@
 		if(strcmp(prpl->name, protocol) == 0
 			&& prpl->handle_cmp(u->handle, handle) == 0) {
-			return u->nick;
-		}
-	}
-	
-	return fallback;
+			return u;
+		}
+	}
+	
+	return NULL;
+}
+
+const char *peernick(irc_t *irc, const char *handle, const char *protocol)
+{
+	static char fallback[512];
+	
+	user_t *u = peeruser(irc, handle, protocol);
+	if(u) {
+		return u->nick;
+	} else {
+		g_snprintf(fallback, 511, "%s/%s", handle, protocol);
+		return fallback;
+	}
+}
+
+int otr_update_modeflags(irc_t *irc, user_t *u)
+{
+	char *vo = set_getstr(&irc->set, "voice_buddies");
+	char *oo = set_getstr(&irc->set, "op_buddies");
+	char eflag=0, tflag=0;
+	int e = u->encrypted;
+	int t = (u->encrypted > 1);
+	
+	if(!strcmp(vo, "encrypted"))
+		eflag='v';
+	else if(!strcmp(oo, "encrypted"))
+		eflag='o';
+	if(!strcmp(vo, "trusted"))
+		tflag='v';
+	else if(!strcmp(oo, "trusted"))
+		tflag='o';
+	
+	if(!eflag)
+		return 0;
+	
+	if(tflag) {
+		irc_write( irc, ":%s!%s@%s MODE %s %c%c%c%c %s %s", irc->mynick, irc->mynick, irc->myhost,
+			irc->channel, e?'+':'-', eflag, t?'+':'-', tflag, u->nick, u->nick );
+	} else {
+		irc_write( irc, ":%s!%s@%s MODE %s %c%c %s", irc->mynick, irc->mynick, irc->myhost,
+			irc->channel, e?'+':'-', eflag, u->nick );
+	}
+		
+	return 1;
 }
 
@@ -966,7 +1148,11 @@
 	account_t *acc = (account_t *)data;
 	
-	/* TODO: remember that we didn't want a key? */
 	irc_usermsg(acc->irc, "proceeding without key, otr inoperable on %s/%s",
 		acc->user, acc->prpl->name);
+	/* TODO: 
+	irc_usermsg(acc->irc, "setting otr policy for %s/%s to \"never\"",
+		acc->user, acc->prpl->name);
+	set_setstr(acc->set, "otr_policy", "never");
+	*/
 }
 
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ protocols/jabber/jabber.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -511,4 +511,5 @@
 	
 	ret->name = "jabber";
+    ret->mms = 0;                        /* no limit */
 	ret->login = jabber_login;
 	ret->init = jabber_init;
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ protocols/msn/msn.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -372,4 +372,5 @@
 	
 	ret->name = "msn";
+    ret->mms = 1409;         /* this guess taken from libotr UPGRADING file */
 	ret->login = msn_login;
 	ret->init = msn_init;
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ protocols/nogaim.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -603,8 +603,7 @@
 	
 	/* LISPy... */
-	if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&		/* Don't do a thing when user doesn't want it */
-	    ( u->online ) &&						/* Don't touch offline people */
-	    ( ( ( u->online != oo ) && !u->away ) ||			/* Voice joining people */
-	      ( ( u->online == oo ) && ( oa == !u->away ) ) ) )		/* (De)voice people changing state */
+	if( ( u->online ) &&						/* Don't touch offline people */
+	    ( ( ( u->online != oo ) && !u->away ) ||			/* Do joining people */
+	      ( ( u->online == oo ) && ( oa == !u->away ) ) ) )		/* Do people changing state */
 	{
 		char *from;
@@ -619,6 +618,12 @@
 			                                    ic->irc->myhost );
 		}
-		irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
-		                                          u->away?'-':'+', u->nick );
+		if(!strcmp(set_getstr(&ic->irc->set, "voice_buddies"), "notaway")) {
+			irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
+		 	                                         u->away?'-':'+', u->nick );
+		}
+		if(!strcmp(set_getstr(&ic->irc->set, "op_buddies"), "notaway")) {
+			irc_write( ic->irc, ":%s MODE %s %co %s", from, ic->irc->channel,
+		 	                                         u->away?'-':'+', u->nick );
+		}
 		g_free( from );
 	}
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ protocols/nogaim.h	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -136,4 +136,8 @@
 	 * - The user sees this name ie. when imcb_log() is used. */
 	const char *name;
+    /* Maximum Message Size of this protocol.
+     * - Introduced for OTR, in order to fragment large protocol messages.
+     * - 0 means "unlimited". */
+    unsigned int mms;
 
 	/* Added this one to be able to add per-account settings, don't think
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ protocols/oscar/oscar.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -2603,4 +2603,5 @@
 	struct prpl *ret = g_new0(struct prpl, 1);
 	ret->name = "oscar";
+    ret->mms = 2343;       /* this guess taken from libotr UPGRADING file */
 	ret->away_states = oscar_away_states;
 	ret->init = oscar_init;
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ protocols/yahoo/yahoo.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -354,4 +354,5 @@
 	struct prpl *ret = g_new0(struct prpl, 1);
 	ret->name = "yahoo";
+    ret->mms = 832;           /* this guess taken from libotr UPGRADING file */
 	ret->init = byahoo_init;
 	
Index: set.c
===================================================================
--- set.c	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ set.c	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -209,24 +209,143 @@
 }
 
-char *set_eval_ops( set_t *set, char *value )
+char *set_eval_op_root( set_t *set, char *value )
 {
 	irc_t *irc = set->data;
-	
-	if( g_strcasecmp( value, "user" ) == 0 )
-		irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost,
-		                                              irc->channel, "+o-o", irc->nick, irc->mynick );
-	else if( g_strcasecmp( value, "root" ) == 0 )
-		irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost,
-		                                              irc->channel, "-o+o", irc->nick, irc->mynick );
-	else if( g_strcasecmp( value, "both" ) == 0 )
-		irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost,
-		                                              irc->channel, "+oo", irc->nick, irc->mynick );
-	else if( g_strcasecmp( value, "none" ) == 0 )
-		irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost,
-		                                              irc->channel, "-oo", irc->nick, irc->mynick );
+	char *ret = set_eval_bool(set, value);
+	int b = bool2int(ret);
+	
+	irc_write( irc, ":%s!%s@%s MODE %s %s %s", irc->mynick, irc->mynick, irc->myhost,
+	                                           irc->channel, b?"+o":"-o", irc->mynick );
+	return ret;
+}
+
+char *set_eval_op_user( set_t *set, char *value )
+{
+	irc_t *irc = set->data;
+	char *ret = set_eval_bool(set, value);
+	int b = bool2int(ret);
+	
+	irc_write( irc, ":%s!%s@%s MODE %s %s %s", irc->mynick, irc->mynick, irc->myhost,
+	                                           irc->channel, b?"+o":"-o", irc->nick );
+	return ret;
+}
+
+/* generalized version of set_eval_op/voice_buddies */
+char *set_eval_mode_buddies( set_t *set, char *value, char modeflag )
+{
+	irc_t *irc = set->data;
+	char op[64], deop[64];
+	int nop=0, ndeop=0;
+	user_t *u;
+	int mode;
+	
+	if(!strcmp(value, "false"))
+		mode=0;
+	else if(!strcmp(value, "encrypted"))
+		mode=1;
+	else if(!strcmp(value, "trusted"))
+		mode=2;
+	else if(!strcmp(value, "notaway"))
+		mode=3;
 	else
 		return NULL;
 	
+	/* sorry for calling them op/deop - too lazy for search+replace :P */
+	op[0]='\0';
+	deop[0]='\0';
+	for(u=irc->users; u; u=u->next) {
+		/* we're only concerned with online buddies */
+		if(!u->ic || !u->online)
+			continue;
+
+		/* just in case... */
+		if(strlen(u->nick) >= 64)
+			continue;
+		
+		/* dump out ops/deops when the corresponding name list fills up */
+		if(strlen(op)+strlen(u->nick)+2 > 64) {
+			char *flags = g_strnfill(nop, modeflag);
+			irc_write( irc, ":%s!%s@%s MODE %s +%s%s", irc->mynick, irc->mynick, irc->myhost,
+		                                               irc->channel, flags, op );
+		    op[0]='\0';
+		    g_free(flags);
+		}
+		if(strlen(deop)+strlen(u->nick)+2 > 64) {
+			char *flags = g_strnfill(ndeop, modeflag);
+			irc_write( irc, ":%s!%s@%s MODE %s -%s%s", irc->mynick, irc->mynick, irc->myhost,
+		                                               irc->channel, flags, deop );
+		    deop[0]='\0';
+		    g_free(flags);
+		}
+		
+		switch(mode) {
+		/* "false" */
+		case 0:
+			g_strlcat(deop, " ", 64);
+			g_strlcat(deop, u->nick, 64);
+			ndeop++;
+			break;
+		/* "encrypted" */
+		case 1:
+			if(u->encrypted) {
+				g_strlcat(op, " ", 64);
+				g_strlcat(op, u->nick, 64);
+				nop++;
+			} else {
+				g_strlcat(deop, " ", 64);
+				g_strlcat(deop, u->nick, 64);
+				ndeop++;
+			}
+			break;
+		/* "trusted" */
+		case 2:
+			if(u->encrypted > 1) {
+				g_strlcat(op, " ", 64);
+				g_strlcat(op, u->nick, 64);
+				nop++;
+			} else {
+				g_strlcat(deop, " ", 64);
+				g_strlcat(deop, u->nick, 64);
+				ndeop++;
+			}
+			break;
+		/* "notaway" */
+		case 3:
+			if(u->away) {
+				g_strlcat(deop, " ", 64);
+				g_strlcat(deop, u->nick, 64);
+				ndeop++;
+			} else {
+				g_strlcat(op, " ", 64);
+				g_strlcat(op, u->nick, 64);
+				nop++;
+			}
+		}
+	}
+	/* dump anything left in op/deop lists */
+	if(*op) {
+		char *flags = g_strnfill(nop, modeflag);
+		irc_write( irc, ":%s!%s@%s MODE %s +%s%s", irc->mynick, irc->mynick, irc->myhost,
+		                                               irc->channel, flags, op );
+		g_free(flags);
+	}
+	if(*deop) {
+		char *flags = g_strnfill(ndeop, modeflag);
+		irc_write( irc, ":%s!%s@%s MODE %s -%s%s", irc->mynick, irc->mynick, irc->myhost,
+	                                               irc->channel, flags, deop );
+		g_free(flags);
+	}
+	
 	return value;
+}
+
+char *set_eval_op_buddies( set_t *set, char *value )
+{
+	return set_eval_mode_buddies(set, value, 'o');
+}
+
+char *set_eval_voice_buddies( set_t *set, char *value )
+{
+	return set_eval_mode_buddies(set, value, 'v');
 }
 
Index: set.h
===================================================================
--- set.h	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ set.h	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -96,5 +96,8 @@
 /* Some not very generic evaluators that really shouldn't be here... */
 char *set_eval_to_char( set_t *set, char *value );
-char *set_eval_ops( set_t *set, char *value );
+char *set_eval_op_root( set_t *set, char *value );
+char *set_eval_op_user( set_t *set, char *value );
+char *set_eval_op_buddies( set_t *set, char *value );
+char *set_eval_voice_buddies( set_t *set, char *value );
 char *set_eval_charset( set_t *set, char *value );
 
Index: user.h
===================================================================
--- user.h	(revision a13855a57daae6eba05c9600b69f640c2949e944)
+++ user.h	(revision 5a71d9c5b14aa749b532666b71b25ce2afcdc5bb)
@@ -37,4 +37,5 @@
 	char is_private;
 	char online;
+	char encrypted;
 	
 	char *handle;
