Index: otr.c
===================================================================
--- otr.c	(revision 5d2bc9dfec01f717068b1a38e538c46c2f7e1e70)
+++ otr.c	(revision 352a6b0bd8ecb0d6dcb32c4f4b767fcd315fdf06)
@@ -84,4 +84,6 @@
 void op_convert_free(void *opdata, ConnContext *ctx, char *msg);
 
+void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx,
+	unsigned short percent, char *question);
 
 /** otr sub-command handlers: **/
@@ -159,7 +161,4 @@
    returns NULL if not found */
 irc_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);
 
 /* combined handler for the 'otr smp' and 'otr smpq' commands */
@@ -228,7 +227,7 @@
 	otr_ops.otr_error_message = NULL;       // TODO?
 	otr_ops.otr_error_message_free = NULL;
-	otr_ops.resent_msg_prefix = NULL;       // XXX don't need?
+	otr_ops.resent_msg_prefix = NULL;       // don't need?
 	otr_ops.resent_msg_prefix_free = NULL;
-	otr_ops.handle_smp_event = NULL; // XXX replace smp state machine w/this
+	otr_ops.handle_smp_event = &op_handle_smp_event;
 	otr_ops.handle_msg_event = NULL; // XXX
 	otr_ops.create_instag = NULL;    // XXX
@@ -402,6 +401,4 @@
 		&tlvs, NULL, NULL, NULL);
 
-	otr_handle_smp(ic, iu->bu->handle, tlvs);
-	
 	if(ignore_msg) {
 		/* this was an internal OTR protocol message */
@@ -761,4 +758,71 @@
 }
 	
+/* Socialist Millionaires' Protocol */
+void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx,
+	unsigned short percent, char *question)
+{
+	struct im_connection *ic =
+		check_imc(opdata, ctx->accountname, ctx->protocol);
+	irc_t *irc = ic->bee->ui_data;
+	OtrlUserState us = irc->otr->us;
+	irc_user_t *u = peeruser(irc, ctx->username, ctx->protocol);
+
+	if(!u) return;
+
+	switch(ev) {
+	case OTRL_SMPEVENT_ASK_FOR_SECRET:
+		irc_rootmsg(irc, "smp: initiated by %s"
+			" - respond with \x02otr smp %s <secret>\x02",
+			u->nick, u->nick);
+		break;
+	case OTRL_SMPEVENT_ASK_FOR_ANSWER:
+		irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick,
+			question);
+		irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02",
+			u->nick);
+		break;
+	case OTRL_SMPEVENT_CHEATED:
+		irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting",
+			u->nick);
+		otrl_message_abort_smp(us, &otr_ops, u->bu->ic, ctx);
+		otrl_sm_state_free(ctx->smstate);
+		break;
+	case OTRL_SMPEVENT_NONE:
+		break;
+	case OTRL_SMPEVENT_IN_PROGRESS:
+		break;
+	case OTRL_SMPEVENT_SUCCESS:
+		if(ctx->smstate->received_question) {
+			irc_rootmsg(irc, "smp %s: correct answer, you are trusted",
+				u->nick);
+		} else {
+			irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
+				u->nick);
+		}
+		otrl_sm_state_free(ctx->smstate);
+		break;
+	case OTRL_SMPEVENT_FAILURE:
+		if(ctx->smstate->received_question) {
+			irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted",
+				u->nick);
+		} else {
+			irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
+				u->nick);
+		}
+		otrl_sm_state_free(ctx->smstate);
+		break;
+	case OTRL_SMPEVENT_ABORT:
+	 	irc_rootmsg(irc, "smp: received abort from %s", u->nick);
+		otrl_sm_state_free(ctx->smstate);
+		break;
+	case OTRL_SMPEVENT_ERROR:
+		irc_rootmsg(irc, "smp %s: protocol error, aborting",
+			u->nick);
+		otrl_message_abort_smp(us, &otr_ops, u->bu->ic, ctx);
+		otrl_sm_state_free(ctx->smstate);
+		break;
+	}
+}
+
 
 
@@ -1131,133 +1195,4 @@
 /*** local helpers / subroutines: ***/
 
