moved session negotiation handling from gajim.py to session.py
This commit is contained in:
parent
984268d845
commit
8b4627049b
|
@ -1218,33 +1218,6 @@ class ConnectionHandlersBase:
|
||||||
# keep track of sessions this connection has with other JIDs
|
# keep track of sessions this connection has with other JIDs
|
||||||
self.sessions = {}
|
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):
|
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.'''
|
'''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
|
# check if the message is a XEP-0020 feature negotiation request
|
||||||
if msg.getTag('feature', namespace=common.xmpp.NS_FEATURE):
|
if msg.getTag('feature', namespace=common.xmpp.NS_FEATURE):
|
||||||
if gajim.HAVE_PYCRYPTO:
|
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
|
return
|
||||||
|
|
||||||
if msg.getTag('init', namespace=common.xmpp.NS_ESESSION_INIT):
|
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 = msg.getTimestamp()
|
||||||
tim = helpers.datetime_tuple(tim)
|
tim = helpers.datetime_tuple(tim)
|
||||||
|
|
149
src/gajim.py
149
src/gajim.py
|
@ -246,7 +246,6 @@ import math
|
||||||
import gtkgui_helpers
|
import gtkgui_helpers
|
||||||
import notify
|
import notify
|
||||||
import message_control
|
import message_control
|
||||||
import negotiation
|
|
||||||
|
|
||||||
from chat_control import ChatControlBase
|
from chat_control import ChatControlBase
|
||||||
from chat_control import ChatControl
|
from chat_control import ChatControl
|
||||||
|
@ -1752,153 +1751,6 @@ class Interface:
|
||||||
else:
|
else:
|
||||||
print 'failed decrypt, unable to find a control to notify you in.'
|
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):
|
def handle_event_privacy_lists_received(self, account, data):
|
||||||
# ('PRIVACY_LISTS_RECEIVED', account, list)
|
# ('PRIVACY_LISTS_RECEIVED', account, list)
|
||||||
if not self.instances.has_key(account):
|
if not self.instances.has_key(account):
|
||||||
|
@ -2195,7 +2047,6 @@ class Interface:
|
||||||
'UNIQUE_ROOM_ID_UNSUPPORTED': \
|
'UNIQUE_ROOM_ID_UNSUPPORTED': \
|
||||||
self.handle_event_unique_room_id_unsupported,
|
self.handle_event_unique_room_id_unsupported,
|
||||||
'UNIQUE_ROOM_ID_SUPPORTED': self.handle_event_unique_room_id_supported,
|
'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,
|
'GPG_PASSWORD_REQUIRED': self.handle_event_gpg_password_required,
|
||||||
'SSL_ERROR': self.handle_event_ssl_error,
|
'SSL_ERROR': self.handle_event_ssl_error,
|
||||||
'FINGERPRINT_ERROR': self.handle_event_fingerprint_error,
|
'FINGERPRINT_ERROR': self.handle_event_fingerprint_error,
|
||||||
|
|
139
src/session.py
139
src/session.py
|
@ -7,12 +7,13 @@ from common import contacts
|
||||||
|
|
||||||
import common.xmpp
|
import common.xmpp
|
||||||
|
|
||||||
import dialogs
|
|
||||||
|
|
||||||
import message_control
|
import message_control
|
||||||
|
|
||||||
import notify
|
import notify
|
||||||
|
|
||||||
|
import dialogs
|
||||||
|
import negotiation
|
||||||
|
|
||||||
class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
||||||
def __init__(self, conn, jid, thread_id, type = 'chat'):
|
def __init__(self, conn, jid, thread_id, type = 'chat'):
|
||||||
stanza_session.EncryptedStanzaSession.__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]
|
gajim.interface.roster.show_title() # we show the * or [n]
|
||||||
# Select contact row in roster.
|
# Select contact row in roster.
|
||||||
gajim.interface.roster.select_contact(jid, self.conn.name)
|
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)
|
||||||
|
|
Loading…
Reference in New Issue