* first draft for archiving negotiation
This commit is contained in:
parent
dc2eadc899
commit
b64475a2d9
|
@ -2477,6 +2477,8 @@ class ChatControl(ChatControlBase):
|
|||
NS_ESESSION) and not gajim.capscache.is_supported(
|
||||
self.contact, 'notexistant'):
|
||||
self.begin_e2e_negotiation()
|
||||
elif not self.session.accepted:
|
||||
self.begin_archiving_negotiation()
|
||||
else:
|
||||
self.send_chatstate('active', self.contact)
|
||||
|
||||
|
@ -2710,7 +2712,7 @@ class ChatControl(ChatControlBase):
|
|||
else:
|
||||
self.begin_e2e_negotiation()
|
||||
|
||||
def begin_e2e_negotiation(self):
|
||||
def begin_negotiation(self):
|
||||
self.no_autonegotiation = True
|
||||
|
||||
if not self.session:
|
||||
|
@ -2718,8 +2720,14 @@ class ChatControl(ChatControlBase):
|
|||
new_sess = gajim.connections[self.account].make_new_session(fjid, type_=self.type_id)
|
||||
self.set_session(new_sess)
|
||||
|
||||
def begin_e2e_negotiation(self):
|
||||
self.begin_negotiation()
|
||||
self.session.negotiate_e2e(False)
|
||||
|
||||
def begin_archiving_negotiation(self):
|
||||
self.begin_negotiation()
|
||||
self.session.negotiate_archiving()
|
||||
|
||||
def got_connected(self):
|
||||
ChatControlBase.got_connected(self)
|
||||
# Refreshing contact
|
||||
|
|
|
@ -73,6 +73,47 @@ class ConnectionArchive:
|
|||
print iq_
|
||||
self.connection.send(iq_)
|
||||
|
||||
def get_item_pref(self, jid):
|
||||
jid = common.xmpp.JID(jid)
|
||||
if unicode(jid) in self.items:
|
||||
return self.items[jid]
|
||||
|
||||
if jid.getStripped() in self.items:
|
||||
return self.items[jid.getStripped()]
|
||||
|
||||
if jid.getDomain() in self.items:
|
||||
return self.items[jid.getDomain()]
|
||||
|
||||
return self.default
|
||||
|
||||
def logging_preference(self, jid, initiator_options=None):
|
||||
otr = self.get_item_pref(jid)['otr']
|
||||
if initiator_options:
|
||||
if ((initiator_options == ['mustnot'] and otr == 'forbid') or
|
||||
(initiator_options == ['may'] and otr == 'require')):
|
||||
return None
|
||||
|
||||
if (initiator_options == ['mustnot'] or
|
||||
(initiator_options[0] == 'mustnot' and
|
||||
otr not in ('opppose', 'forbid')) or
|
||||
(initiator_options == ['may', 'mustnot'] and
|
||||
otr in ('require', 'prefer'))):
|
||||
return 'mustnot'
|
||||
|
||||
return 'may'
|
||||
|
||||
if otr == 'require':
|
||||
return ['mustnot']
|
||||
|
||||
if otr in ('prefer', 'approve'):
|
||||
return ['mustnot', 'may']
|
||||
|
||||
if otr in ('concede', 'oppose'):
|
||||
return ['may', 'mustnot']
|
||||
|
||||
# otr == 'forbid'
|
||||
return ['may']
|
||||
|
||||
def _ArchiveCB(self, con, iq_obj):
|
||||
print '_ArchiveCB', iq_obj.getType()
|
||||
if iq_obj.getType() == 'error':
|
||||
|
|
|
@ -166,7 +166,114 @@ class StanzaSession(object):
|
|||
self.status = None
|
||||
|
||||
|
||||
class EncryptedStanzaSession(StanzaSession):
|
||||
class ArchivingStanzaSession(StanzaSession):
|
||||
def __init__(self, conn, jid, thread_id, type_='chat'):
|
||||
StanzaSession.__init__(self, conn, jid, thread_id, type_='chat')
|
||||
self.accepted = False
|
||||
|
||||
def archiving_logging_preference(self, initiator_options=None):
|
||||
return self.conn.logging_preference(self.jid, initiator_options)
|
||||
|
||||
def negotiate_archiving(self):
|
||||
self.negotiated = {}
|
||||
|
||||
request = xmpp.Message()
|
||||
feature = request.NT.feature
|
||||
feature.setNamespace(xmpp.NS_FEATURE)
|
||||
|
||||
x = xmpp.DataForm(typ='form')
|
||||
|
||||
x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn',
|
||||
typ='hidden'))
|
||||
x.addChild(node=xmpp.DataField(name='accept', value='1', typ='boolean',
|
||||
required=True))
|
||||
|
||||
x.addChild(node=xmpp.DataField(name='logging', typ='list-single',
|
||||
options=self.archiving_logging_preference(), required=True))
|
||||
|
||||
x.addChild(node=xmpp.DataField(name='disclosure', typ='list-single',
|
||||
options=['never'], required=True))
|
||||
x.addChild(node=xmpp.DataField(name='security', typ='list-single',
|
||||
options=['none'], required=True))
|
||||
|
||||
feature.addChild(node=x)
|
||||
|
||||
self.status = 'requested'
|
||||
|
||||
self.send(request)
|
||||
|
||||
def respond_archiving_bob(self, form):
|
||||
field = form.getField('logging')
|
||||
options = [x[1] for x in field.getOptions()]
|
||||
values = field.getValues()
|
||||
|
||||
logging = self.archiving_logging_preference(options)
|
||||
self.negotiated['logging'] = logging
|
||||
|
||||
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'))
|
||||
|
||||
x.addChild(node=xmpp.DataField(name='logging', value=logging))
|
||||
|
||||
self.status = 'responded'
|
||||
|
||||
feature.addChild(node=x)
|
||||
|
||||
if not logging:
|
||||
response = xmpp.Error(response, xmpp.ERR_NOT_ACCEPTABLE)
|
||||
|
||||
feature = xmpp.Node(xmpp.NS_FEATURE + ' feature')
|
||||
|
||||
n = xmpp.Node('field')
|
||||
n['var'] = 'logging'
|
||||
feature.addChild(node=n)
|
||||
|
||||
response.T.error.addChild(node=feature)
|
||||
|
||||
self.send(response)
|
||||
|
||||
def accept_archiving_bob(self, form):
|
||||
if self.negotiated['logging'] == 'mustnot':
|
||||
self.loggable = False
|
||||
print 'SESSION ACCEPTED', self.loggable
|
||||
self.accepted = True
|
||||
|
||||
def accept_archiving_alice(self, form):
|
||||
negotiated = {}
|
||||
ask_user = {}
|
||||
not_acceptable = []
|
||||
|
||||
if form['logging'] not in self.archiving_logging_preference():
|
||||
raise
|
||||
|
||||
self.negotiated['logging'] = form['logging']
|
||||
|
||||
accept = xmpp.Message()
|
||||
feature = accept.NT.feature
|
||||
feature.setNamespace(xmpp.NS_FEATURE)
|
||||
|
||||
result = xmpp.DataForm(typ='result')
|
||||
|
||||
result.addChild(node=xmpp.DataField(name='FORM_TYPE',
|
||||
value='urn:xmpp:ssn'))
|
||||
result.addChild(node=xmpp.DataField(name='accept', value='1'))
|
||||
|
||||
feature.addChild(node=result)
|
||||
|
||||
self.send(accept)
|
||||
if self.negotiated['logging'] == 'mustnot':
|
||||
self.loggable = False
|
||||
print 'SESSION ACCEPTED', self.loggable
|
||||
self.accepted = True
|
||||
|
||||
|
||||
class EncryptedStanzaSession(ArchivingStanzaSession):
|
||||
'''
|
||||
An encrypted stanza negotiation has several states. They arerepresented as
|
||||
the following values in the 'status' attribute of the session object:
|
||||
|
|
|
@ -114,7 +114,6 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
|||
log_type = 'chat_msg_recv'
|
||||
else:
|
||||
log_type = 'single_msg_recv'
|
||||
|
||||
if self.is_loggable() and msgtxt:
|
||||
try:
|
||||
msg_id = gajim.logger.write(log_type, full_jid_with_resource,
|
||||
|
@ -386,40 +385,53 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
|||
# encrypted session states. these are described in stanza_session.py
|
||||
|
||||
try:
|
||||
# bob responds
|
||||
if form.getType() == 'form' and 'security' in form.asDict():
|
||||
# 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
|
||||
security_options = [x[1] for x in form.getField('security').getOptions()]
|
||||
if security_options == ['none']:
|
||||
self.respond_archiving_bob(form)
|
||||
else:
|
||||
# bob responds
|
||||
|
||||
negotiated, not_acceptable, ask_user = self.verify_options_bob(form)
|
||||
# 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
|
||||
|
||||
if ask_user:
|
||||
def accept_nondefault_options(is_checked):
|
||||
self.dialog.destroy()
|
||||
negotiated.update(ask_user)
|
||||
self.respond_e2e_bob(form, negotiated, not_acceptable)
|
||||
negotiated, not_acceptable, ask_user = self.verify_options_bob(form)
|
||||
|
||||
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)
|
||||
if ask_user:
|
||||
def accept_nondefault_options(is_checked):
|
||||
self.dialog.destroy()
|
||||
negotiated.update(ask_user)
|
||||
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:
|
||||
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)
|
||||
ask_user)),
|
||||
on_response_yes=accept_nondefault_options,
|
||||
on_response_no=reject_nondefault_options)
|
||||
else:
|
||||
self.respond_e2e_bob(form, negotiated, not_acceptable)
|
||||
|
||||
return
|
||||
|
||||
elif self.status == 'requested' and form.getType() == 'submit':
|
||||
try:
|
||||
self.accept_archiving_alice(form)
|
||||
except exceptions.NegotiationError, details:
|
||||
self.fail_bad_negotiation(details)
|
||||
|
||||
return
|
||||
|
||||
|
@ -455,6 +467,13 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
|||
except exceptions.NegotiationError, details:
|
||||
self.fail_bad_negotiation(details)
|
||||
|
||||
return
|
||||
elif self.status == 'responded' and form.getType() == 'result':
|
||||
try:
|
||||
self.accept_archiving_bob(form)
|
||||
except exceptions.NegotiationError, details:
|
||||
self.fail_bad_negotiation(details)
|
||||
|
||||
return
|
||||
elif self.status == 'responded-e2e' and form.getType() == 'result':
|
||||
try:
|
||||
|
|
Loading…
Reference in New Issue