-/* Socialist Millionaires' Protocol */
-void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
-{
-	irc_t *irc = ic->bee->ui_data;
-	OtrlUserState us = irc->otr->us;
-	OtrlMessageAppOps *ops = &otr_ops;
-	OtrlTLV *tlv = NULL;
-	ConnContext *context;
-	NextExpectedSMP nextMsg;
-	irc_user_t *u;
-	bee_user_t *bu;
-
-	bu = bee_user_by_handle(ic->bee, ic, handle);
-	if(!bu || !(u = bu->ui_data)) return;
-	context = otrl_context_find(us, handle,
-		ic->acc->user, ic->acc->prpl->name, OTRL_INSTAG_MASTER, 1, NULL, NULL, NULL);
-	if(!context) {
-		/* huh? out of memory or what? */
-		irc_rootmsg(irc, "smp: failed to get otr context for %s", u->nick);
-		otrl_message_abort_smp(us, ops, u->bu->ic, context);
-		otrl_sm_state_free(context->smstate);
-		return;
-	}
-	nextMsg = context->smstate->nextExpected;
-
-	if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED) {
-		irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting",
-			u->nick);
-		otrl_message_abort_smp(us, ops, u->bu->ic, context);
-		otrl_sm_state_free(context->smstate);
-		return;
-	}
-
-	tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
-	if (tlv) {
-		if (nextMsg != OTRL_SMP_EXPECT1) {
-			irc_rootmsg(irc, "smp %s: spurious SMP1Q received, aborting", u->nick);
-			otrl_message_abort_smp(us, ops, u->bu->ic, context);
-			otrl_sm_state_free(context->smstate);
-		} else {
-			char *question = g_strndup((char *)tlv->data, tlv->len);
-			irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick,
-				question);
-			irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02",
-				u->nick);
-			g_free(question);
-			/* smp stays in EXPECT1 until user responds */
-		}
-	}
-	tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
-	if (tlv) {
-		if (nextMsg != OTRL_SMP_EXPECT1) {
-			irc_rootmsg(irc, "smp %s: spurious SMP1 received, aborting", u->nick);
-			otrl_message_abort_smp(us, ops, u->bu->ic, context);
-			otrl_sm_state_free(context->smstate);
-		} else {
-			irc_rootmsg(irc, "smp: initiated by %s"
-				" - respond with \x02otr smp %s <secret>\x02",
-				u->nick, u->nick);
-			/* smp stays in EXPECT1 until user responds */
-		}
-	}
-	tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
-	if (tlv) {
-		if (nextMsg != OTRL_SMP_EXPECT2) {
-			irc_rootmsg(irc, "smp %s: spurious SMP2 received, aborting", u->nick);
-			otrl_message_abort_smp(us, ops, u->bu->ic, context);
-			otrl_sm_state_free(context->smstate);
-		} else {
-			/* SMP2 received, otrl_message_receiving will have sent SMP3 */
-			context->smstate->nextExpected = OTRL_SMP_EXPECT4;
-		}
-	}
-	tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
-	if (tlv) {
-		if (nextMsg != OTRL_SMP_EXPECT3) {
-			irc_rootmsg(irc, "smp %s: spurious SMP3 received, aborting", u->nick);
-			otrl_message_abort_smp(us, ops, u->bu->ic, context);
-			otrl_sm_state_free(context->smstate);
-		} else {
-			/* SMP3 received, otrl_message_receiving will have sent SMP4 */
-			if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) {
-				if(context->smstate->received_question) {
-					irc_rootmsg(irc, "smp %s: correct answer, you are trusted",
-						u->nick);
-				} else {
-					irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
-						u->nick);
-				}
-			} else {
-				if(context->smstate->received_question) {
-					irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted",
-						u->nick);
-				} else {
-					irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
-						u->nick);
-				}
-			}
-			otrl_sm_state_free(context->smstate);
-			/* smp is in back in EXPECT1 */
-		}
-	}
-	tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
-	if (tlv) {
-		if (nextMsg != OTRL_SMP_EXPECT4) {
-			irc_rootmsg(irc, "smp %s: spurious SMP4 received, aborting", u->nick);
-			otrl_message_abort_smp(us, ops, u->bu->ic, context);
-			otrl_sm_state_free(context->smstate);
-		} else {
-			/* SMP4 received, otrl_message_receiving will have set fp trust */
-			if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) {
-				irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",
-					u->nick);
-			} else {
-				irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",
-					u->nick);
-			}
-			otrl_sm_state_free(context->smstate);
-			/* smp is in back in EXPECT1 */
-		}
-	}
-	tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
-	if (tlv) {
-	 	irc_rootmsg(irc, "smp: received abort from %s", u->nick);
-		otrl_sm_state_free(context->smstate);
-		/* smp is in back in EXPECT1 */
-	}
-}
-
 /* combined handler for the 'otr smp' and 'otr smpq' commands */
 void otr_smp_or_smpq(irc_t *irc, const char *nick, const char *question,
@@ -1278,5 +1213,5 @@
 	
 	ctx = otrl_context_find(irc->otr->us, u->bu->handle,
-		u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
+		u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);  // XXX
 	if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
 		irc_rootmsg(irc, "smp: otr inactive with %s, try \x02otr connect"
