disable logs in encrypted sessions.
This commit is contained in:
parent
4bd805cf07
commit
6fe668d863
|
@ -1948,10 +1948,13 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
def _on_toggle_e2e_menuitem_activate(self, widget):
|
||||
if self.session.enable_encryption:
|
||||
self.session.enable_encryption = False
|
||||
self.session.terminate_e2e()
|
||||
|
||||
jid = str(self.session.jid)
|
||||
|
||||
gajim.connections[self.account].delete_session(jid, self.session.thread_id)
|
||||
self.session = gajim.connections[self.account].make_new_session(jid)
|
||||
else:
|
||||
self.session.enable_encryption = True
|
||||
self.session.negotiate_e2e()
|
||||
|
||||
def got_connected(self):
|
||||
|
|
|
@ -921,10 +921,7 @@ class Connection(ConnectionHandlers):
|
|||
|
||||
self.connection.send(msg_iq)
|
||||
|
||||
no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for')\
|
||||
.split()
|
||||
ji = gajim.get_jid_without_resource(jid)
|
||||
if self.name not in no_log_for and ji not in no_log_for:
|
||||
if session.is_loggable():
|
||||
log_msg = msg
|
||||
if subject:
|
||||
log_msg = _('Subject: %s\n%s') % (subject, msg)
|
||||
|
|
|
@ -1461,11 +1461,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
tim = time.strptime(tim, '%Y%m%dT%H:%M:%S')
|
||||
tim = time.localtime(timegm(tim))
|
||||
jid = helpers.get_jid_from_iq(msg)
|
||||
no_log_for = gajim.config.get_per('accounts', self.name,
|
||||
'no_log_for')
|
||||
if not no_log_for:
|
||||
no_log_for = ''
|
||||
no_log_for = no_log_for.split()
|
||||
encrypted = False
|
||||
chatstate = None
|
||||
encTag = msg.getTag('x', namespace = common.xmpp.NS_ENCRYPTED)
|
||||
|
@ -1525,7 +1520,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if not error_msg:
|
||||
error_msg = msgtxt
|
||||
msgtxt = None
|
||||
if self.name not in no_log_for:
|
||||
if session.is_loggable():
|
||||
gajim.logger.write('error', frm, error_msg, tim = tim,
|
||||
subject = subject)
|
||||
self.dispatch('MSGERROR', (frm, msg.getErrorCode(), error_msg, msgtxt,
|
||||
|
@ -1544,15 +1539,14 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if not self.last_history_line.has_key(jid):
|
||||
return
|
||||
self.dispatch('GC_MSG', (frm, msgtxt, tim, has_timestamp, msghtml))
|
||||
if self.name not in no_log_for and not int(float(time.mktime(tim)))\
|
||||
if session.is_loggable() and not int(float(time.mktime(tim)))\
|
||||
<= self.last_history_line[jid] and msgtxt:
|
||||
gajim.logger.write('gc_msg', frm, msgtxt, tim = tim)
|
||||
return
|
||||
elif mtype == 'chat': # it's type 'chat'
|
||||
if not msg.getTag('body') and chatstate is None: #no <body>
|
||||
return
|
||||
if msg.getTag('body') and self.name not in no_log_for and jid not in\
|
||||
no_log_for and msgtxt:
|
||||
if msg.getTag('body') and session.is_loggable() and msgtxt:
|
||||
msg_id = gajim.logger.write('chat_msg_recv', frm, msgtxt, tim = tim,
|
||||
subject = subject)
|
||||
else: # it's single message
|
||||
|
@ -1564,7 +1558,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
password = invite.getTagData('password')
|
||||
self.dispatch('GC_INVITATION',(frm, jid_from, reason, password))
|
||||
return
|
||||
if self.name not in no_log_for and jid not in no_log_for and msgtxt:
|
||||
if session.is_loggable()and msgtxt:
|
||||
gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim,
|
||||
subject = subject)
|
||||
mtype = 'normal'
|
||||
|
@ -1576,7 +1570,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
# END messageCB
|
||||
|
||||
def get_session(self, jid, thread_id, type):
|
||||
'''returns an existing session between this connection and 'jid' or starts a new one.'''
|
||||
'''returns an existing session between this connection and 'jid', returns a new one if none exist.'''
|
||||
session = self.find_session(jid, thread_id, type)
|
||||
|
||||
if session:
|
||||
|
@ -1588,6 +1582,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if bare_jid != jid:
|
||||
session = self.find_session(bare_jid, thread_id, type)
|
||||
if session:
|
||||
print repr(bare_jid), repr(thread_id), repr(jid.split("/")[1])
|
||||
self.move_session(bare_jid, thread_id, jid.split("/")[1])
|
||||
return session
|
||||
|
||||
|
@ -1609,6 +1604,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
del self.sessions[jid]
|
||||
|
||||
def move_session(self, original_jid, thread_id, to_resource):
|
||||
'''moves a session to another resource.'''
|
||||
session = self.sessions[original_jid][thread_id]
|
||||
|
||||
del self.sessions[original_jid][thread_id]
|
||||
|
@ -1622,13 +1618,15 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
self.sessions[new_jid][thread_id] = session
|
||||
|
||||
def find_null_session(self, jid):
|
||||
'''returns the session between this connecting and 'jid' that we last sent a message in.
|
||||
this is needed to handle clients that don't support threads; see XEP-0201.'''
|
||||
all = self.sessions[jid].values()
|
||||
null_sessions = filter(lambda s: not s.received_thread_id, all)
|
||||
null_sessions.sort(key=lambda s: s.last_send)
|
||||
'''finds all of the sessions between us and jid that jid hasn't sent a thread_id in yet.
|
||||
|
||||
return null_sessions[-1]
|
||||
returns the session that we last sent a message to.'''
|
||||
|
||||
sessions_with_jid = self.sessions[jid].values()
|
||||
no_threadid_sessions = filter(lambda s: not s.received_thread_id, sessions_with_jid)
|
||||
no_threadid_sessions.sort(key=lambda s: s.last_send)
|
||||
|
||||
return no_threadid_sessions[-1]
|
||||
|
||||
def make_new_session(self, jid, thread_id = None, type = 'chat'):
|
||||
sess = EncryptedStanzaSession(self, jid, thread_id, type)
|
||||
|
|
|
@ -41,7 +41,7 @@ class StanzaSession(object):
|
|||
|
||||
self.last_send = 0
|
||||
self.status = None
|
||||
self.features = {}
|
||||
self.negotiated = {}
|
||||
|
||||
def generate_thread_id(self):
|
||||
return "".join([random.choice(string.letters) for x in xrange(0,32)])
|
||||
|
@ -55,6 +55,29 @@ class StanzaSession(object):
|
|||
|
||||
self.last_send = time.time()
|
||||
|
||||
def reject_negotiation(self, body = None):
|
||||
msg = xmpp.Message()
|
||||
feature = msg.NT.feature
|
||||
feature.setNamespace(xmpp.NS_FEATURE)
|
||||
|
||||
x = xmpp.DataForm(typ='submit')
|
||||
x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
|
||||
x.addChild(node=xmpp.DataField(name='accept', value='0'))
|
||||
|
||||
feature.addChild(node=x)
|
||||
|
||||
if body:
|
||||
msg.setBody(body)
|
||||
|
||||
self.send(msg)
|
||||
|
||||
self.cancelled_negotiation()
|
||||
|
||||
def cancelled_negotiation(self):
|
||||
'''A negotiation has been cancelled, so reset this session to its default state.'''
|
||||
self.status = None
|
||||
self.negotiated = {}
|
||||
|
||||
def terminate(self):
|
||||
msg = xmpp.Message()
|
||||
feature = msg.NT.feature
|
||||
|
@ -101,6 +124,8 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
def __init__(self, conn, jid, thread_id, type = 'chat'):
|
||||
StanzaSession.__init__(self, conn, jid, thread_id, type = 'chat')
|
||||
|
||||
self.loggable = True
|
||||
|
||||
self.xes = {}
|
||||
self.es = {}
|
||||
|
||||
|
@ -195,12 +220,24 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
def hmac(self, key, content):
|
||||
return HMAC.new(key, content, self.hash_alg).digest()
|
||||
|
||||
# this should be more generic?
|
||||
def sha256(self, string):
|
||||
sh = SHA256.new()
|
||||
sh.update(string)
|
||||
return sh.digest()
|
||||
|
||||
base28_chr = "acdefghikmopqruvwxy123456789"
|
||||
|
||||
def sas_28x5(self, m_a, form_b):
|
||||
sha = self.sha256(m_a + form_b + 'Short Authentication String')
|
||||
lsb24 = self.decode_mpi(sha[-3:])
|
||||
return self.base28(lsb24)
|
||||
|
||||
def base28(self, n):
|
||||
if n >= 28:
|
||||
return self.base28(n / 28) + self.base28_chr[n % 28]
|
||||
else:
|
||||
return self.base28_chr[n]
|
||||
|
||||
def generate_initiator_keys(self, k):
|
||||
return (self.hmac(k, 'Initiator Cipher Key'),
|
||||
self.hmac(k, 'Initiator MAC Key'),
|
||||
|
@ -265,7 +302,15 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
def decrypt(self, ciphertext):
|
||||
return self.decrypter.decrypt(ciphertext)
|
||||
|
||||
def logging_preference(self):
|
||||
if gajim.config.get('log_encrypted_sessions'):
|
||||
return ["may", "mustnot"]
|
||||
else:
|
||||
return ["mustnot", "may"]
|
||||
|
||||
def negotiate_e2e(self):
|
||||
self.negotiated = {}
|
||||
|
||||
request = xmpp.Message()
|
||||
feature = request.NT.feature
|
||||
feature.setNamespace(xmpp.NS_FEATURE)
|
||||
|
@ -276,8 +321,7 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
x.addChild(node=xmpp.DataField(name='accept', value='1', typ='boolean', required=True))
|
||||
|
||||
# this field is incorrectly called 'otr' in XEPs 0116 and 0217
|
||||
# unsupported options: 'mustnot'
|
||||
x.addChild(node=xmpp.DataField(name='logging', typ='list-single', options=['may'], required=True))
|
||||
x.addChild(node=xmpp.DataField(name='logging', typ='list-single', options=self.logging_preference(), required=True))
|
||||
|
||||
# unsupported options: 'disabled', 'enabled'
|
||||
x.addChild(node=xmpp.DataField(name='disclosure', typ='list-single', options=['never'], required=True))
|
||||
|
@ -317,12 +361,10 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
self.send(request)
|
||||
|
||||
# 4.3 esession response (bob)
|
||||
def respond_e2e_bob(self, request_form):
|
||||
response = xmpp.Message()
|
||||
feature = response.NT.feature
|
||||
feature.setNamespace(xmpp.NS_FEATURE)
|
||||
|
||||
x = xmpp.DataForm(typ='submit')
|
||||
def verify_options_bob(self, form):
|
||||
negotiated = {}
|
||||
not_acceptable = []
|
||||
ask_user = {}
|
||||
|
||||
fixed = { 'disclosure': 'never',
|
||||
'security': 'e2e',
|
||||
|
@ -333,21 +375,16 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
'init_pubkey': 'none',
|
||||
'resp_pubkey': 'none',
|
||||
'ver': '1.0',
|
||||
'sas_algs': 'sas28x5',
|
||||
'logging': 'may' }
|
||||
|
||||
not_acceptable = []
|
||||
'sas_algs': 'sas28x5' }
|
||||
|
||||
self.encryptable_stanzas = ['message']
|
||||
|
||||
self.sas_algs = 'sas28x5'
|
||||
self.cipher = AES
|
||||
self.hash_alg = SHA256
|
||||
self.compression = None
|
||||
|
||||
x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
|
||||
x.addChild(node=xmpp.DataField(name='accept', value='true'))
|
||||
|
||||
for name, field in map(lambda name: (name, request_form.getField(name)), request_form.asDict().keys()):
|
||||
for name, field in map(lambda name: (name, form.getField(name)), form.asDict().keys()):
|
||||
options = map(lambda x: x[1], field.getOptions())
|
||||
values = field.getValues()
|
||||
|
||||
|
@ -356,28 +393,61 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
|
||||
if name in fixed:
|
||||
if fixed[name] in options:
|
||||
x.addChild(node=xmpp.DataField(name=name, value=fixed[name]))
|
||||
negotiated[name] = fixed[name]
|
||||
else:
|
||||
not_acceptable.append(name)
|
||||
elif name == 'modp':
|
||||
# the offset of the group we chose (need it to match up with the dhhash)
|
||||
group_order = 0
|
||||
self.modp = int(options[group_order])
|
||||
x.addChild(node=xmpp.DataField(name='modp', value=self.modp))
|
||||
|
||||
g = dh.generators[self.modp]
|
||||
p = dh.primes[self.modp]
|
||||
elif name == 'rekey_freq':
|
||||
preferred = int(options[0])
|
||||
x.addChild(node=xmpp.DataField(name='rekey_freq', value=preferred))
|
||||
|
||||
negotiated['rekey_freq'] = preferred
|
||||
self.rekey_freq = preferred
|
||||
elif name == 'my_nonce':
|
||||
self.n_o = base64.b64decode(field.getValue())
|
||||
elif name == 'logging':
|
||||
my_prefs = self.logging_preference()
|
||||
|
||||
# XXX do something with not_acceptable
|
||||
if my_prefs[0] in options:
|
||||
pref = my_prefs[0]
|
||||
negotiated['logging'] = pref
|
||||
else:
|
||||
for pref in my_prefs:
|
||||
if pref in options:
|
||||
ask_user['logging'] = pref
|
||||
break
|
||||
|
||||
self.He = request_form.getField('dhhashes').getValues()[group_order].encode("utf8")
|
||||
if not 'logging' in ask_user:
|
||||
not_acceptable.append(name)
|
||||
else:
|
||||
# some things are handled elsewhere, some things are not-implemented
|
||||
pass
|
||||
|
||||
return (negotiated, not_acceptable, ask_user)
|
||||
|
||||
# 4.3 esession response (bob)
|
||||
def respond_e2e_bob(self, form, negotiated, not_acceptable):
|
||||
response = xmpp.Message()
|
||||
feature = response.NT.feature
|
||||
feature.setNamespace(xmpp.NS_FEATURE)
|
||||
|
||||
x = xmpp.DataForm(typ='submit')
|
||||
|
||||
x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
|
||||
x.addChild(node=xmpp.DataField(name='accept', value='true'))
|
||||
|
||||
for name in negotiated:
|
||||
x.addChild(node=xmpp.DataField(name=name, value=negotiated[name]))
|
||||
|
||||
self.negotiated = negotiated
|
||||
|
||||
# the offset of the group we chose (need it to match up with the dhhash)
|
||||
group_order = 0
|
||||
self.modp = int(form.getField('modp').getOptions()[group_order][1])
|
||||
x.addChild(node=xmpp.DataField(name='modp', value=self.modp))
|
||||
|
||||
g = dh.generators[self.modp]
|
||||
p = dh.primes[self.modp]
|
||||
|
||||
self.n_o = base64.b64decode(form['my_nonce'])
|
||||
|
||||
dhhashes = form.getField('dhhashes').getValues()
|
||||
self.He = dhhashes[group_order].encode("utf8")
|
||||
|
||||
bytes = int(self.n / 8)
|
||||
|
||||
|
@ -389,30 +459,61 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
self.y = self.srand(2 ** (2 * self.n - 1), p - 1)
|
||||
self.d = self.powmod(g, self.y, p)
|
||||
|
||||
to_add = { 'my_nonce': self.n_s, 'dhkeys': self.encode_mpi(self.d), 'counter': self.encode_mpi(self.c_o), 'nonce': self.n_o }
|
||||
to_add = { 'my_nonce': self.n_s,
|
||||
'dhkeys': self.encode_mpi(self.d),
|
||||
'counter': self.encode_mpi(self.c_o),
|
||||
'nonce': self.n_o }
|
||||
|
||||
for name in to_add:
|
||||
b64ed = base64.b64encode(to_add[name])
|
||||
x.addChild(node=xmpp.DataField(name=name, value=b64ed))
|
||||
|
||||
self.form_a = ''.join(map(lambda el: xmpp.c14n.c14n(el), request_form.getChildren()))
|
||||
self.form_a = ''.join(map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))
|
||||
self.form_b = ''.join(map(lambda el: xmpp.c14n.c14n(el), x.getChildren()))
|
||||
|
||||
self.status = 'responded-e2e'
|
||||
|
||||
feature.addChild(node=x)
|
||||
|
||||
if not_acceptable:
|
||||
pass
|
||||
# XXX
|
||||
# <error code='406' type='modify'>
|
||||
# <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
|
||||
# <feature xmlns='http://jabber.org/protocol/feature-neg'>
|
||||
# <field var='security'/>
|
||||
# </feature>
|
||||
# </error>
|
||||
|
||||
self.send(response)
|
||||
|
||||
# 'Alice Accepts'
|
||||
def accept_e2e_alice(self, form):
|
||||
def verify_options_alice(self, form):
|
||||
# 1. Verify that the ESession options selected by Bob are acceptable
|
||||
|
||||
negotiated = {}
|
||||
ask_user = {}
|
||||
not_acceptable = []
|
||||
|
||||
if not form['logging'] in self.logging_preference():
|
||||
not_acceptable.append(form['logging'])
|
||||
elif form['logging'] != self.logging_preference()[0]:
|
||||
ask_user['logging'] = form['logging']
|
||||
else:
|
||||
negotiated['logging'] = self.logging_preference()[0]
|
||||
|
||||
return (negotiated, not_acceptable, ask_user)
|
||||
|
||||
# 'Alice Accepts', continued
|
||||
def accept_e2e_alice(self, form, negotiated):
|
||||
self.encryptable_stanzas = ['message']
|
||||
self.sas_algs = 'sas28x5'
|
||||
self.cipher = AES
|
||||
self.hash_alg = SHA256
|
||||
self.compression = None
|
||||
|
||||
self.negotiated = negotiated
|
||||
|
||||
# 2. Return a <not-acceptable/> error to Bob unless: 1 < d < p - 1
|
||||
self.form_b = ''.join(map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))
|
||||
|
||||
|
@ -457,6 +558,11 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
|
||||
m_a = self.hmac(self.km_s, self.encode_mpi(old_c_s) + id_a)
|
||||
|
||||
# check for a retained secret
|
||||
# if none exists, prompt the user with the SAS
|
||||
if self.sas_algs == 'sas28x5':
|
||||
print "sas: %s" % self.sas_28x5(m_a, self.form_b)
|
||||
|
||||
result.addChild(node=xmpp.DataField(name='identity', value=base64.b64encode(id_a)))
|
||||
result.addChild(node=xmpp.DataField(name='mac', value=base64.b64encode(m_a)))
|
||||
|
||||
|
@ -520,6 +626,11 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
self.srs = ''
|
||||
oss = ''
|
||||
|
||||
# check for a retained secret
|
||||
# if none exists, prompt the user with the SAS
|
||||
if self.sas_algs == 'sas28x5':
|
||||
print "sas: %s" % self.sas_28x5(m_a, self.form_b)
|
||||
|
||||
k = self.sha256(k + self.srs + oss)
|
||||
|
||||
# XXX I can skip generating ks_o here
|
||||
|
@ -556,6 +667,10 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
self.srs = self.hmac(k, 'New Retained Secret')
|
||||
|
||||
# destroy k
|
||||
|
||||
if self.negotiated['logging'] == 'mustnot':
|
||||
self.loggable = False
|
||||
|
||||
self.status = 'active'
|
||||
self.enable_encryption = True
|
||||
|
||||
|
@ -594,6 +709,9 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
|
||||
# Note: If Alice discovers an error then she SHOULD ignore any encrypted content she received in the stanza.
|
||||
# XXX check for MAC equality?
|
||||
|
||||
if self.negotiated['logging'] == 'mustnot':
|
||||
self.loggable = False
|
||||
|
||||
self.status = 'active'
|
||||
self.enable_encryption = True
|
||||
|
@ -647,3 +765,14 @@ class EncryptedStanzaSession(StanzaSession):
|
|||
StanzaSession.acknowledge_termination(self)
|
||||
|
||||
self.enable_encryption = False
|
||||
|
||||
def is_loggable(self):
|
||||
name = self.conn.name
|
||||
no_log_for = gajim.config.get_per('accounts', name, 'no_log_for')
|
||||
|
||||
if not no_log_for:
|
||||
no_log_for = ''
|
||||
|
||||
no_log_for = no_log_for.split()
|
||||
|
||||
return self.loggable and name not in no_log_for and self.jid not in no_log_for
|
||||
|
|
73
src/gajim.py
73
src/gajim.py
|
@ -1657,13 +1657,64 @@ class Interface:
|
|||
|
||||
def handle_session_negotiation(self, account, data):
|
||||
jid, session, form = data
|
||||
|
||||
# encrypted session states
|
||||
if form.getType() == 'form' and u'e2e' in map(lambda x: x[1], form.getField('security').getOptions()):
|
||||
session.respond_e2e_bob(form)
|
||||
|
||||
if form.getField('accept') and not form['accept'] in ('1', 'true'):
|
||||
dialogs.InformationDialog(_('Session negotiation cancelled.'),
|
||||
_('The client at %s cancelled the session negotiation.') % (jid))
|
||||
session.cancelled_negotiation()
|
||||
return
|
||||
|
||||
# encrypted session states. these are descriped in stanza_session.py
|
||||
|
||||
# bob responds
|
||||
if form.getType() == 'form' and u'e2e' in map(lambda x: x[1], form.getField('security').getOptions()):
|
||||
negotiated, not_acceptable, ask_user = session.verify_options_bob(form)
|
||||
|
||||
if ask_user:
|
||||
def accept_nondefault_options(widget):
|
||||
negotiated.update(ask_user)
|
||||
session.respond_e2e_bob(form, negotiated, not_acceptable)
|
||||
|
||||
dialog.destroy()
|
||||
|
||||
def reject_nondefault_options(widget):
|
||||
for key in ask_user.keys():
|
||||
not_acceptable.append(key) # XXX for some reason I can't concatenate using += here?
|
||||
session.respond_e2e_bob(form, negotiated, not_acceptable)
|
||||
|
||||
dialog.destroy()
|
||||
|
||||
dialog = dialogs.ConfirmationDialog(_('confirm these negotiation options'),
|
||||
_('are the following options acceptable? %s') % (ask_user),
|
||||
on_response_ok = accept_nondefault_options,
|
||||
on_response_cancel = reject_nondefault_options)
|
||||
else:
|
||||
session.respond_e2e_bob(form, negotiated, not_acceptable)
|
||||
|
||||
return
|
||||
|
||||
# alice accepts
|
||||
elif session.status == 'requested-e2e' and form.getType() == 'submit':
|
||||
session.accept_e2e_alice(form)
|
||||
negotiated, not_acceptable, ask_user = session.verify_options_alice(form)
|
||||
|
||||
if ask_user:
|
||||
def accept_nondefault_options(widget):
|
||||
negotiated.update(ask_user)
|
||||
session.accept_e2e_alice(form, negotiated)
|
||||
|
||||
dialog.destroy()
|
||||
|
||||
def reject_nondefault_options(widget):
|
||||
session.reject_negotiation()
|
||||
dialog.destroy()
|
||||
|
||||
dialog = dialogs.ConfirmationDialog(_('confirm these negotiation options'),
|
||||
_('are the following options acceptable? %s') % (ask_user),
|
||||
on_response_ok = accept_nondefault_options,
|
||||
on_response_cancel = reject_nondefault_options)
|
||||
else:
|
||||
session.accept_e2e_alice(form, negotiated)
|
||||
|
||||
return
|
||||
elif session.status == 'responded-e2e' and form.getType() == 'result':
|
||||
session.accept_e2e_bob(form)
|
||||
|
@ -1671,6 +1722,18 @@ class Interface:
|
|||
elif session.status == 'identified-alice' and form.getType() == 'result':
|
||||
session.final_steps_alice(form)
|
||||
return
|
||||
|
||||
if form.getField('terminate'):
|
||||
if form.getField('terminate').getValue() in ('1', 'true'):
|
||||
session.acknowledge_termination()
|
||||
gajim.connections[account].delete_session(str(jid), session.thread_id)
|
||||
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(str(jid), account)
|
||||
|
||||
if ctrl:
|
||||
ctrl.session = gajim.connections[self.account].make_new_session(str(jid))
|
||||
|
||||
return
|
||||
|
||||
# non-esession negotiation. this isn't very useful, but i'm keeping it around
|
||||
# to test my test suite.
|
||||
|
|
|
@ -115,6 +115,8 @@ class MessageControl:
|
|||
return
|
||||
if self.session:
|
||||
print "starting a new session, forgetting about the old one!"
|
||||
gajim.connections[self.account].delete_session(self.contact.jid, self.session.thread_id)
|
||||
|
||||
self.session = session
|
||||
|
||||
def send_message(self, message, keyID = '', type = 'chat',
|
||||
|
|
Loading…
Reference in New Issue