Index: doc/user-guide/commands.xml
===================================================================
--- doc/user-guide/commands.xml	(revision 858ea0166108e9cfab3cc9290fc976f041411cce)
+++ doc/user-guide/commands.xml	(revision 6ce2240e6dd88d86e90ffbfff078bc55b3f49477)
@@ -375,5 +375,5 @@
 
 			<para>
-				Available subcommands: connect, disconnect, smp, trust, info, keygen, and forget. See <emphasis>help otr &lt;subcommand&gt;</emphasis> for more information.
+				Available subcommands: connect, disconnect, smp, smpq, trust, info, keygen, and forget. See <emphasis>help otr &lt;subcommand&gt;</emphasis> for more information.
 			</para>
 
@@ -417,4 +417,21 @@
 				<para>
 					If an SMP challenge has already been received from the given user, responds with the specified secret. Otherwise, a challenge for the secret will be sent. If the protocol succeeds (i.e. both parties gave the same secret), the fingerprint will be trusted.
+				</para>
+				
+			</description>
+		
+		</bitlbee-command>
+		
+		<bitlbee-command name="smpq">
+			<syntax>otr smpq &lt;nick&gt; &lt;question&gt; &lt;answer&gt;</syntax>
+			
+			<description>
+			
+				<para>
+					Attempts to authenticate the given user's active fingerprint via the Socialist Millionaires' Protocol, Q&amp;A style.
+				</para>
+
+				<para>
+					When initiating SMP, this is an alternative to the 'otr smp' command. The shared secret is provided as the answer to a specific question. The question is transmitted with the initial SMP packet and used to prompt the other party. If the protocol succeeds (i.e. they give the correct answer), the fingerprint will be trusted.
 				</para>
 				
Index: irc.c
===================================================================
--- irc.c	(revision 858ea0166108e9cfab3cc9290fc976f041411cce)
+++ irc.c	(revision 6ce2240e6dd88d86e90ffbfff078bc55b3f49477)
@@ -222,4 +222,8 @@
 	log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
 	
+	if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) ) 
+		if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
+			log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
+	
 	for( l = irc_plugins; l; l = l->next )
 	{
@@ -228,8 +232,4 @@
 			p->irc_free( irc );
 	}
-	
-	if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) ) 
-		if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
-			log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
 	
 	irc_connection_list = g_slist_remove( irc_connection_list, irc );
Index: otr.c
===================================================================
--- otr.c	(revision 858ea0166108e9cfab3cc9290fc976f041411cce)
+++ otr.c	(revision 6ce2240e6dd88d86e90ffbfff078bc55b3f49477)
@@ -2,5 +2,5 @@
   * BitlBee -- An IRC to other IM-networks gateway                     *
   *                                                                    *
-  * Copyright 2002-2008 Wilmer van der Gaast and others                *
+  * Copyright 2002-2010 Wilmer van der Gaast and others                *
   \********************************************************************/
 
@@ -87,4 +87,5 @@
 void cmd_otr_disconnect(irc_t *irc, char **args);
 void cmd_otr_smp(irc_t *irc, char **args);
+void cmd_otr_smpq(irc_t *irc, char **args);
 void cmd_otr_trust(irc_t *irc, char **args);
 void cmd_otr_info(irc_t *irc, char **args);
@@ -96,4 +97,5 @@
 	{ "disconnect",  1, &cmd_otr_disconnect, 0 },
 	{ "smp",         2, &cmd_otr_smp,        0 },
+	{ "smpq",        3, &cmd_otr_smpq,       0 },
 	{ "trust",       6, &cmd_otr_trust,      0 },
 	{ "info",        0, &cmd_otr_info,       0 },
@@ -154,4 +156,8 @@
 /* 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 */
