From a3217bcf8c2a8fe64447a0ec02c0d9d9b39e6686 Mon Sep 17 00:00:00 2001
From: James Booth <boothj5@gmail.com>
Date: Sat, 11 Jan 2014 23:28:11 +0000
Subject: [PATCH] End OTR session when user closes chat window

---
 src/otr.c     | 34 ++++++++++++++++++++++++++++++++--
 src/otr.h     |  2 ++
 src/ui/core.c | 28 ++++++++++++++++++++++++++--
 src/ui/ui.h   |  3 ++-
 4 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/src/otr.c b/src/otr.c
index 7e25bdf5..3259543f 100644
--- a/src/otr.c
+++ b/src/otr.c
@@ -27,6 +27,8 @@
 
 #include "otr.h"
 #include "log.h"
+#include "roster_list.h"
+#include "contact.h"
 #include "ui/ui.h"
 
 static OtrlUserState user_state;
@@ -53,9 +55,14 @@ static int
 cb_is_logged_in(void *opdata, const char *accountname,
     const char *protocol, const char *recipient)
 {
+    PContact contact = roster_get_contact(recipient);
+    if (g_strcmp0(p_contact_presence(contact), "offline") == 0) {
+        return 0;
+    } else {
+        return 1;
+    }
 //    cons_debug("cb_is_logged_in: account: %s, protocol: %s, recipient: %s",
 //        accountname, protocol, recipient);
-    return -1;
 }
 
 static void
@@ -350,6 +357,17 @@ otr_is_secure(const char * const recipient)
     }
 }
 
+void
+otr_end_session(const char * const recipient)
+{
+    ConnContext *context = otrl_context_find(user_state, recipient, jid, "xmpp",
+        0, NULL, NULL, NULL);
+
+    if (context != NULL) {
+        otrl_message_disconnect(user_state, &ops, NULL, jid, "xmpp", recipient);
+    }
+}
+
 char *
 otr_get_my_fingerprint(void)
 {
@@ -409,11 +427,23 @@ otr_decrypt_message(const char * const from, const char * const message)
 {
     cons_debug("Decrypting message: %s", message);
     char *decrypted = NULL;
-    int result = otrl_message_receiving(user_state, &ops, NULL, jid, "xmpp", from, message, &decrypted, 0, NULL, NULL);
+    OtrlTLV *tlvs = NULL;
+    OtrlTLV *tlv = NULL;
+    int result = otrl_message_receiving(user_state, &ops, NULL, jid, "xmpp", from, message, &decrypted, &tlvs, NULL, NULL);
 
     // internal libotr message, ignore
     if (result == 1) {
         cons_debug("Internal message.");
+        tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
+        if (tlv) {
+            ConnContext *context = otrl_context_find(user_state, from, jid, "xmpp",
+                0, NULL, NULL, NULL);
+
+            if (context != NULL) {
+                otrl_context_force_plaintext(context);
+                ui_gone_insecure(from);
+            }
+        }
         return NULL;
 
     // message was decrypted, return to user
diff --git a/src/otr.h b/src/otr.h
index 0331a5a3..ad89359c 100644
--- a/src/otr.h
+++ b/src/otr.h
@@ -32,6 +32,8 @@ void otr_keygen(ProfAccount *account);
 gboolean otr_key_loaded(void);
 gboolean otr_is_secure(const char * const recipient);
 
+void otr_end_session(const char * const recipient);
+
 char * otr_get_my_fingerprint(void);
 char * otr_get_their_fingerprint(const char * const recipient);
 
diff --git a/src/ui/core.c b/src/ui/core.c
index 397c6a0e..7acab4c2 100644
--- a/src/ui/core.c
+++ b/src/ui/core.c
@@ -439,7 +439,13 @@ _ui_close_connected_win(int index)
         char *room_jid = ui_recipient(index);
         presence_leave_chat_room(room_jid);
     } else if ((win_type == WIN_CHAT) || (win_type == WIN_PRIVATE)) {
-
+#ifdef HAVE_LIBOTR
+        ProfWin *window = wins_get_by_num(index);
+        if (window->is_otr) {
+            cons_debug("Ending OTR session");
+            otr_end_session(window->from);
+        }
+#endif
         if (prefs_get_boolean(PREF_STATES)) {
             char *recipient = ui_recipient(index);
 
@@ -588,7 +594,7 @@ _ui_next_win(void)
 }
 
 static void
-_ui_gone_secure(char *recipient)
+_ui_gone_secure(const char * const recipient)
 {
     ProfWin *window = wins_get_by_recipient(recipient);
     if (window != NULL) {
@@ -604,6 +610,23 @@ _ui_gone_secure(char *recipient)
     }
 }
 
+static void
+_ui_gone_insecure(const char * const recipient)
+{
+    ProfWin *window = wins_get_by_recipient(recipient);
+    if (window != NULL) {
+        window->is_otr = FALSE;
+
+        if (wins_is_current(window)) {
+            GString *recipient_str = _get_recipient_string(window);
+            title_bar_set_recipient(recipient_str->str);
+            g_string_free(recipient_str, TRUE);
+            title_bar_draw();
+            wins_refresh_current();
+        }
+    }
+}
+
 static void
 _ui_previous_win(void)
 {
@@ -1663,4 +1686,5 @@ ui_init_module(void)
     ui_current_win_is_otr = _ui_current_win_is_otr;
     ui_current_set_otr = _ui_current_set_otr;
     ui_gone_secure = _ui_gone_secure;
+    ui_gone_insecure = _ui_gone_insecure;
 }
diff --git a/src/ui/ui.h b/src/ui/ui.h
index 6f2e6c4f..88be3fbb 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -61,7 +61,8 @@ void (*ui_handle_special_keys)(const wint_t * const ch, const char * const inp,
 void (*ui_switch_win)(const int i);
 void (*ui_next_win)(void);
 void (*ui_previous_win)(void);
-void (*ui_gone_secure)(char *recipient);
+void (*ui_gone_secure)(const char * const recipient);
+void (*ui_gone_insecure)(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);