diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index 3b77214324552c6202219f91276c6a6ff0a93b86..bb46f79b2fad4759d10e456ff720f51af520212d 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -1218,33 +1218,6 @@ class ConnectionHandlersBase: # keep track of sessions this connection has with other JIDs self.sessions = {} - def _FeatureNegCB(self, con, stanza, session): - gajim.log.debug('FeatureNegCB') - feature = stanza.getTag(name='feature', namespace=common.xmpp.NS_FEATURE) - form = common.xmpp.DataForm(node=feature.getTag('x')) - - if form['FORM_TYPE'] == 'urn:xmpp:ssn': - self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form)) - else: - reply = stanza.buildReply() - reply.setType('error') - - reply.addChild(feature) - reply.addChild(node=common.xmpp.ErrorNode('service-unavailable', typ='cancel')) - - con.send(reply) - - raise common.xmpp.NodeProcessed - - def _InitE2ECB(self, con, stanza, session): - gajim.log.debug('InitE2ECB') - init = stanza.getTag(name='init', namespace=common.xmpp.NS_ESESSION_INIT) - form = common.xmpp.DataForm(node=init.getTag('x')) - - self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form)) - - raise common.xmpp.NodeProcessed - def get_or_create_session(self, jid, thread_id): '''returns an existing session between this connection and 'jid', returns a new one if none exist.''' @@ -1717,10 +1690,32 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, # check if the message is a XEP-0020 feature negotiation request if msg.getTag('feature', namespace=common.xmpp.NS_FEATURE): if gajim.HAVE_PYCRYPTO: - self._FeatureNegCB(con, msg, session) + feature = msg.getTag(name='feature', namespace=common.xmpp.NS_FEATURE) + form = common.xmpp.DataForm(node=feature.getTag('x')) + + if form['FORM_TYPE'] == 'urn:xmpp:ssn': + session.handle_negotiation(form) + else: + reply = msg.buildReply() + reply.setType('error') + + reply.addChild(feature) + err = common.xmpp.ErrorNode('service-unavailable', typ='cancel') + reply.addChild(node=err) + + con.send(reply) + + raise common.xmpp.NodeProcessed + return + if msg.getTag('init', namespace=common.xmpp.NS_ESESSION_INIT): - self._InitE2ECB(con, msg, session) + init = msg.getTag(name='init', namespace=common.xmpp.NS_ESESSION_INIT) + form = common.xmpp.DataForm(node=init.getTag('x')) + + session.handle_negotiation(form) + + raise common.xmpp.NodeProcessed tim = msg.getTimestamp() tim = helpers.datetime_tuple(tim) diff --git a/src/gajim.py b/src/gajim.py index ea26b4bf292d182d9d13e46053aa4e1d8b666a28..3f7de1af3183d011c2dda1dfa87e3787363205dc 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -246,7 +246,6 @@ import math import gtkgui_helpers import notify import message_control -import negotiation from chat_control import ChatControlBase from chat_control import ChatControl @@ -1752,153 +1751,6 @@ class Interface: else: print 'failed decrypt, unable to find a control to notify you in.' - def handle_session_negotiation(self, account, data): - jid, session, form = data - - if form.getField('accept') and not form['accept'] in ('1', 'true'): - session.cancelled_negotiation() - return - - # encrypted session states. these are described in stanza_session.py - - try: - # bob responds - if form.getType() == 'form' and 'security' in form.asDict(): - def continue_with_negotiation(*args): - if len(args): - self.dialog.destroy() - - # we don't support 3-message negotiation as the responder - if 'dhkeys' in form.asDict(): - session.fail_bad_negotiation('3 message negotiation not supported when responding', ('dhkeys',)) - return - - negotiated, not_acceptable, ask_user = session.verify_options_bob(form) - - if ask_user: - def accept_nondefault_options(is_checked): - self.dialog.destroy() - negotiated.update(ask_user) - session.respond_e2e_bob(form, negotiated, not_acceptable) - - def reject_nondefault_options(): - self.dialog.destroy() - for key in ask_user.keys(): - not_acceptable.append(key) - session.respond_e2e_bob(form, negotiated, not_acceptable) - - self.dialog = dialogs.YesNoDialog(_('Confirm these session options'), - _('''The remote client wants to negotiate an session with these features: - - %s - - Are these options acceptable?''') % (negotiation.describe_features(ask_user)), - on_response_yes=accept_nondefault_options, - on_response_no=reject_nondefault_options) - else: - session.respond_e2e_bob(form, negotiated, not_acceptable) - - def ignore_negotiation(widget): - self.dialog.destroy() - return - - continue_with_negotiation() - - return - - # alice accepts - elif session.status == 'requested-e2e' and form.getType() == 'submit': - negotiated, not_acceptable, ask_user = session.verify_options_alice(form) - - if session.sigmai: - def _cb(on_success): - negotiation.show_sas_dialog(session, jid, session.sas, on_success) - - session.check_identity = _cb - - if ask_user: - def accept_nondefault_options(is_checked): - dialog.destroy() - - negotiated.update(ask_user) - - try: - session.accept_e2e_alice(form, negotiated) - except exceptions.NegotiationError, details: - session.fail_bad_negotiation(details) - - def reject_nondefault_options(): - session.reject_negotiation() - dialog.destroy() - - dialog = dialogs.YesNoDialog(_('Confirm these session options'), - _('The remote client selected these options:\n\n%s\n\nContinue with the session?') % (negotiation.describe_features(ask_user)), - on_response_yes = accept_nondefault_options, - on_response_no = reject_nondefault_options) - else: - try: - session.accept_e2e_alice(form, negotiated) - except exceptions.NegotiationError, details: - session.fail_bad_negotiation(details) - - return - elif session.status == 'responded-e2e' and form.getType() == 'result': - - def _cb(on_success): - negotiation.show_sas_dialog(session, jid, session.sas, on_success) - - session.check_identity = _cb - - try: - session.accept_e2e_bob(form) - except exceptions.NegotiationError, details: - session.fail_bad_negotiation(details) - - return - elif session.status == 'identified-alice' and form.getType() == 'result': - def _cb(on_success): - negotiation.show_sas_dialog(session, jid, session.sas, on_success) - - session.check_identity = _cb - - try: - session.final_steps_alice(form) - except exceptions.NegotiationError, details: - session.fail_bad_negotiation(details) - - return - except exceptions.Cancelled: - # user cancelled the negotiation - - session.reject_negotiation() - - return - - if form.getField('terminate') and\ - form.getField('terminate').getValue() in ('1', 'true'): - jid = str(jid) - - session.acknowledge_termination() - - conn = gajim.connections[account] - conn.delete_session(jid, session.thread_id) - - return - - # non-esession negotiation. this isn't very useful, but i'm keeping it around - # to test my test suite. - if form.getType() == 'form': - if not session.control: - resource = jid.getResource() - contact = gajim.contacts.get_contact(account, str(jid), resource) - if not contact: - connection = gajim.connections[account] - contact = gajim.contacts.create_contact(jid = jid.getStripped(), - resource = resource, show = connection.get_status()) - self.new_chat(contact, account, resource = resource, session = session) - - negotiation.FeatureNegotiationWindow(account, jid, session, form) - def handle_event_privacy_lists_received(self, account, data): # ('PRIVACY_LISTS_RECEIVED', account, list) if not self.instances.has_key(account): @@ -2195,7 +2047,6 @@ class Interface: 'UNIQUE_ROOM_ID_UNSUPPORTED': \ self.handle_event_unique_room_id_unsupported, 'UNIQUE_ROOM_ID_SUPPORTED': self.handle_event_unique_room_id_supported, - 'SESSION_NEG': self.handle_session_negotiation, 'GPG_PASSWORD_REQUIRED': self.handle_event_gpg_password_required, 'SSL_ERROR': self.handle_event_ssl_error, 'FINGERPRINT_ERROR': self.handle_event_fingerprint_error, diff --git a/src/session.py b/src/session.py index 1df578c741b1531bb1f52ab55147f30135dca0c7..7e90d4f6fccc8123989451a61f8371cab6c52281 100644 --- a/src/session.py +++ b/src/session.py @@ -7,12 +7,13 @@ from common import contacts import common.xmpp -import dialogs - import message_control import notify +import dialogs +import negotiation + class ChatControlSession(stanza_session.EncryptedStanzaSession): def __init__(self, conn, jid, thread_id, type = 'chat'): stanza_session.EncryptedStanzaSession.__init__(self, conn, jid, thread_id, type = 'chat') @@ -330,3 +331,137 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): gajim.interface.roster.show_title() # we show the * or [n] # Select contact row in roster. gajim.interface.roster.select_contact(jid, self.conn.name) + + # ---- ESessions stuff --- + + def check_identity(self, on_success): + negotiation.show_sas_dialog(self, self.jid, self.sas, on_success) + + def handle_negotiation(self, form): + if form.getField('accept') and not form['accept'] in ('1', 'true'): + self.cancelled_negotiation() + return + + # encrypted session states. these are described in stanza_session.py + + try: + # bob responds + if form.getType() == 'form' and 'security' in form.asDict(): + def continue_with_negotiation(*args): + if len(args): + self.dialog.destroy() + + # we don't support 3-message negotiation as the responder + if 'dhkeys' in form.asDict(): + self.fail_bad_negotiation('3 message negotiation not supported when responding', ('dhkeys',)) + return + + negotiated, not_acceptable, ask_user = self.verify_options_bob(form) + + if ask_user: + def accept_nondefault_options(is_checked): + self.dialog.destroy() + negotiated.update(ask_user) + self.respond_e2e_bob(form, negotiated, not_acceptable) + + def reject_nondefault_options(): + self.dialog.destroy() + for key in ask_user.keys(): + not_acceptable.append(key) + self.respond_e2e_bob(form, negotiated, not_acceptable) + + self.dialog = dialogs.YesNoDialog(_('Confirm these session options'), + _('''The remote client wants to negotiate an session with these features: + + %s + + Are these options acceptable?''') % (negotiation.describe_features(ask_user)), + on_response_yes=accept_nondefault_options, + on_response_no=reject_nondefault_options) + else: + self.respond_e2e_bob(form, negotiated, not_acceptable) + + def ignore_negotiation(widget): + self.dialog.destroy() + return + + continue_with_negotiation() + + return + + # alice accepts + elif self.status == 'requested-e2e' and form.getType() == 'submit': + negotiated, not_acceptable, ask_user = self.verify_options_alice(form) + + if ask_user: + def accept_nondefault_options(is_checked): + dialog.destroy() + + negotiated.update(ask_user) + + try: + self.accept_e2e_alice(form, negotiated) + except exceptions.NegotiationError, details: + self.fail_bad_negotiation(details) + + def reject_nondefault_options(): + self.reject_negotiation() + dialog.destroy() + + dialog = dialogs.YesNoDialog(_('Confirm these session options'), + _('The remote client selected these options:\n\n%s\n\nContinue with the session?') % (negotiation.describe_features(ask_user)), + on_response_yes = accept_nondefault_options, + on_response_no = reject_nondefault_options) + else: + try: + self.accept_e2e_alice(form, negotiated) + except exceptions.NegotiationError, details: + self.fail_bad_negotiation(details) + + return + elif self.status == 'responded-e2e' and form.getType() == 'result': + try: + self.accept_e2e_bob(form) + except exceptions.NegotiationError, details: + self.fail_bad_negotiation(details) + + return + elif self.status == 'identified-alice' and form.getType() == 'result': + try: + self.final_steps_alice(form) + except exceptions.NegotiationError, details: + self.fail_bad_negotiation(details) + + return + except exceptions.Cancelled: + # user cancelled the negotiation + + self.reject_negotiation() + + return + + if form.getField('terminate') and\ + form.getField('terminate').getValue() in ('1', 'true'): + self.acknowledge_termination() + + self.conn.delete_session(self.jid, self.thread_id) + + return + + # non-esession negotiation. this isn't very useful, but i'm keeping it around + # to test my test suite. + if form.getType() == 'form': + if not self.control: + jid, resource = gajim.get_room_and_nick_from_fjid(self.jid) + + account = self.conn.name + contact = gajim.contacts.get_contact(account, self.jid, resource) + + if not contact: + contact = gajim.contacts.create_contact(jid = jidk, + resource = resource, show = self.conn.get_status()) + + gajim.interface.new_chat(contact, account, + resource = resource, session = self) + + negotiation.FeatureNegotiationWindow(account, self.jid, self, form)