about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/command/command.c5
-rw-r--r--src/command/commands.c50
-rw-r--r--src/otr/otr.c119
-rw-r--r--src/otr/otr.h12
-rw-r--r--src/otr/otrlib.h5
-rw-r--r--src/otr/otrlibv3.c90
-rw-r--r--src/otr/otrlibv4.c96
-rw-r--r--src/profanity.c3
-rw-r--r--src/ui/core.c134
-rw-r--r--src/ui/ui.h12
10 files changed, 519 insertions, 7 deletions
diff --git a/src/command/command.c b/src/command/command.c
index 95a6158e..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",
           "--------------------------------------------------------------------",
@@ -1066,10 +1066,13 @@ cmd_init(void)
     autocomplete_add(otr_ac, "theirfp");
     autocomplete_add(otr_ac, "trust");
     autocomplete_add(otr_ac, "untrust");
+    autocomplete_add(otr_ac, "secret");
     autocomplete_add(otr_ac, "log");
     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 940a7f5a..ad508cc7 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -2788,7 +2788,57 @@ cmd_otr(gchar **args, struct cmd_help_t help)
             otr_untrust(recipient);
         }
         return TRUE;
+    } else if (strcmp(args[0], "secret") == 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 *secret = args[1];
+            if (secret == NULL) {
+                cons_show("Usage: %s", help.usage);
+            } else {
+                char *recipient = ui_current_recipient();
+                otr_smp_secret(recipient, secret);
+            }
+        }
+        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 e80086af..043dc30f 100644
--- a/src/otr/otr.c
+++ b/src/otr/otr.c
@@ -23,6 +23,7 @@
 #include <libotr/proto.h>
 #include <libotr/privkey.h>
 #include <libotr/message.h>
+#include <libotr/sm.h>
 #include <glib.h>
 
 #include "otr/otr.h"
@@ -40,6 +41,25 @@ static OtrlUserState user_state;
 static OtrlMessageAppOps ops;
 static char *jid;
 static gboolean data_loaded;
+static GHashTable *smp_initiators;
+
+OtrlUserState
+otr_userstate(void)
+{
+    return user_state;
+}
+
+OtrlMessageAppOps *
+otr_messageops(void)
+{
+    return &ops;
+}
+
+GHashTable *
+otr_smpinitators(void)
+{
+    return smp_initiators;
+}
 
 // ops callbacks
 static OtrlPolicy
@@ -134,10 +154,18 @@ _otr_init(void)
     ops.gone_secure = cb_gone_secure;
 
     otrlib_init_ops(&ops);
+    otrlib_init_timer();
+    smp_initiators = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 
     data_loaded = FALSE;
 }
 
+void
+_otr_poll(void)
+{
+    otrlib_poll();
+}
+
 static void
 _otr_on_connect(ProfAccount *account)
 {
@@ -337,9 +365,14 @@ _otr_is_trusted(const char * const recipient)
         return TRUE;
     }
 
-    if (context->active_fingerprint &&
-                g_strcmp0(context->active_fingerprint->trust, "trusted") == 0) {
-        return TRUE;
+    if (context->active_fingerprint) {
+        if (context->active_fingerprint->trust == NULL) {
+            return FALSE;
+        } else if (context->active_fingerprint->trust[0] == '\0') {
+            return FALSE;
+        } else {
+            return TRUE;
+        }
     }
 
     return FALSE;
@@ -359,7 +392,10 @@ _otr_trust(const char * const recipient)
     }
 
     if (context->active_fingerprint) {
-        context->active_fingerprint->trust = "trusted";
+        if (context->active_fingerprint->trust != NULL) {
+            free(context->active_fingerprint->trust);
+        }
+        context->active_fingerprint->trust = strdup("trusted");
         cb_write_fingerprints(NULL);
     }
 
@@ -380,6 +416,9 @@ _otr_untrust(const char * const recipient)
     }
 
     if (context->active_fingerprint) {
+        if (context->active_fingerprint->trust != NULL) {
+            free(context->active_fingerprint->trust);
+        }
         context->active_fingerprint->trust = NULL;
         cb_write_fingerprints(NULL);
     }
@@ -388,6 +427,64 @@ _otr_untrust(const char * const recipient)
 }
 
 static void
