* first draft for archiving negotiation
This commit is contained in:
		
							parent
							
								
									dc2eadc899
								
							
						
					
					
						commit
						b64475a2d9
					
				
					 4 changed files with 203 additions and 28 deletions
				
			
		|  | @ -2477,6 +2477,8 @@ class ChatControl(ChatControlBase): | ||||||
| 			NS_ESESSION) and not gajim.capscache.is_supported( | 			NS_ESESSION) and not gajim.capscache.is_supported( | ||||||
| 			self.contact, 'notexistant'): | 			self.contact, 'notexistant'): | ||||||
| 				self.begin_e2e_negotiation() | 				self.begin_e2e_negotiation() | ||||||
|  | 			elif not self.session.accepted: | ||||||
|  | 				self.begin_archiving_negotiation() | ||||||
| 		else: | 		else: | ||||||
| 			self.send_chatstate('active', self.contact) | 			self.send_chatstate('active', self.contact) | ||||||
| 
 | 
 | ||||||
|  | @ -2710,7 +2712,7 @@ class ChatControl(ChatControlBase): | ||||||
| 		else: | 		else: | ||||||
| 			self.begin_e2e_negotiation() | 			self.begin_e2e_negotiation() | ||||||
| 
 | 
 | ||||||
| 	def begin_e2e_negotiation(self): | 	def begin_negotiation(self): | ||||||
| 		self.no_autonegotiation = True | 		self.no_autonegotiation = True | ||||||
| 
 | 
 | ||||||
| 		if not self.session: | 		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) | 			new_sess = gajim.connections[self.account].make_new_session(fjid, type_=self.type_id) | ||||||
| 			self.set_session(new_sess) | 			self.set_session(new_sess) | ||||||
| 
 | 
 | ||||||
|  | 	def begin_e2e_negotiation(self): | ||||||
|  | 		self.begin_negotiation() | ||||||
| 		self.session.negotiate_e2e(False) | 		self.session.negotiate_e2e(False) | ||||||
| 
 | 
 | ||||||
|  | 	def begin_archiving_negotiation(self): | ||||||
|  | 		self.begin_negotiation() | ||||||
|  | 		self.session.negotiate_archiving() | ||||||
|  | 
 | ||||||
| 	def got_connected(self): | 	def got_connected(self): | ||||||
| 		ChatControlBase.got_connected(self) | 		ChatControlBase.got_connected(self) | ||||||
| 		# Refreshing contact | 		# Refreshing contact | ||||||
|  |  | ||||||
|  | @ -73,6 +73,47 @@ class ConnectionArchive: | ||||||
| 		print iq_ | 		print iq_ | ||||||
| 		self.connection.send(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): | 	def _ArchiveCB(self, con, iq_obj): | ||||||
| 		print '_ArchiveCB', iq_obj.getType() | 		print '_ArchiveCB', iq_obj.getType() | ||||||
| 		if iq_obj.getType() == 'error': | 		if iq_obj.getType() == 'error': | ||||||
|  |  | ||||||
|  | @ -166,7 +166,114 @@ class StanzaSession(object): | ||||||
| 		self.status = None | 		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 | 	An encrypted stanza negotiation has several states. They arerepresented	as | ||||||
| 	the following values in the 'status' attribute of the session object: | 	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' | 			log_type = 'chat_msg_recv' | ||||||
| 		else: | 		else: | ||||||
| 			log_type = 'single_msg_recv' | 			log_type = 'single_msg_recv' | ||||||
| 
 |  | ||||||
| 		if self.is_loggable() and msgtxt: | 		if self.is_loggable() and msgtxt: | ||||||
| 			try: | 			try: | ||||||
| 				msg_id = gajim.logger.write(log_type, full_jid_with_resource, | 				msg_id = gajim.logger.write(log_type, full_jid_with_resource, | ||||||
|  | @ -386,8 +385,13 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): | ||||||
| 		# encrypted session states. these are described in stanza_session.py | 		# encrypted session states. these are described in stanza_session.py | ||||||
| 
 | 
 | ||||||
| 		try: | 		try: | ||||||
| 			# bob responds |  | ||||||
| 			if form.getType() == 'form' and 'security' in form.asDict(): | 			if form.getType() == 'form' and 'security' in form.asDict(): | ||||||
|  | 				security_options = [x[1] for x in form.getField('security').getOptions()] | ||||||
|  | 				if security_options == ['none']: | ||||||
|  | 					self.respond_archiving_bob(form) | ||||||
|  | 				else: | ||||||
|  | 					# bob responds | ||||||
|  | 
 | ||||||
| 					# we don't support 3-message negotiation as the responder | 					# we don't support 3-message negotiation as the responder | ||||||
| 					if 'dhkeys' in form.asDict(): | 					if 'dhkeys' in form.asDict(): | ||||||
| 						self.fail_bad_negotiation('3 message negotiation not supported ' | 						self.fail_bad_negotiation('3 message negotiation not supported ' | ||||||
|  | @ -423,6 +427,14 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): | ||||||
| 
 | 
 | ||||||
| 				return | 				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 | ||||||
|  | 
 | ||||||
| 			# alice accepts | 			# alice accepts | ||||||
| 			elif self.status == 'requested-e2e' and form.getType() == 'submit': | 			elif self.status == 'requested-e2e' and form.getType() == 'submit': | ||||||
| 				negotiated, not_acceptable, ask_user = self.verify_options_alice( | 				negotiated, not_acceptable, ask_user = self.verify_options_alice( | ||||||
|  | @ -455,6 +467,13 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): | ||||||
| 					except exceptions.NegotiationError, details: | 					except exceptions.NegotiationError, details: | ||||||
| 						self.fail_bad_negotiation(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 | 				return | ||||||
| 			elif self.status == 'responded-e2e' and form.getType() == 'result': | 			elif self.status == 'responded-e2e' and form.getType() == 'result': | ||||||
| 				try: | 				try: | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue