Index: otr.c
===================================================================
--- otr.c	(revision c59530844d25ae814141cf56f0fa810968e8df55)
+++ otr.c	(revision 5f4eedefd2a444c213f65283a3d942d6287e6ea2)
@@ -94,4 +94,5 @@
 void yes_forget_fingerprint(gpointer w, void *data);
 void yes_forget_context(gpointer w, void *data);
+void yes_forget_key(gpointer w, void *data);
 
 /* helper to make sure accountname and protocol match the incoming "opdata" */
@@ -129,4 +130,7 @@
 /* find a fingerprint by prefix (given as any number of hex strings) */
 Fingerprint *match_fingerprint(irc_t *irc, ConnContext *ctx, const char **args);
+
+/* find a private key by fingerprint prefix (given as any number of hex strings) */
+OtrlPrivKey *match_privkey(irc_t *irc, const char **args);
 
 /* to log out accounts during keygen */
@@ -288,5 +292,6 @@
 		ConnContext *context = otrl_context_find(ic->irc->otr_us, handle,
 			ic->acc->user, ic->acc->prpl->name, 0, NULL, NULL, NULL);
-		if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
+		if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+		   set_getbool(&ic->irc->set, "color_encrypted")) {
 			/* color according to f'print trust */
 			char color;
@@ -395,6 +400,6 @@
 	log_message(LOGLVL_DEBUG, "op_create_privkey '%s' '%s'", accountname, protocol);
 
-	s = g_strdup_printf("oops, no otr privkey for %s/%s - generate one now?",
-		accountname, protocol);
+	s = g_strdup_printf("oops, no otr privkey for %s - generate one now?",
+		accountname);
 	query_add(ic->irc, ic, s, yes_keygen, NULL, ic->acc);
 }
@@ -794,5 +799,5 @@
 	if(otrl_privkey_find(irc->otr_us, a->user, a->prpl->name)) {
 		char *s = g_strdup_printf("account %d already has a key, replace it?", n);
-		query_add(irc, a->ic, s, yes_keygen, NULL, a);
+		query_add(irc, NULL, s, yes_keygen, NULL, a);
 	} else {
 		otr_keygen(irc, a->user, a->prpl->name);
@@ -802,9 +807,9 @@
 void yes_forget_fingerprint(gpointer w, void *data)
 {
-	struct im_connection *ic = (struct im_connection *)w;
+	irc_t *irc = (irc_t *)w;
 	Fingerprint *fp = (Fingerprint *)data;
 	
 	if(fp == fp->context->active_fingerprint) {
-		irc_usermsg(ic->irc, "that fingerprint is active, terminate otr connection first");
+		irc_usermsg(irc, "that fingerprint is active, terminate otr connection first");
 		return;
 	}
@@ -815,10 +820,10 @@
 void yes_forget_context(gpointer w, void *data)
 {
-	struct im_connection *ic = (struct im_connection *)w;
+	irc_t *irc = (irc_t *)w;
 	ConnContext *ctx = (ConnContext *)data;
 	
 	if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
-		irc_usermsg(ic->irc, "active otr connection with %s, terminate it first",
-			peernick(ic->irc, ctx->username, ctx->protocol));
+		irc_usermsg(irc, "active otr connection with %s, terminate it first",
+			peernick(irc, ctx->username, ctx->protocol));
 		return;
 	}
@@ -827,4 +832,13 @@
 		otrl_context_force_plaintext(ctx);
 	otrl_context_forget(ctx);
+}
+
+void yes_forget_key(gpointer w, void *data)
+{
+	OtrlPrivKey *key = (OtrlPrivKey *)data;
+	
+	/* FIXME: For some reason which /completely eludes me/, this call keeps
+	   barfing on the gcry_sexp_release inside (invalid pointer free). */
+	otrl_privkey_forget(key);
 }
 
@@ -870,5 +884,5 @@
 		otrl_privkey_hash_to_human(human, fp->fingerprint);
 		s = g_strdup_printf("about to forget fingerprint %s, are you sure?", human);
-		query_add(irc, u->ic, s, yes_forget_fingerprint, NULL, fp);
+		query_add(irc, NULL, s, yes_forget_fingerprint, NULL, fp);
 	}
 	