+_otr_smp_secret(const char * const recipient, const char *secret)
+{
+    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
+    if (g_hash_table_contains(smp_initiators, recipient)) {
+        otrl_message_respond_smp(user_state, &ops, NULL, context, (const unsigned char*)secret, strlen(secret));
+        ui_otr_authenticating(recipient);
+        g_hash_table_remove(smp_initiators, context->username);
+    } else {
+        otrl_message_initiate_smp(user_state, &ops, NULL, context, (const unsigned char*)secret, strlen(secret));
+        ui_otr_authetication_waiting(recipient);
+    }
+}
+
+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);
@@ -424,7 +521,7 @@ _otr_encrypt_message(const char * const to, const char * const message)
     char *newmessage = NULL;
     gcry_error_t err = otrlib_encrypt_message(user_state, &ops, jid, to, message, &newmessage);
 
-    if (!err == GPG_ERR_NO_ERROR) {
+    if (err != 0) {
         return NULL;
     } else {
         return newmessage;
@@ -441,15 +538,21 @@ _otr_decrypt_message(const char * const from, const char * const message, gboole
 
     // internal libotr message
     if (result == 1) {
+        ConnContext *context = otrlib_context_find(user_state, from, jid);
+
+        // common tlv handling
         OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
         if (tlv) {
-            ConnContext *context = otrlib_context_find(user_state, from, jid);
 
             if (context != NULL) {
                 otrl_context_force_plaintext(context);
                 ui_gone_insecure(from);
             }
         }
+
+        // library version specific tlv handling
+        otrlib_handle_tlvs(user_state, &ops, context, tlvs, smp_initiators);
+
         return NULL;
 
     // message was decrypted, return to user
@@ -476,6 +579,7 @@ otr_init_module(void)
     otr_init = _otr_init;
     otr_libotr_version = _otr_libotr_version;
     otr_start_query = _otr_start_query;
+    otr_poll = _otr_poll;
     otr_on_connect = _otr_on_connect;
     otr_keygen = _otr_keygen;
     otr_key_loaded = _otr_key_loaded;
@@ -489,4 +593,7 @@ otr_init_module(void)
     otr_encrypt_message = _otr_encrypt_message;
     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 5239c033..87b34b45 100644
--- a/src/otr/otr.h
+++ b/src/otr/otr.h
@@ -23,13 +23,21 @@
 #ifndef OTR_H
 #define OTR_H
 
+#include <libotr/proto.h>
+#include <libotr/message.h>
+
 #include "config/accounts.h"
 
 void otr_init_module(void);
 
+OtrlUserState otr_userstate(void);
+OtrlMessageAppOps* otr_messageops(void);
+GHashTable* otr_smpinitators(void);
+
 void (*otr_init)(void);
 char* (*otr_libotr_version)(void);
 char* (*otr_start_query)(void);
+void (*otr_poll)(void);
 void (*otr_on_connect)(ProfAccount *account);
 void (*otr_keygen)(ProfAccount *account);
 
@@ -40,6 +48,10 @@ gboolean (*otr_is_trusted)(const char * const recipient);
 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);
 
 char * (*otr_get_my_fingerprint)(void);
diff --git a/src/otr/otrlib.h b/src/otr/otrlib.h
index 0986c59b..c0ca518f 100644
--- a/src/otr/otrlib.h
+++ b/src/otr/otrlib.h
@@ -29,6 +29,9 @@ char* otrlib_start_query(void);
 
 void otrlib_init_ops(OtrlMessageAppOps *ops);
 
+void otrlib_init_timer(void);
+void otrlib_poll(void);
+
 ConnContext * otrlib_context_find(OtrlUserState user_state, const char * const recipient, char *jid);
 
 void otrlib_end_session(OtrlUserState user_state, const char * const recipient, char *jid, OtrlMessageAppOps *ops);
@@ -39,4 +42,6 @@ gcry_error_t otrlib_encrypt_message(OtrlUserState user_state, OtrlMessageAppOps
 int otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *jid, const char * const from,
     const char * const message, char **decrypted, OtrlTLV **tlvs);
 
+void otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators);
+
 #endif
diff --git a/src/otr/otrlibv3.c b/src/otr/otrlibv3.c
index d1495c9a..92ca3602 100644
--- a/src/otr/otrlibv3.c
+++ b/src/otr/otrlibv3.c
@@ -24,6 +24,8 @@
 #include <libotr/message.h>
 
 #include "ui/ui.h"
+#include "otr/otr.h"
+#include "otr/otrlib.h"
 
 OtrlPolicy
 otrlib_policy(void)
@@ -31,6 +33,16 @@ otrlib_policy(void)
     return OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2 ;
 }
 
+void
+otrlib_init_timer(void)
+{
+}
+
+void
+otrlib_poll(void)
+{
+}
+
 char *
 otrlib_start_query(void)
 {
@@ -106,3 +118,81 @@ otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *j
         NULL,
         NULL);
 }
