* first draft for archiving negotiation

This commit is contained in:
Anaël Verrier 2009-08-17 19:32:17 +02:00
parent dc2eadc899
commit b64475a2d9
4 changed files with 203 additions and 28 deletions

View File

@ -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

View File

@ -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':

View File

@ -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:

View File

@ -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: