about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/command/command.c4
-rw-r--r--src/command/commands.c35
-rw-r--r--src/otr/otr.c36
-rw-r--r--src/otr/otr.h2
-rw-r--r--src/otr/otrlibv3.c30
-rw-r--r--src/ui/core.c18
-rw-r--r--src/ui/ui.h2
7 files changed, 118 insertions, 9 deletions
diff --git a/src/command/command.c b/src/command/command.c
index 54df170d..d7a60495 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -594,7 +594,7 @@ static struct cmd_t command_defs[] =
           NULL } } },
 
     { "/otr",
-        cmd_otr, parse_args, 1, 2, NULL,
+        cmd_otr, parse_args, 1, 3, NULL,
         { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver|policy", "Off The Record encryption commands.",
         { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver|policy",
           "--------------------------------------------------------------------",
@@ -1071,6 +1071,8 @@ cmd_init(void)
     autocomplete_add(otr_ac, "warn");
     autocomplete_add(otr_ac, "libver");
     autocomplete_add(otr_ac, "policy");
+    autocomplete_add(otr_ac, "question");
+    autocomplete_add(otr_ac, "answer");
 
     otr_log_ac = autocomplete_new();
     autocomplete_add(otr_log_ac, "on");
diff --git a/src/command/commands.c b/src/command/commands.c
index 75f3c793..ad508cc7 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -2804,6 +2804,41 @@ cmd_otr(gchar **args, struct cmd_help_t help)
             }
         }
         return TRUE;
+    } else if (strcmp(args[0], "question") == 0) {
+        char *question = args[1];
+        char *answer = args[2];
+
+        if (question == NULL || answer == NULL) {
+            cons_show("Usage: %s", help.usage);
+            return TRUE;
+        } else {
+            win_type_t win_type = ui_current_win_type();
+            if (win_type != WIN_CHAT) {
+                ui_current_print_line("You must be in an OTR session to trust a recipient.");
+            } else if (!ui_current_win_is_otr()) {
+                ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+            } else {
+                char *recipient = ui_current_recipient();
+                otr_smp_question(recipient, question, answer);
+            }
+            return TRUE;
+        }
+    } else if (strcmp(args[0], "answer") == 0) {
+        win_type_t win_type = ui_current_win_type();
+        if (win_type != WIN_CHAT) {
+            ui_current_print_line("You must be in an OTR session to trust a recipient.");
+        } else if (!ui_current_win_is_otr()) {
+            ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        } else {
+            char *answer = args[1];
+            if (answer == NULL) {
+                cons_show("Usage: %s", help.usage);
+            } else {
+                char *recipient = ui_current_recipient();
+                otr_smp_answer(recipient, answer);
+            }
+        }
+        return TRUE;
     } else {
         cons_show("Usage: %s", help.usage);
         return TRUE;
diff --git a/src/otr/otr.c b/src/otr/otr.c
index 2ad8e752..043dc30f 100644
--- a/src/otr/otr.c
+++ b/src/otr/otr.c
@@ -451,6 +451,40 @@ _otr_smp_secret(const char * const recipient, const char *secret)
 }
 
 static void
+_otr_smp_question(const char * const recipient, const char *question, const char *answer)
+{
+    ConnContext *context = otrlib_context_find(user_state, recipient, jid);
+
+    if (context == NULL) {
+        return;
+    }
+
+    if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
+        return;
+    }
+
+    otrl_message_initiate_smp_q(user_state, &ops, NULL, context, question, (const unsigned char*)answer, strlen(answer));
+    ui_otr_authetication_waiting(recipient);
+}
+
+static void
+_otr_smp_answer(const char * const recipient, const char *answer)
+{
+    ConnContext *context = otrlib_context_find(user_state, recipient, jid);
+
+    if (context == NULL) {
+        return;
+    }
+
+    if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
+        return;
+    }
+
+    // if recipient initiated SMP, send response, else initialise
+    otrl_message_respond_smp(user_state, &ops, NULL, context, (const unsigned char*)answer, strlen(answer));
+}
+
+static void
 _otr_end_session(const char * const recipient)
 {
     otrlib_end_session(user_state, recipient, jid, &ops);
@@ -560,4 +594,6 @@ otr_init_module(void)
     otr_decrypt_message = _otr_decrypt_message;
     otr_free_message = _otr_free_message;
     otr_smp_secret = _otr_smp_secret;
+    otr_smp_question = _otr_smp_question;
+    otr_smp_answer = _otr_smp_answer;
 }