+
+void
+otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators)
+{
+    NextExpectedSMP nextMsg = context->smstate->nextExpected;
+    OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT1) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            ui_smp_recipient_initiated(context->username);
+            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) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            context->smstate->nextExpected = OTRL_SMP_EXPECT4;
+        }
+    }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT3) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+            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);
+                }
+            }
+        }
+    }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT4) {
+            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_receiver(context->username);
+                ui_untrust(context->username);
+                otr_untrust(context->username);
+            }
+        }
+    }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
+    if (tlv) {
+        context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+        ui_smp_aborted(context->username);
+        ui_untrust(context->username);
+        otr_untrust(context->username);
+    }
+}
diff --git a/src/otr/otrlibv4.c b/src/otr/otrlibv4.c
index c55d2972..d9e7ce01 100644
--- a/src/otr/otrlibv4.c
+++ b/src/otr/otrlibv4.c
@@ -25,6 +25,12 @@
 #include <libotr/message.h>
 
 #include "ui/ui.h"
+#include "log.h"
+#include "otr/otr.h"
+#include "otr/otrlib.h"
+
+static GTimer *timer;
+static unsigned int current_interval;
 
 OtrlPolicy
 otrlib_policy(void)
@@ -32,6 +38,27 @@ otrlib_policy(void)
     return OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2;
 }
 
+void
+otrlib_init_timer(void)
+{
+    OtrlUserState user_state = otr_userstate();
+    timer = g_timer_new();
+    current_interval = otrl_message_poll_get_default_interval(user_state);
+}
+
+void
+otrlib_poll(void)
+{
+    gdouble elapsed = g_timer_elapsed(timer, NULL);
+
+    if (current_interval != 0 && elapsed > current_interval) {
+        OtrlUserState user_state = otr_userstate();
+        OtrlMessageAppOps *ops = otr_messageops();
+        otrl_message_poll(user_state, ops, NULL);
+        g_timer_start(timer);
+    }
+}
+
 char *
 otrlib_start_query(void)
 {
@@ -64,6 +91,12 @@ cb_otr_error_message_free(void *opdata, const char *err_msg)
 }
 
 static void
+cb_timer_control(void *opdata, unsigned int interval)
+{
+    current_interval = interval; 
+}
+
+static void
 cb_handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
     ConnContext *context, const char *message,
     gcry_error_t err)
@@ -77,12 +110,70 @@ cb_handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
     }
 }
 