@@ -898,10 +912,26 @@
 		
 		s = g_strdup_printf("about to forget otr data about %s, are you sure?", args[2]);
-		query_add(irc, u->ic, s, yes_forget_context, NULL, ctx);
+		query_add(irc, NULL, s, yes_forget_context, NULL, ctx);
 	}
 	
 	else if(!strcmp(args[1], "key"))
 	{
-		irc_usermsg(irc, "n/a: TODO");
+		OtrlPrivKey *key;
+		char *s;
+		
+		key = match_privkey(irc, ((const char **)args)+2);
+		if(!key) {
+			/* match_privkey does error messages */
+			return;
+		}
+		
+		/* TODO: Find out why 'otr forget key' barfs (cf. yes_forget_key) */
+		irc_usermsg(irc, "otr %s %s: not implemented, please edit \x02%s%s.otr_keys\x02 manually :-/",
+			args[0], args[1], global.conf->configdir, irc->nick);
+		return;
+
+		s = g_strdup_printf("about to forget the private key for %s/%s, are you sure?",
+			key->accountname, key->protocol);
+		query_add(irc, NULL, s, yes_forget_key, NULL, key);
 	}
 	
@@ -1231,4 +1261,70 @@
 }
 
+OtrlPrivKey *match_privkey(irc_t *irc, const char **args)
+{
+	OtrlPrivKey *k, *k2;
+	char human[45];
+	char prefix[45], *p;
+	int n;
+	int i,j;
+	
+	/* assemble the args into a prefix in standard "human" form */
+	n=0;
+	p=prefix;
+	for(i=0; args[i]; i++) {
+		for(j=0; args[i][j]; j++) {
+			char c = toupper(args[i][j]);
+			
+			if(n>=40) {
+				irc_usermsg(irc, "too many fingerprint digits given, expected at most 40");
+				return NULL;
+			}
+			
+			if( (c>='A' && c<='F') || (c>='0' && c<='9') ) {
+				*(p++) = c;
+			} else {
+				irc_usermsg(irc, "invalid hex digit '%c' in block %d", args[i][j], i+1);
+				return NULL;
+			}
+			
+			n++;
+			if(n%8 == 0)
+				*(p++) = ' ';
+		}
+	}
+	*p = '\0';
+	log_message(LOGLVL_DEBUG, "match_privkey '%s'", prefix);
+	log_message(LOGLVL_DEBUG, "n=%d strlen(prefix)=%d", n, strlen(prefix));
+	
+	/* find first key which matches the given prefix */
+	n = strlen(prefix);
+	for(k=irc->otr_us->privkey_root; k; k=k->next) {
+		p = otrl_privkey_fingerprint(irc->otr_us, human, k->accountname, k->protocol);
+		if(!p) /* gah! :-P */
+			continue;
+		if(!strncmp(prefix, human, n))
+			break;
+	}
+	if(!k) {
+		irc_usermsg(irc, "%s: no match", prefix);
+		return NULL;
+	}
+	
+	/* make sure the match, if any, is unique */
+	for(k2=k->next; k2; k2=k2->next) {
+		p = otrl_privkey_fingerprint(irc->otr_us, human, k2->accountname, k2->protocol);
+		if(!p) /* gah! :-P */
+			continue;
+		if(!strncmp(prefix, human, n))
+			break;
+	}
+	if(k2) {
+		irc_usermsg(irc, "%s: multiple matches", prefix);
+		return NULL;
+	}
+	
+	return k;
+}
+
 void show_general_otr_info(irc_t *irc)
 {