+void otr_initiate_smp(irc_t *irc, const char *nick, const char *question,
+		const char *secret);
 
 /* update op/voice flag of given user according to encryption state and settings
@@ -732,47 +738,10 @@
 void cmd_otr_smp(irc_t *irc, char **args)
 {
-	irc_user_t *u;
-	ConnContext *ctx;
-	
-	u = irc_user_by_name(irc, args[1]);
-	if(!u || !u->bu || !u->bu->ic) {
-		irc_usermsg(irc, "%s: unknown user", args[1]);
-		return;
-	}
-	if(!(u->bu->flags & BEE_USER_ONLINE)) {
-		irc_usermsg(irc, "%s is offline", args[1]);
-		return;
-	}
-	
-	ctx = otrl_context_find(irc->otr->us, u->bu->handle,
-		u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 1, NULL, NULL, NULL);
-	if(!ctx) {
-		/* huh? out of memory or what? */
-		return;
-	}
-
-	if(ctx->smstate->nextExpected != OTRL_SMP_EXPECT1) {
-		log_message(LOGLVL_INFO,
-			"SMP already in phase %d, sending abort before reinitiating",
-			ctx->smstate->nextExpected+1);
-		otrl_message_abort_smp(irc->otr->us, &otr_ops, u->bu->ic, ctx);
-		otrl_sm_state_free(ctx->smstate);
-	}
-	
-	/* warning: the following assumes that smstates are cleared whenever an SMP
-	   is completed or aborted! */ 
-	if(ctx->smstate->secret == NULL) {
-		irc_usermsg(irc, "smp: initiating with %s...", u->nick);
-		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 */
-	} else {
-		/* if we're still in EXPECT1 but smstate is initialized, we must have
-		   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, &otr_ops,
-			u->bu->ic, ctx, (unsigned char *)args[2], strlen(args[2]));
-		/* smp is now in EXPECT3 */
-	}
+	otr_initiate_smp(irc, args[1], NULL, args[2]);	/* no question */
+}
+
+void cmd_otr_smpq(irc_t *irc, char **args)
+{
+	otr_initiate_smp(irc, args[1], args[2], args[3]);
 }
 
@@ -1098,8 +1067,27 @@
 	if(!context) {
 		/* huh? out of memory or what? */
+		irc_usermsg(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;
 
+	tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
+	if (tlv) {
+		if (nextMsg != OTRL_SMP_EXPECT1) {
+			irc_usermsg(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_usermsg(irc, "smp: initiated by %s with question: \"%s\"", u->nick,
+				question);
+			irc_usermsg(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) {
@@ -1171,4 +1159,63 @@
 		otrl_sm_state_free(context->smstate);
 		/* smp is in back in EXPECT1 */
+	}
+}
+
+/* combined handler for the 'otr smp' and 'otr smpq' commands */
+void otr_initiate_smp(irc_t *irc, const char *nick, const char *question,
+		const char *secret)
+{
+	irc_user_t *u;
+	ConnContext *ctx;
+
+	u = irc_user_by_name(irc, nick);
+	if(!u || !u->bu || !u->bu->ic) {
+		irc_usermsg(irc, "%s: unknown user", nick);
+		return;
+	}
+	if(!(u->bu->flags & BEE_USER_ONLINE)) {
+		irc_usermsg(irc, "%s is offline", nick);
+		return;
+	}
+	
+	ctx = otrl_context_find(irc->otr->us, u->bu->handle,
+		u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
+	if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
+		irc_usermsg(irc, "smp: otr inactive with %s, try \x02otr connect"
+				" %s\x02", nick, nick);
+		return;
+	}
+
+	if(ctx->smstate->nextExpected != OTRL_SMP_EXPECT1) {
+		log_message(LOGLVL_INFO,
+			"SMP already in phase %d, sending abort before reinitiating",
+			ctx->smstate->nextExpected+1);
+		otrl_message_abort_smp(irc->otr->us, &otr_ops, u->bu->ic, ctx);
+		otrl_sm_state_free(ctx->smstate);
+	}
+	
+	if(question) {
+		/* this was 'otr smpq', just initiate */
+		irc_usermsg(irc, "smp: initiating with %s...", u->nick);
+		otrl_message_initiate_smp_q(irc->otr->us, &otr_ops, u->bu->ic, ctx,
+			question, (unsigned char *)secret, strlen(secret));
+		/* smp is now in EXPECT2 */
+	} else {
+		/* this was 'otr smp', initiate or reply */
+		/* warning: the following assumes that smstates are cleared whenever an SMP
+		   is completed or aborted! */ 
+		if(ctx->smstate->secret == NULL) {
+			irc_usermsg(irc, "smp: initiating with %s...", u->nick);
+			otrl_message_initiate_smp(irc->otr->us, &otr_ops,
+				u->bu->ic, ctx, (unsigned char *)secret, strlen(secret));
+			/* smp is now in EXPECT2 */
+		} else {
+			/* if we're still in EXPECT1 but smstate is initialized, we must have
+			   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, &otr_ops,
+				u->bu->ic, ctx, (unsigned char *)secret, strlen(secret));
+			/* smp is now in EXPECT3 */
+		}
 	}
 }