+static void
+cb_handle_smp_event(void *opdata, OtrlSMPEvent smp_event,
+    ConnContext *context, unsigned short progress_percent,
+    char *question)
+{
+    NextExpectedSMP nextMsg = context->smstate->nextExpected;
+    OtrlUserState user_state = otr_userstate();
+    OtrlMessageAppOps *ops = otr_messageops();
+    GHashTable *smp_initiators = otr_smpinitators();
+
+    switch(smp_event)
+    {
+        case OTRL_SMPEVENT_ASK_FOR_SECRET:
+            ui_smp_recipient_initiated(context->username);
+            g_hash_table_insert(smp_initiators, strdup(context->username), strdup(context->username));
+            break;
+
+        case OTRL_SMPEVENT_SUCCESS:
+            ui_smp_successful(context->username);
+            ui_trust(context->username);
+            break;
+            
+        case OTRL_SMPEVENT_FAILURE:
+            if (nextMsg == OTRL_SMP_EXPECT3) {
+                ui_smp_unsuccessful_sender(context->username);
+                ui_untrust(context->username);
+            } else if (nextMsg == OTRL_SMP_EXPECT4) {
+                ui_smp_unsuccessful_receiver(context->username);
+                ui_untrust(context->username);
+            }
+            break;
+
+        case OTRL_SMPEVENT_ERROR:
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+            break;
+
+        case OTRL_SMPEVENT_CHEATED:
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+            break;
+
+        case OTRL_SMPEVENT_ABORT:
+            ui_smp_aborted(context->username);
+            ui_untrust(context->username);
+            break;
+
+        case OTRL_SMPEVENT_ASK_FOR_ANSWER:
+            break;
+
+        case OTRL_SMPEVENT_IN_PROGRESS:
+            break;
+
+        default:
+            break;
+    }
+}
+
 void
 otrlib_init_ops(OtrlMessageAppOps *ops)
 {
     ops->otr_error_message = cb_otr_error_message;
     ops->otr_error_message_free = cb_otr_error_message_free;
     ops->handle_msg_event = cb_handle_msg_event;
+    ops->handle_smp_event = cb_handle_smp_event;
+    ops->timer_control = cb_timer_control;
 }
 
 ConnContext *
@@ -145,3 +236,8 @@ otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *j
         NULL,
         NULL);
 }
+
+void
+otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators)
+{
+}
diff --git a/src/profanity.c b/src/profanity.c
index 0fb6ebbd..ce0ee431 100644
--- a/src/profanity.c
+++ b/src/profanity.c
@@ -103,6 +103,9 @@ prof_run(const int disable_tls, char *log_level, char *account_name)
 
             ui_handle_special_keys(&ch, inp, size);
             ui_update_screen();
+#ifdef HAVE_LIBOTR
+            otr_poll();
+#endif
             jabber_process_events();
 
             ch = ui_get_char(inp, &size);
diff --git a/src/ui/core.c b/src/ui/core.c
index adebdadd..bc4a9587 100644
--- a/src/ui/core.c
+++ b/src/ui/core.c
@@ -767,6 +767,7 @@ _ui_gone_secure(const char * const recipient, gboolean trusted)
         title_bar_set_recipient(recipient_str->str);
         g_string_free(recipient_str, TRUE);
         win_update_virtual(window);
+        ui_current_page_off();
     } else {
         int num = wins_get_num(window);
         status_bar_new(num);
@@ -785,6 +786,98 @@ _ui_gone_secure(const char * const recipient, gboolean trusted)
 }
 
 static void
+_ui_smp_recipient_initiated(const char * const recipient)
+{
+    ProfWin *window = wins_get_by_recipient(recipient);
+    if (window == NULL) {
+        return;
+    } else {
+        win_vprint_line(window, '!', 0, "%s wants to authenticate your identity, use '/otr secret <secret>'.", recipient);
+        win_update_virtual(window);
+        if (wins_is_current(window)) {
+            ui_current_page_off();
+        }
+    }
+}
+
+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);
+    if (window == NULL) {
+        return;
+    } else {
+        win_vprint_line(window, '!', 0, "Authentication failed, the secret you entered does not match the secret entered by %s.", recipient);
+        win_update_virtual(window);
+        if (wins_is_current(window)) {
+            ui_current_page_off();
+        }
+    }
+}
+
+static void
+_ui_smp_unsuccessful_receiver(const char * const recipient)
+{
+    ProfWin *window = wins_get_by_recipient(recipient);
+    if (window == NULL) {
+        return;
+    } else {
+        win_vprint_line(window, '!', 0, "Authentication failed, the secret entered by %s does not match yours.", recipient);
+        win_update_virtual(window);
+        if (wins_is_current(window)) {
+            ui_current_page_off();
+        }
+    }
+}
+
+static void
+_ui_smp_aborted(const char * const recipient)
+{
+    ProfWin *window = wins_get_by_recipient(recipient);
+    if (window == NULL) {
+        return;
+    } else {
+        win_vprint_line(window, '!', 0, "SMP session aborted.");
+        win_update_virtual(window);
+        if (wins_is_current(window)) {
+            ui_current_page_off();
+        }
+    }
+}
+
+static void
+_ui_smp_successful(const char * const recipient)
+{
+    ProfWin *window = wins_get_by_recipient(recipient);
+    if (window == NULL) {
+        return;
+    } else {
+        win_vprint_line(window, '!', 0, "Authentication successful.");
+        win_update_virtual(window);
+        if (wins_is_current(window)) {
+            ui_current_page_off();
+        }
+    }
+}
+
+static void
 _ui_gone_insecure(const char * const recipient)
 {
     ProfWin *window = wins_get_by_recipient(recipient);
@@ -798,6 +891,7 @@ _ui_gone_insecure(const char * const recipient)
             title_bar_set_recipient(recipient_str->str);
             g_string_free(recipient_str, TRUE);
             win_update_virtual(window);
+            ui_current_page_off();
         }
     }
 }