diff --git a/src/otr/otr.h b/src/otr/otr.h
index f2f20d17..87b34b45 100644
--- a/src/otr/otr.h
+++ b/src/otr/otr.h
@@ -49,6 +49,8 @@ void (*otr_trust)(const char * const recipient);
 void (*otr_untrust)(const char * const recipient);
 
 void (*otr_smp_secret)(const char * const recipient, const char *secret);
+void (*otr_smp_question)(const char * const recipient, const char *question, const char *answer);
+void (*otr_smp_answer)(const char * const recipient, const char *answer);
 
 void (*otr_end_session)(const char * const recipient);
 
diff --git a/src/otr/otrlibv3.c b/src/otr/otrlibv3.c
index 7ec8a492..92ca3602 100644
--- a/src/otr/otrlibv3.c
+++ b/src/otr/otrlibv3.c
@@ -132,6 +132,18 @@ otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext
             g_hash_table_insert(smp_initiators, strdup(context->username), strdup(context->username));
         }
     }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT1) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            char *question = (char *)tlv->data;
+            char *eoq = memchr(question, '\0', tlv->len);
+            if (eoq) {
+                ui_smp_recipient_initiated_q(context->username, question);
+            }
+        }
+    }
     tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
     if (tlv) {
         if (nextMsg != OTRL_SMP_EXPECT2) {
@@ -146,14 +158,16 @@ otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext
             otrl_message_abort_smp(user_state, ops, NULL, context);
         } else {
             context->smstate->nextExpected = OTRL_SMP_EXPECT1;
-            if ((context->active_fingerprint->trust != NULL) && (context->active_fingerprint->trust[0] != '\0')) {
-                ui_smp_successful(context->username);
-                ui_trust(context->username);
-                otr_trust(context->username);
-            } else {
-                ui_smp_unsuccessful_sender(context->username);
-                ui_untrust(context->username);
-                otr_untrust(context->username);
+            if (context->smstate->received_question == 0) {
+                if ((context->active_fingerprint->trust != NULL) && (context->active_fingerprint->trust[0] != '\0')) {
+                    ui_smp_successful(context->username);
+                    ui_trust(context->username);
+                    otr_trust(context->username);
+                } else {
+                    ui_smp_unsuccessful_sender(context->username);
+                    ui_untrust(context->username);
+                    otr_untrust(context->username);
+                }
             }
         }
     }
diff --git a/src/ui/core.c b/src/ui/core.c
index 987d8570..bc4a9587 100644
--- a/src/ui/core.c
+++ b/src/ui/core.c
@@ -801,6 +801,23 @@ _ui_smp_recipient_initiated(const char * const recipient)
 }
 
 static void
+_ui_smp_recipient_initiated_q(const char * const recipient, const char *question)
+{
+    ProfWin *window = wins_get_by_recipient(recipient);
+    if (window == NULL) {
+        return;
+    } else {
+        win_vprint_line(window, '!', 0, "%s wants to authenticate your identity with the following question:", recipient);
+        win_vprint_line(window, '!', 0, "  %s", question);
+        win_vprint_line(window, '!', 0, "use '/otr answer <answer>'.");
+        win_update_virtual(window);
+        if (wins_is_current(window)) {
+            ui_current_page_off();
+        }
+    }
+}
+
+static void
 _ui_smp_unsuccessful_sender(const char * const recipient)
 {
     ProfWin *window = wins_get_by_recipient(recipient);
@@ -2090,6 +2107,7 @@ ui_init_module(void)
     ui_trust = _ui_trust;
     ui_untrust = _ui_untrust;
     ui_smp_recipient_initiated = _ui_smp_recipient_initiated;
+    ui_smp_recipient_initiated_q = _ui_smp_recipient_initiated_q;
     ui_smp_successful = _ui_smp_successful;
     ui_smp_unsuccessful_sender = _ui_smp_unsuccessful_sender;
     ui_smp_unsuccessful_receiver = _ui_smp_unsuccessful_receiver;
diff --git a/src/ui/ui.h b/src/ui/ui.h
index 9bf07fd1..5e850c6c 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -64,6 +64,8 @@ void (*ui_gone_insecure)(const char * const recipient);
 void (*ui_trust)(const char * const recipient);
 void (*ui_untrust)(const char * const recipient);
 void (*ui_smp_recipient_initiated)(const char * const recipient);
+void (*ui_smp_recipient_initiated_q)(const char * const recipient, const char *question);
+
 void (*ui_smp_successful)(const char * const recipient);
 void (*ui_smp_unsuccessful_sender)(const char * const recipient);
 void (*ui_smp_unsuccessful_receiver)(const char * const recipient);