From ab0f7899ad60d4eeee3a7760d9b4a7c7ad9feb68 Mon Sep 17 00:00:00 2001
From: Thibaut GIRKA <thib@sitedethib.com>
Date: Mon, 15 Mar 2010 21:34:28 +0100
Subject: [PATCH] Refuse multiple sessions and implement alternative-session;
 make jingle GUI a bit more reliable.

---
 src/chat_control.py          | 13 ++++++++-----
 src/common/jingle.py         | 14 ++++++++++++++
 src/common/jingle_session.py | 12 ++++++++++++
 src/dialogs.py               | 15 ++++-----------
 src/gui_interface.py         |  7 ++++---
 5 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/src/chat_control.py b/src/chat_control.py
index 226bf6c3cc..10c128bc27 100644
--- a/src/chat_control.py
+++ b/src/chat_control.py
@@ -1620,11 +1620,14 @@ class ChatControl(ChatControlBase):
                 'stop': self.JINGLE_STATE_AVAILABLE,
                 'error': self.JINGLE_STATE_ERROR}
 
-        if state in states:
-            jingle_state = states[state]
-            if getattr(self, jingle_type + '_state') == jingle_state:
-                return
-            setattr(self, jingle_type + '_state', jingle_state)
+        jingle_state = states[state]
+        if getattr(self, jingle_type + '_state') == jingle_state:
+            return
+
+        if state == 'stop' and getattr(self, jingle_type + '_sid') not in (None, sid):
+            return
+
+        setattr(self, jingle_type + '_state', jingle_state)
 
         # Destroy existing session with the user when he signs off
         # We need to do that before modifying the sid
diff --git a/src/common/jingle.py b/src/common/jingle.py
index 31c09b6ebc..edc9331566 100644
--- a/src/common/jingle.py
+++ b/src/common/jingle.py
@@ -121,6 +121,20 @@ class ConnectionJingle(object):
             jingle.start_session()
         return jingle.sid
 
+
+    def iter_jingle_sessions(self, jid, sid=None, media=None):
+        if sid:
+            return (session for session in self.__sessions.values() if session.sid == sid)
+        sessions = (session for session in self.__sessions.values() if session.peerjid == jid)
+        if media:
+            if media not in ('audio', 'video'):
+                return tuple()
+            else:
+                return (session for session in sessions if session.get_content(media))
+        else:
+            return sessions
+
+
     def get_jingle_session(self, jid, sid=None, media=None):
         if sid:
             if sid in self.__sessions:
diff --git a/src/common/jingle_session.py b/src/common/jingle_session.py
index c572262c08..df13dcc017 100644
--- a/src/common/jingle_session.py
+++ b/src/common/jingle_session.py
@@ -426,6 +426,16 @@ class JingleSession(object):
         # Jingle with unknown entities, it SHOULD return a <service-unavailable/>
         # error.
 
+        # Check if there's already a session with this user:
+        for session in self.connection.iter_jingle_sessions(self.peerjid):
+            if not session is self:
+                reason = xmpp.Node('reason')
+                alternative_session = reason.setTag('alternative-session')
+                alternative_session.setTagData('sid', session.sid)
+                self.__ack(stanza, jingle, error, action)
+                self._session_terminate(reason)
+                raise xmpp.NodeProcessed
+
         # Lets check what kind of jingle session does the peer want
         contents, contents_rejected, reason_txt = self.__parse_contents(jingle)
 
@@ -520,6 +530,7 @@ class JingleSession(object):
         self.connection.dispatch('JINGLE_ERROR', (self.peerjid, self.sid, text))
 
     def __reason_from_stanza(self, stanza):
+        # TODO: Move to GUI?
         reason = 'success'
         reasons = ['success', 'busy', 'cancel', 'connectivity-error',
                 'decline', 'expired', 'failed-application', 'failed-transport',
@@ -602,6 +613,7 @@ class JingleSession(object):
             jingle.addChild(node=reason)
         self.__broadcast_all(stanza, jingle, None, 'session-terminate-sent')
         self.connection.connection.send(stanza)
+        # TODO: Move to GUI?
         reason, text = self.__reason_from_stanza(jingle)
         if reason not in ('success', 'cancel', 'decline'):
             self.__dispatch_error(reason, reason, text)
diff --git a/src/dialogs.py b/src/dialogs.py
index 101febbb0b..7bcb308fab 100644
--- a/src/dialogs.py
+++ b/src/dialogs.py
@@ -4925,17 +4925,10 @@ class VoIPCallReceivedDialog(object):
             #TODO: Ensure that ctrl.contact.resource == resource
             jid = gajim.get_jid_without_resource(self.fjid)
             resource = gajim.get_resource_from_jid(self.fjid)
-            ctrl = gajim.interface.msg_win_mgr.get_control(self.fjid, self.account)
-            if not ctrl:
-                ctrl = gajim.interface.msg_win_mgr.get_control(jid, self.account)
-            if not ctrl:
-                # open chat control
-                contact = gajim.contacts.get_contact(self.account, jid, resource)
-                if not contact:
-                    contact = gajim.contacts.get_contact(self.account, jid)
-                if not contact:
-                    return
-                ctrl = gajim.interface.new_chat(contact, self.account, resource)
+            ctrl = (gajim.interface.msg_win_mgr.get_control(self.fjid, self.account)
+                    or gajim.interface.msg_win_mgr.get_control(jid, self.account)
+                    or gajim.interface.new_chat_from_jid(self.account, jid))
+
             # Chat control opened, update content's status
             audio = session.get_content('audio')
             video = session.get_content('video')
diff --git a/src/gui_interface.py b/src/gui_interface.py
index 0554af9a19..7035b69997 100644
--- a/src/gui_interface.py
+++ b/src/gui_interface.py
@@ -1775,9 +1775,8 @@ class Interface:
 
         jid = gajim.get_jid_without_resource(peerjid)
         resource = gajim.get_resource_from_jid(peerjid)
-        ctrl = self.msg_win_mgr.get_control(peerjid, account)
-        if not ctrl:
-            ctrl = self.msg_win_mgr.get_control(jid, account)
+        ctrl = (self.msg_win_mgr.get_control(peerjid, account)
+                or self.msg_win_mgr.get_control(jid, account))
         if ctrl:
             if 'audio' in content_types:
                 ctrl.set_audio_state('connection_received', sid)
@@ -2811,6 +2810,8 @@ class Interface:
             ctrl.user_nick = gajim.nicks[account]
         gobject.idle_add(mw.window.grab_focus)
 
+        return ctrl
+
     def on_open_chat_window(self, widget, contact, account, resource=None,
     session=None):
         # Get the window containing the chat
-- 
GitLab