@@ -816,6 +910,7 @@ _ui_trust(const char * const recipient)
             title_bar_set_recipient(recipient_str->str);
             g_string_free(recipient_str, TRUE);
             win_update_virtual(window);
+            ui_current_page_off();
         }
     }
 }
@@ -834,6 +929,7 @@ _ui_untrust(const char * const recipient)
             title_bar_set_recipient(recipient_str->str);
             g_string_free(recipient_str, TRUE);
             win_update_virtual(window);
+            ui_current_page_off();
         }
     }
 }
@@ -976,6 +1072,36 @@ _ui_current_set_otr(gboolean value)
     current->is_otr = value;
 }
 
+static void
+_ui_otr_authenticating(const char * const recipient)
+{
+    ProfWin *window = wins_get_by_recipient(recipient);
+    if (window == NULL) {
+        return;
+    } else {
+        win_vprint_line(window, '!', 0, "Authenticating %s...", recipient);
+        win_update_virtual(window);
+        if (wins_is_current(window)) {
+            ui_current_page_off();
+        }
+    }
+}
+
+static void
+_ui_otr_authetication_waiting(const char * const recipient)
+{
+    ProfWin *window = wins_get_by_recipient(recipient);
+    if (window == NULL) {
+        return;
+    } else {
+        win_vprint_line(window, '!', 0, "Awaiting authentication from %s...", recipient);
+        win_update_virtual(window);
+        if (wins_is_current(window)) {
+            ui_current_page_off();
+        }
+    }
+}
+
 static int
 _ui_current_win_index(void)
 {
@@ -1974,10 +2100,18 @@ ui_init_module(void)
     ui_ask_password = _ui_ask_password;
     ui_current_win_is_otr = _ui_current_win_is_otr;
     ui_current_set_otr = _ui_current_set_otr;
+    ui_otr_authenticating = _ui_otr_authenticating;
+    ui_otr_authetication_waiting = _ui_otr_authetication_waiting;
     ui_gone_secure = _ui_gone_secure;
     ui_gone_insecure = _ui_gone_insecure;
     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;
+    ui_smp_aborted = _ui_smp_aborted;
     ui_chat_win_contact_online = _ui_chat_win_contact_online;
     ui_chat_win_contact_offline = _ui_chat_win_contact_offline;
     ui_handle_recipient_not_found = _ui_handle_recipient_not_found;
diff --git a/src/ui/ui.h b/src/ui/ui.h
index d56c8f5d..5e850c6c 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -58,10 +58,19 @@ void (*ui_handle_special_keys)(const wint_t * const ch, const char * const inp,
 gboolean (*ui_switch_win)(const int i);
 void (*ui_next_win)(void);
 void (*ui_previous_win)(void);
+
 void (*ui_gone_secure)(const char * const recipient, gboolean trusted);
 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);
+void (*ui_smp_aborted)(const char * const recipient);
+
 unsigned long (*ui_get_idle_time)(void);
 void (*ui_reset_idle_time)(void);
 void (*ui_new_chat_win)(const char * const to);
@@ -85,6 +94,9 @@ void (*ui_current_error_line)(const char * const msg);
 void (*ui_current_page_off)(void);
 void (*ui_current_update_virtual)(void);
 
+void (*ui_otr_authenticating)(const char * const recipient);
+void (*ui_otr_authetication_waiting)(const char * const recipient);
+
 win_type_t (*ui_win_type)(int index);
 char * (*ui_recipient)(int index);
 void (*ui_close_win)(int index);