More doc-string (and not only) refactoring
This commit is contained in:
		
							parent
							
								
									99472b1702
								
							
						
					
					
						commit
						6d0f28c47d
					
				
					 9 changed files with 1350 additions and 744 deletions
				
			
		| 
						 | 
					@ -13,12 +13,14 @@
 | 
				
			||||||
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					##   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
##   GNU General Public License for more details.
 | 
					##   GNU General Public License for more details.
 | 
				
			||||||
'''
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
Provides plugs for SASL and NON-SASL authentication mechanisms.
 | 
					Provides plugs for SASL and NON-SASL authentication mechanisms.
 | 
				
			||||||
Can be used both for client and transport authentication.
 | 
					Can be used both for client and transport authentication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
See client_nb.py
 | 
					See client_nb.py
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH
 | 
					from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH
 | 
				
			||||||
from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID
 | 
					from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID
 | 
				
			||||||
from plugin import PlugIn
 | 
					from plugin import PlugIn
 | 
				
			||||||
| 
						 | 
					@ -49,7 +51,8 @@ SASL_UNSUPPORTED = 'not-supported'
 | 
				
			||||||
SASL_IN_PROCESS = 'in-process'
 | 
					SASL_IN_PROCESS = 'in-process'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def challenge_splitter(data):
 | 
					def challenge_splitter(data):
 | 
				
			||||||
	''' Helper function that creates a dict from challenge string.
 | 
						"""
 | 
				
			||||||
 | 
						Helper function that creates a dict from challenge string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Sample challenge string:
 | 
						Sample challenge string:
 | 
				
			||||||
		username="example.org",realm="somerealm",\
 | 
							username="example.org",realm="somerealm",\
 | 
				
			||||||
| 
						 | 
					@ -59,7 +62,7 @@ def challenge_splitter(data):
 | 
				
			||||||
	Expected result for challan:
 | 
						Expected result for challan:
 | 
				
			||||||
		dict['qop'] = ('auth','auth-int','auth-conf')
 | 
							dict['qop'] = ('auth','auth-int','auth-conf')
 | 
				
			||||||
		dict['realm'] = 'somerealm'
 | 
							dict['realm'] = 'somerealm'
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	X_KEYWORD, X_VALUE, X_END = 0, 1, 2
 | 
						X_KEYWORD, X_VALUE, X_END = 0, 1, 2
 | 
				
			||||||
	quotes_open = False
 | 
						quotes_open = False
 | 
				
			||||||
	keyword, value = '', ''
 | 
						keyword, value = '', ''
 | 
				
			||||||
| 
						 | 
					@ -112,16 +115,17 @@ def challenge_splitter(data):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SASL(PlugIn):
 | 
					class SASL(PlugIn):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Implements SASL authentication. Can be plugged into NonBlockingClient
 | 
						Implements SASL authentication. Can be plugged into NonBlockingClient
 | 
				
			||||||
	to start authentication.
 | 
						to start authentication
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self, username, password, on_sasl):
 | 
						def __init__(self, username, password, on_sasl):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		:param user: XMPP username
 | 
							:param user: XMPP username
 | 
				
			||||||
		:param password: XMPP password
 | 
							:param password: XMPP password
 | 
				
			||||||
		:param on_sasl: Callback, will be called after each SASL auth-step.
 | 
							:param on_sasl: Callback, will be called after each SASL auth-step.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		PlugIn.__init__(self)
 | 
							PlugIn.__init__(self)
 | 
				
			||||||
		self.username = username
 | 
							self.username = username
 | 
				
			||||||
		self.password = password
 | 
							self.password = password
 | 
				
			||||||
| 
						 | 
					@ -141,7 +145,9 @@ class SASL(PlugIn):
 | 
				
			||||||
			self.startsasl = None
 | 
								self.startsasl = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def plugout(self):
 | 
						def plugout(self):
 | 
				
			||||||
		''' Remove SASL handlers from owner's dispatcher. Used internally. '''
 | 
							"""
 | 
				
			||||||
 | 
							Remove SASL handlers from owner's dispatcher. Used internally
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if 'features' in  self._owner.__dict__:
 | 
							if 'features' in  self._owner.__dict__:
 | 
				
			||||||
			self._owner.UnregisterHandler('features', self.FeaturesHandler,
 | 
								self._owner.UnregisterHandler('features', self.FeaturesHandler,
 | 
				
			||||||
				xmlns=NS_STREAMS)
 | 
									xmlns=NS_STREAMS)
 | 
				
			||||||
| 
						 | 
					@ -156,13 +162,13 @@ class SASL(PlugIn):
 | 
				
			||||||
				xmlns=NS_SASL)
 | 
									xmlns=NS_SASL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def auth(self):
 | 
						def auth(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Start authentication. Result can be obtained via "SASL.startsasl"
 | 
							Start authentication. Result can be obtained via "SASL.startsasl"
 | 
				
			||||||
		attribute and will be either SASL_SUCCESS or SASL_FAILURE.
 | 
							attribute and will be either SASL_SUCCESS or SASL_FAILURE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Note that successfull auth will take at least two Dispatcher.Process()
 | 
							Note that successfull auth will take at least two Dispatcher.Process()
 | 
				
			||||||
		calls.
 | 
							calls.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if self.startsasl:
 | 
							if self.startsasl:
 | 
				
			||||||
			pass
 | 
								pass
 | 
				
			||||||
		elif self._owner.Dispatcher.Stream.features:
 | 
							elif self._owner.Dispatcher.Stream.features:
 | 
				
			||||||
| 
						 | 
					@ -176,7 +182,9 @@ class SASL(PlugIn):
 | 
				
			||||||
				self.FeaturesHandler, xmlns=NS_STREAMS)
 | 
									self.FeaturesHandler, xmlns=NS_STREAMS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def FeaturesHandler(self, conn, feats):
 | 
						def FeaturesHandler(self, conn, feats):
 | 
				
			||||||
		''' Used to determine if server supports SASL auth. Used internally. '''
 | 
							"""
 | 
				
			||||||
 | 
							Used to determine if server supports SASL auth. Used internally
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if not feats.getTag('mechanisms', namespace=NS_SASL):
 | 
							if not feats.getTag('mechanisms', namespace=NS_SASL):
 | 
				
			||||||
			self.startsasl='not-supported'
 | 
								self.startsasl='not-supported'
 | 
				
			||||||
			log.error('SASL not supported by server')
 | 
								log.error('SASL not supported by server')
 | 
				
			||||||
| 
						 | 
					@ -235,7 +243,9 @@ class SASL(PlugIn):
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def SASLHandler(self, conn, challenge):
 | 
						def SASLHandler(self, conn, challenge):
 | 
				
			||||||
		''' Perform next SASL auth step. Used internally. '''
 | 
							"""
 | 
				
			||||||
 | 
							Perform next SASL auth step. Used internally
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if challenge.getNamespace() != NS_SASL:
 | 
							if challenge.getNamespace() != NS_SASL:
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		### Handle Auth result
 | 
							### Handle Auth result
 | 
				
			||||||
| 
						 | 
					@ -359,12 +369,15 @@ class SASL(PlugIn):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NonBlockingNonSASL(PlugIn):
 | 
					class NonBlockingNonSASL(PlugIn):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Implements old Non-SASL (JEP-0078) authentication used in jabberd1.4 and
 | 
						Implements old Non-SASL (JEP-0078) authentication used in jabberd1.4 and
 | 
				
			||||||
	transport authentication.
 | 
						transport authentication
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self, user, password, resource, on_auth):
 | 
						def __init__(self, user, password, resource, on_auth):
 | 
				
			||||||
		''' Caches username, password and resource for auth. '''
 | 
							"""
 | 
				
			||||||
 | 
							Caches username, password and resource for auth
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		PlugIn.__init__(self)
 | 
							PlugIn.__init__(self)
 | 
				
			||||||
		self.user = user
 | 
							self.user = user
 | 
				
			||||||
		if password is None:
 | 
							if password is None:
 | 
				
			||||||
| 
						 | 
					@ -375,10 +388,10 @@ class NonBlockingNonSASL(PlugIn):
 | 
				
			||||||
		self.on_auth = on_auth
 | 
							self.on_auth = on_auth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def plugin(self, owner):
 | 
						def plugin(self, owner):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Determine the best auth method (digest/0k/plain) and use it for auth.
 | 
							Determine the best auth method (digest/0k/plain) and use it for auth.
 | 
				
			||||||
		Returns used method name on success. Used internally.
 | 
							Returns used method name on success. Used internally
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		log.info('Querying server about possible auth methods')
 | 
							log.info('Querying server about possible auth methods')
 | 
				
			||||||
		self.owner = owner
 | 
							self.owner = owner
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -438,10 +451,11 @@ class NonBlockingNonSASL(PlugIn):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NonBlockingBind(PlugIn):
 | 
					class NonBlockingBind(PlugIn):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Bind some JID to the current connection to allow router know of our
 | 
						Bind some JID to the current connection to allow router know of our
 | 
				
			||||||
	location. Must be plugged after successful SASL auth.
 | 
						location. Must be plugged after successful SASL auth
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self):
 | 
						def __init__(self):
 | 
				
			||||||
		PlugIn.__init__(self)
 | 
							PlugIn.__init__(self)
 | 
				
			||||||
		self.bound = None
 | 
							self.bound = None
 | 
				
			||||||
| 
						 | 
					@ -459,10 +473,10 @@ class NonBlockingBind(PlugIn):
 | 
				
			||||||
				xmlns=NS_STREAMS)
 | 
									xmlns=NS_STREAMS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def FeaturesHandler(self, conn, feats):
 | 
						def FeaturesHandler(self, conn, feats):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Determine if server supports resource binding and set some internal
 | 
							Determine if server supports resource binding and set some internal
 | 
				
			||||||
		attributes accordingly.
 | 
							attributes accordingly
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if not feats.getTag('bind', namespace=NS_BIND):
 | 
							if not feats.getTag('bind', namespace=NS_BIND):
 | 
				
			||||||
			log.error('Server does not requested binding.')
 | 
								log.error('Server does not requested binding.')
 | 
				
			||||||
			# we try to bind resource anyway
 | 
								# we try to bind resource anyway
 | 
				
			||||||
| 
						 | 
					@ -476,14 +490,16 @@ class NonBlockingBind(PlugIn):
 | 
				
			||||||
		self.bound = []
 | 
							self.bound = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def plugout(self):
 | 
						def plugout(self):
 | 
				
			||||||
		''' Remove Bind handler from owner's dispatcher. Used internally. '''
 | 
							"""
 | 
				
			||||||
 | 
							Remove Bind handler from owner's dispatcher. Used internally
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self._owner.UnregisterHandler('features', self.FeaturesHandler,
 | 
							self._owner.UnregisterHandler('features', self.FeaturesHandler,
 | 
				
			||||||
			xmlns=NS_STREAMS)
 | 
								xmlns=NS_STREAMS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def NonBlockingBind(self, resource=None, on_bound=None):
 | 
						def NonBlockingBind(self, resource=None, on_bound=None):
 | 
				
			||||||
		''' Perform binding.
 | 
							"""
 | 
				
			||||||
		Use provided resource name or random (if not provided).
 | 
							Perform binding. Use provided resource name or random (if not provided).
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self.on_bound = on_bound
 | 
							self.on_bound = on_bound
 | 
				
			||||||
		self._resource = resource
 | 
							self._resource = resource
 | 
				
			||||||
		if self._resource:
 | 
							if self._resource:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,11 +125,12 @@ class NonBlockingBOSH(NonBlockingTransport):
 | 
				
			||||||
			log.warn('set_timeout: TIMEOUT NOT SET: state is %s, fd is %s' % (self.get_state(), self.fd))
 | 
								log.warn('set_timeout: TIMEOUT NOT SET: state is %s, fd is %s' % (self.get_state(), self.fd))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def on_http_request_possible(self):
 | 
						def on_http_request_possible(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Called when HTTP request it's possible to send a HTTP request. It can be when
 | 
							Called when HTTP request it's possible to send a HTTP request. It can be when
 | 
				
			||||||
		socket is connected or when HTTP response arrived.
 | 
							socket is connected or when HTTP response arrived
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		There should be always one pending request to BOSH CM.
 | 
							There should be always one pending request to BOSH CM.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		log.debug('on_http_req possible, state:\n%s' % self.get_current_state())
 | 
							log.debug('on_http_req possible, state:\n%s' % self.get_current_state())
 | 
				
			||||||
		if self.get_state()==DISCONNECTED: return
 | 
							if self.get_state()==DISCONNECTED: return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,14 +150,18 @@ class NonBlockingBOSH(NonBlockingTransport):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def get_socket_in(self, state):
 | 
						def get_socket_in(self, state):
 | 
				
			||||||
		''' gets sockets in desired state '''
 | 
							"""
 | 
				
			||||||
 | 
							Get sockets in desired state
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		for s in self.http_socks:
 | 
							for s in self.http_socks:
 | 
				
			||||||
			if s.get_state()==state: return s
 | 
								if s.get_state()==state: return s
 | 
				
			||||||
		return None
 | 
							return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def get_free_socket(self):
 | 
						def get_free_socket(self):
 | 
				
			||||||
		''' Selects and returns socket eligible for sending a data to.'''
 | 
							"""
 | 
				
			||||||
 | 
							Select and returns socket eligible for sending a data to
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if self.http_pipelining:
 | 
							if self.http_pipelining:
 | 
				
			||||||
			return self.get_socket_in(CONNECTED)
 | 
								return self.get_socket_in(CONNECTED)
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
| 
						 | 
					@ -176,10 +181,10 @@ class NonBlockingBOSH(NonBlockingTransport):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def send_BOSH(self, payload):
 | 
						def send_BOSH(self, payload):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Tries to send a stanza in payload by appeding it to a buffer and plugging a
 | 
							Tries to send a stanza in payload by appeding it to a buffer and plugging a
 | 
				
			||||||
		free socket for writing.
 | 
							free socket for writing.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		total_pending_reqs = sum([s.pending_requests for s in self.http_socks])
 | 
							total_pending_reqs = sum([s.pending_requests for s in self.http_socks])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# when called after HTTP response (Payload=None) and when there are already
 | 
							# when called after HTTP response (Payload=None) and when there are already
 | 
				
			||||||
| 
						 | 
					@ -236,15 +241,16 @@ class NonBlockingBOSH(NonBlockingTransport):
 | 
				
			||||||
			log.error('=====!!!!!!!!====> Couldn\'t get free socket in plug_socket())')
 | 
								log.error('=====!!!!!!!!====> Couldn\'t get free socket in plug_socket())')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def build_stanza(self, socket):
 | 
						def build_stanza(self, socket):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Builds a BOSH body tag from data in buffers and adds key, rid and ack
 | 
							Build a BOSH body tag from data in buffers and adds key, rid and ack
 | 
				
			||||||
		attributes to it.
 | 
							attributes to it
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		This method is called from _do_send() of underlying transport. This is to
 | 
							This method is called from _do_send() of underlying transport. This is to
 | 
				
			||||||
		ensure rid and keys will be processed in correct order. If I generate them
 | 
							ensure rid and keys will be processed in correct order. If I generate
 | 
				
			||||||
		before	plugging a socket for write (and did it for two sockets/HTTP
 | 
							them before	plugging a socket for write (and did it for two sockets/HTTP
 | 
				
			||||||
		connections) in parallel, they might be sent in wrong order, which results
 | 
							connections) in parallel, they might be sent in wrong order, which
 | 
				
			||||||
		in violating the BOSH session and server-side disconnect.
 | 
							results in violating the BOSH session and server-side disconnect.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if self.prio_bosh_stanzas:
 | 
							if self.prio_bosh_stanzas:
 | 
				
			||||||
			stanza, add_payload = self.prio_bosh_stanzas.pop(0)
 | 
								stanza, add_payload = self.prio_bosh_stanzas.pop(0)
 | 
				
			||||||
			if add_payload:
 | 
								if add_payload:
 | 
				
			||||||
| 
						 | 
					@ -285,10 +291,11 @@ class NonBlockingBOSH(NonBlockingTransport):
 | 
				
			||||||
				self.wait_cb_time)
 | 
									self.wait_cb_time)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def on_persistent_fallback(self, socket):
 | 
						def on_persistent_fallback(self, socket):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Called from underlying transport when server closes TCP connection.
 | 
							Called from underlying transport when server closes TCP connection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param socket: disconnected transport object
 | 
							:param socket: disconnected transport object
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if socket.http_persistent:
 | 
							if socket.http_persistent:
 | 
				
			||||||
			log.warn('Fallback to nonpersistent HTTP (no pipelining as well)')
 | 
								log.warn('Fallback to nonpersistent HTTP (no pipelining as well)')
 | 
				
			||||||
			socket.http_persistent = False
 | 
								socket.http_persistent = False
 | 
				
			||||||
| 
						 | 
					@ -302,9 +309,10 @@ class NonBlockingBOSH(NonBlockingTransport):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def handle_body_attrs(self, stanza_attrs):
 | 
						def handle_body_attrs(self, stanza_attrs):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Called for each incoming body stanza from dispatcher. Checks body attributes.
 | 
							Called for each incoming body stanza from dispatcher. Checks body
 | 
				
			||||||
		'''
 | 
							attributes.
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.remove_bosh_wait_timeout()
 | 
							self.remove_bosh_wait_timeout()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if self.after_init:
 | 
							if self.after_init:
 | 
				
			||||||
| 
						 | 
					@ -345,7 +353,9 @@ class NonBlockingBOSH(NonBlockingTransport):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def append_stanza(self, stanza):
 | 
						def append_stanza(self, stanza):
 | 
				
			||||||
		''' appends stanza to a buffer to send '''
 | 
							"""
 | 
				
			||||||
 | 
							Append stanza to a buffer to send
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if stanza:
 | 
							if stanza:
 | 
				
			||||||
			if isinstance(stanza, tuple):
 | 
								if isinstance(stanza, tuple):
 | 
				
			||||||
				# stanza is tuple of BOSH stanza and bool value for whether to add payload
 | 
									# stanza is tuple of BOSH stanza and bool value for whether to add payload
 | 
				
			||||||
| 
						 | 
					@ -378,7 +388,9 @@ class NonBlockingBOSH(NonBlockingTransport):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def boshify_stanzas(self, stanzas=[], body_attrs=None):
 | 
						def boshify_stanzas(self, stanzas=[], body_attrs=None):
 | 
				
			||||||
		''' wraps zero to many stanzas by body tag with xmlns and sid '''
 | 
							"""
 | 
				
			||||||
 | 
							Wraps zero to many stanzas by body tag with xmlns and sid
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		log.debug('boshify_staza - type is: %s, stanza is %s' % (type(stanzas), stanzas))
 | 
							log.debug('boshify_staza - type is: %s, stanza is %s' % (type(stanzas), stanzas))
 | 
				
			||||||
		tag = BOSHBody(attrs={'sid': self.bosh_sid})
 | 
							tag = BOSHBody(attrs={'sid': self.bosh_sid})
 | 
				
			||||||
		tag.setPayload(stanzas)
 | 
							tag.setPayload(stanzas)
 | 
				
			||||||
| 
						 | 
					@ -470,10 +482,10 @@ def get_rand_number():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AckChecker():
 | 
					class AckChecker():
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Class for generating rids and generating and checking acknowledgements in
 | 
						Class for generating rids and generating and checking acknowledgements in
 | 
				
			||||||
	BOSH messages.
 | 
						BOSH messages
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	def __init__(self):
 | 
						def __init__(self):
 | 
				
			||||||
		self.rid = get_rand_number()
 | 
							self.rid = get_rand_number()
 | 
				
			||||||
		self.ack = 1
 | 
							self.ack = 1
 | 
				
			||||||
| 
						 | 
					@ -516,9 +528,9 @@ class AckChecker():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class KeyStack():
 | 
					class KeyStack():
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Class implementing key sequences for BOSH messages
 | 
						Class implementing key sequences for BOSH messages
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	def __init__(self, count):
 | 
						def __init__(self, count):
 | 
				
			||||||
		self.count = count
 | 
							self.count = count
 | 
				
			||||||
		self.keys = []
 | 
							self.keys = []
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,10 @@
 | 
				
			||||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
 | 
					## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
 | 
					
 | 
				
			||||||
''' XML canonicalisation methods (for XEP-0116) '''
 | 
					"""
 | 
				
			||||||
 | 
					XML canonicalisation methods (for XEP-0116)
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from simplexml import ustr
 | 
					from simplexml import ustr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def c14n(node, is_buggy):
 | 
					def c14n(node, is_buggy):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,9 +16,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# $Id: client.py,v 1.52 2006/01/02 19:40:55 normanr Exp $
 | 
					# $Id: client.py,v 1.52 2006/01/02 19:40:55 normanr Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
Client class establishs connection to XMPP Server and handles authentication
 | 
					Client class establishs connection to XMPP Server and handles authentication
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import socket
 | 
					import socket
 | 
				
			||||||
import transports_nb, dispatcher_nb, auth_nb, roster_nb, protocol, bosh
 | 
					import transports_nb, dispatcher_nb, auth_nb, roster_nb, protocol, bosh
 | 
				
			||||||
from protocol import NS_TLS
 | 
					from protocol import NS_TLS
 | 
				
			||||||
| 
						 | 
					@ -28,21 +29,22 @@ log = logging.getLogger('gajim.c.x.client_nb')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NonBlockingClient:
 | 
					class NonBlockingClient:
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Client class is XMPP connection mountpoint. Objects for authentication,
 | 
						Client class is XMPP connection mountpoint. Objects for authentication,
 | 
				
			||||||
	network communication, roster, xml parsing ... are plugged to client object.
 | 
						network communication, roster, xml parsing ... are plugged to client object.
 | 
				
			||||||
	Client implements the abstract behavior - mostly negotioation and callbacks
 | 
						Client implements the abstract behavior - mostly negotioation and callbacks
 | 
				
			||||||
	handling, whereas underlying modules take care of feature-specific logic.
 | 
						handling, whereas underlying modules take care of feature-specific logic
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self, domain, idlequeue, caller=None):
 | 
						def __init__(self, domain, idlequeue, caller=None):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Caches connection data:
 | 
							Caches connection data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param domain: domain - for to: attribute (from account info)
 | 
							:param domain: domain - for to: attribute (from account info)
 | 
				
			||||||
		:param idlequeue: processing idlequeue
 | 
							:param idlequeue: processing idlequeue
 | 
				
			||||||
		:param caller: calling object - it has to implement methods
 | 
							:param caller: calling object - it has to implement methods
 | 
				
			||||||
			_event_dispatcher which is called from dispatcher instance
 | 
								_event_dispatcher which is called from dispatcher instance
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self.Namespace = protocol.NS_CLIENT
 | 
							self.Namespace = protocol.NS_CLIENT
 | 
				
			||||||
		self.defaultNamespace = self.Namespace
 | 
							self.defaultNamespace = self.Namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,10 +71,10 @@ class NonBlockingClient:
 | 
				
			||||||
		self.protocol_type = 'XMPP'
 | 
							self.protocol_type = 'XMPP'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def disconnect(self, message=''):
 | 
						def disconnect(self, message=''):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Called on disconnection - disconnect callback is picked based on state
 | 
							Called on disconnection - disconnect callback is picked based on state of
 | 
				
			||||||
		of the client.
 | 
							the client.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		# to avoid recursive calls
 | 
							# to avoid recursive calls
 | 
				
			||||||
		if self.disconnecting: return
 | 
							if self.disconnecting: return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -132,9 +134,10 @@ class NonBlockingClient:
 | 
				
			||||||
		self.disconnecting = False
 | 
							self.disconnecting = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def connect(self, on_connect, on_connect_failure, hostname=None, port=5222,
 | 
						def connect(self, on_connect, on_connect_failure, hostname=None, port=5222,
 | 
				
			||||||
	on_proxy_failure=None, proxy=None, secure_tuple=('plain', None, None)):
 | 
								on_proxy_failure=None, proxy=None, secure_tuple=('plain', None,
 | 
				
			||||||
		'''
 | 
									None)):
 | 
				
			||||||
		Open XMPP connection (open XML streams in both directions).
 | 
							"""
 | 
				
			||||||
 | 
							Open XMPP connection (open XML streams in both directions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param on_connect: called after stream is successfully opened
 | 
							:param on_connect: called after stream is successfully opened
 | 
				
			||||||
		:param on_connect_failure: called when error occures during connection
 | 
							:param on_connect_failure: called when error occures during connection
 | 
				
			||||||
| 
						 | 
					@ -150,7 +153,7 @@ class NonBlockingClient:
 | 
				
			||||||
			'tls' - TLS established after negotiation with starttls, or 'plain'.
 | 
								'tls' - TLS established after negotiation with starttls, or 'plain'.
 | 
				
			||||||
			cacerts, mycerts - see tls_nb.NonBlockingTLS constructor for more
 | 
								cacerts, mycerts - see tls_nb.NonBlockingTLS constructor for more
 | 
				
			||||||
			details
 | 
								details
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self.on_connect = on_connect
 | 
							self.on_connect = on_connect
 | 
				
			||||||
		self.on_connect_failure=on_connect_failure
 | 
							self.on_connect_failure=on_connect_failure
 | 
				
			||||||
		self.on_proxy_failure = on_proxy_failure
 | 
							self.on_proxy_failure = on_proxy_failure
 | 
				
			||||||
| 
						 | 
					@ -223,7 +226,11 @@ class NonBlockingClient:
 | 
				
			||||||
			on_success=self._try_next_ip)
 | 
								on_success=self._try_next_ip)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _resolve_hostname(self, hostname, port, on_success):
 | 
						def _resolve_hostname(self, hostname, port, on_success):
 | 
				
			||||||
		''' wrapper for getaddinfo call. FIXME: getaddinfo blocks'''
 | 
							"""
 | 
				
			||||||
 | 
							Wrapper for getaddinfo call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FIXME: getaddinfo blocks
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		try:
 | 
							try:
 | 
				
			||||||
			self.ip_addresses = socket.getaddrinfo(hostname, port,
 | 
								self.ip_addresses = socket.getaddrinfo(hostname, port,
 | 
				
			||||||
				socket.AF_UNSPEC, socket.SOCK_STREAM)
 | 
									socket.AF_UNSPEC, socket.SOCK_STREAM)
 | 
				
			||||||
| 
						 | 
					@ -234,7 +241,9 @@ class NonBlockingClient:
 | 
				
			||||||
			on_success()
 | 
								on_success()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _try_next_ip(self, err_message=None):
 | 
						def _try_next_ip(self, err_message=None):
 | 
				
			||||||
		'''Iterates over IP addresses tries to connect to it'''
 | 
							"""
 | 
				
			||||||
 | 
							Iterate over IP addresses tries to connect to it
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if err_message:
 | 
							if err_message:
 | 
				
			||||||
			log.debug('While looping over DNS A records: %s' % err_message)
 | 
								log.debug('While looping over DNS A records: %s' % err_message)
 | 
				
			||||||
		if self.ip_addresses == []:
 | 
							if self.ip_addresses == []:
 | 
				
			||||||
| 
						 | 
					@ -249,18 +258,20 @@ class NonBlockingClient:
 | 
				
			||||||
				on_connect_failure=self._try_next_ip)
 | 
									on_connect_failure=self._try_next_ip)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def incoming_stream_version(self):
 | 
						def incoming_stream_version(self):
 | 
				
			||||||
		''' gets version of xml stream'''
 | 
							"""
 | 
				
			||||||
 | 
							Get version of xml stream
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if 'version' in self.Dispatcher.Stream._document_attrs:
 | 
							if 'version' in self.Dispatcher.Stream._document_attrs:
 | 
				
			||||||
			return self.Dispatcher.Stream._document_attrs['version']
 | 
								return self.Dispatcher.Stream._document_attrs['version']
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			return None
 | 
								return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _xmpp_connect(self, socket_type=None):
 | 
						def _xmpp_connect(self, socket_type=None):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Starts XMPP connecting process - opens the XML stream. Is called after TCP
 | 
							Start XMPP connecting process - open the XML stream. Is called after TCP
 | 
				
			||||||
		connection is established or after switch to TLS when successfully
 | 
							connection is established or after switch to TLS when successfully
 | 
				
			||||||
		negotiated with <starttls>.
 | 
							negotiated with <starttls>.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		# socket_type contains info which transport connection was established
 | 
							# socket_type contains info which transport connection was established
 | 
				
			||||||
		if not socket_type:
 | 
							if not socket_type:
 | 
				
			||||||
			if self.Connection.ssl_lib:
 | 
								if self.Connection.ssl_lib:
 | 
				
			||||||
| 
						 | 
					@ -273,19 +284,19 @@ class NonBlockingClient:
 | 
				
			||||||
		self._xmpp_connect_machine()
 | 
							self._xmpp_connect_machine()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _xmpp_connect_machine(self, mode=None, data=None):
 | 
						def _xmpp_connect_machine(self, mode=None, data=None):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Finite automaton taking care of stream opening and features tag
 | 
							Finite automaton taking care of stream opening and features tag handling.
 | 
				
			||||||
		handling. Calls _on_stream_start when stream is started, and disconnect()
 | 
							Calls _on_stream_start when stream is started, and disconnect() on
 | 
				
			||||||
		on failure.
 | 
							failure.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		log.info('-------------xmpp_connect_machine() >> mode: %s, data: %s...' %
 | 
							log.info('-------------xmpp_connect_machine() >> mode: %s, data: %s...' %
 | 
				
			||||||
			(mode, str(data)[:20]))
 | 
								(mode, str(data)[:20]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		def on_next_receive(mode):
 | 
							def on_next_receive(mode):
 | 
				
			||||||
			'''
 | 
								"""
 | 
				
			||||||
			Sets desired on_receive callback on transport based on the state of
 | 
								Set desired on_receive callback on transport based on the state of
 | 
				
			||||||
			connect_machine.
 | 
								connect_machine.
 | 
				
			||||||
			'''
 | 
								"""
 | 
				
			||||||
			log.info('setting %s on next receive' % mode)
 | 
								log.info('setting %s on next receive' % mode)
 | 
				
			||||||
			if mode is None:
 | 
								if mode is None:
 | 
				
			||||||
				self.onreceive(None) # switch to Dispatcher.ProcessNonBlocking
 | 
									self.onreceive(None) # switch to Dispatcher.ProcessNonBlocking
 | 
				
			||||||
| 
						 | 
					@ -346,10 +357,10 @@ class NonBlockingClient:
 | 
				
			||||||
			self._on_stream_start()
 | 
								self._on_stream_start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _on_stream_start(self):
 | 
						def _on_stream_start(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Called after XMPP stream is opened.	TLS negotiation may follow if
 | 
							Called after XMPP stream is opened.	TLS negotiation may follow if
 | 
				
			||||||
		supported and desired.
 | 
							supported and desired.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self.stream_started = True
 | 
							self.stream_started = True
 | 
				
			||||||
		self.onreceive(None)
 | 
							self.onreceive(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -381,7 +392,9 @@ class NonBlockingClient:
 | 
				
			||||||
			assert False, 'Stream opened for unsupported connection'
 | 
								assert False, 'Stream opened for unsupported connection'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _tls_negotiation_handler(self, con=None, tag=None):
 | 
						def _tls_negotiation_handler(self, con=None, tag=None):
 | 
				
			||||||
		''' takes care of TLS negotioation with <starttls> '''
 | 
							"""
 | 
				
			||||||
 | 
							Take care of TLS negotioation with <starttls>
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		log.info('-------------tls_negotiaton_handler() >> tag: %s' % tag)
 | 
							log.info('-------------tls_negotiaton_handler() >> tag: %s' % tag)
 | 
				
			||||||
		if not con and not tag:
 | 
							if not con and not tag:
 | 
				
			||||||
			# starting state when we send the <starttls>
 | 
								# starting state when we send the <starttls>
 | 
				
			||||||
| 
						 | 
					@ -407,15 +420,17 @@ class NonBlockingClient:
 | 
				
			||||||
				on_fail = lambda: self.disconnect('error while etabilishing TLS'))
 | 
									on_fail = lambda: self.disconnect('error while etabilishing TLS'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _on_connect(self):
 | 
						def _on_connect(self):
 | 
				
			||||||
		''' preceeds call of on_connect callback '''
 | 
							"""
 | 
				
			||||||
 | 
							Preceed call of on_connect callback
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.onreceive(None)
 | 
							self.onreceive(None)
 | 
				
			||||||
		self.on_connect(self, self.connected)
 | 
							self.on_connect(self, self.connected)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def raise_event(self, event_type, data):
 | 
						def raise_event(self, event_type, data):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Raises event to connection instance. DATA_SENT and DATA_RECIVED events
 | 
							Raise event to connection instance. DATA_SENT and DATA_RECIVED events
 | 
				
			||||||
		are used in XML console to show XMPP traffic
 | 
							are used in XML console to show XMPP traffic
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		log.info('raising event from transport: :::::%s::::\n_____________\n%s\n_____________\n' % (event_type,data))
 | 
							log.info('raising event from transport: :::::%s::::\n_____________\n%s\n_____________\n' % (event_type,data))
 | 
				
			||||||
		if hasattr(self, 'Dispatcher'):
 | 
							if hasattr(self, 'Dispatcher'):
 | 
				
			||||||
			self.Dispatcher.Event('', event_type, data)
 | 
								self.Dispatcher.Event('', event_type, data)
 | 
				
			||||||
| 
						 | 
					@ -425,9 +440,9 @@ class NonBlockingClient:
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def auth(self, user, password, resource='', sasl=True, on_auth=None):
 | 
						def auth(self, user, password, resource='', sasl=True, on_auth=None):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Authenticate connnection and bind resource. If resource is not provided
 | 
							Authenticate connnection and bind resource. If resource is not provided
 | 
				
			||||||
		random one or library name used.
 | 
							random one or library name used
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param user: XMPP username
 | 
							:param user: XMPP username
 | 
				
			||||||
		:param password: XMPP password
 | 
							:param password: XMPP password
 | 
				
			||||||
| 
						 | 
					@ -435,7 +450,7 @@ class NonBlockingClient:
 | 
				
			||||||
		:param sasl: Boolean indicating if SASL shall be used. (default: True)
 | 
							:param sasl: Boolean indicating if SASL shall be used. (default: True)
 | 
				
			||||||
		:param on_auth: Callback, called after auth. On auth failure, argument
 | 
							:param on_auth: Callback, called after auth. On auth failure, argument
 | 
				
			||||||
			is None.
 | 
								is None.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self._User, self._Password = user, password
 | 
							self._User, self._Password = user, password
 | 
				
			||||||
		self._Resource, self._sasl = resource, sasl
 | 
							self._Resource, self._sasl = resource, sasl
 | 
				
			||||||
		self.on_auth = on_auth
 | 
							self.on_auth = on_auth
 | 
				
			||||||
| 
						 | 
					@ -443,7 +458,9 @@ class NonBlockingClient:
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _on_old_auth(self, res):
 | 
						def _on_old_auth(self, res):
 | 
				
			||||||
		''' Callback used by NON-SASL auth. On auth failure, res is None. '''
 | 
							"""
 | 
				
			||||||
 | 
							Callback used by NON-SASL auth. On auth failure, res is None
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if res:
 | 
							if res:
 | 
				
			||||||
			self.connected += '+old_auth'
 | 
								self.connected += '+old_auth'
 | 
				
			||||||
			self.on_auth(self, 'old_auth')
 | 
								self.on_auth(self, 'old_auth')
 | 
				
			||||||
| 
						 | 
					@ -451,7 +468,9 @@ class NonBlockingClient:
 | 
				
			||||||
			self.on_auth(self, None)
 | 
								self.on_auth(self, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _on_sasl_auth(self, res):
 | 
						def _on_sasl_auth(self, res):
 | 
				
			||||||
		''' Used internally. On auth failure, res is None. '''
 | 
							"""
 | 
				
			||||||
 | 
							Used internally. On auth failure, res is None
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.onreceive(None)
 | 
							self.onreceive(None)
 | 
				
			||||||
		if res:
 | 
							if res:
 | 
				
			||||||
			self.connected += '+sasl'
 | 
								self.connected += '+sasl'
 | 
				
			||||||
| 
						 | 
					@ -460,7 +479,9 @@ class NonBlockingClient:
 | 
				
			||||||
			self.on_auth(self, None)
 | 
								self.on_auth(self, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _on_doc_attrs(self):
 | 
						def _on_doc_attrs(self):
 | 
				
			||||||
		''' Plug authentication objects and start auth. '''
 | 
							"""
 | 
				
			||||||
 | 
							Plug authentication objects and start auth
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if self._sasl:
 | 
							if self._sasl:
 | 
				
			||||||
			auth_nb.SASL.get_instance(self._User, self._Password,
 | 
								auth_nb.SASL.get_instance(self._User, self._Password,
 | 
				
			||||||
				self._on_start_sasl).PlugIn(self)
 | 
									self._on_start_sasl).PlugIn(self)
 | 
				
			||||||
| 
						 | 
					@ -474,7 +495,9 @@ class NonBlockingClient:
 | 
				
			||||||
		return True
 | 
							return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _on_start_sasl(self, data=None):
 | 
						def _on_start_sasl(self, data=None):
 | 
				
			||||||
		''' Callback used by SASL, called on each auth step.'''
 | 
							"""
 | 
				
			||||||
 | 
							Callback used by SASL, called on each auth step
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if data:
 | 
							if data:
 | 
				
			||||||
			self.Dispatcher.ProcessNonBlocking(data)
 | 
								self.Dispatcher.ProcessNonBlocking(data)
 | 
				
			||||||
		if not 'SASL' in self.__dict__:
 | 
							if not 'SASL' in self.__dict__:
 | 
				
			||||||
| 
						 | 
					@ -504,20 +527,26 @@ class NonBlockingClient:
 | 
				
			||||||
		return True
 | 
							return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def initRoster(self, version=''):
 | 
						def initRoster(self, version=''):
 | 
				
			||||||
		''' Plug in the roster. '''
 | 
							"""
 | 
				
			||||||
 | 
							Plug in the roster
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if not self.__dict__.has_key('NonBlockingRoster'):
 | 
							if not self.__dict__.has_key('NonBlockingRoster'):
 | 
				
			||||||
			return roster_nb.NonBlockingRoster.get_instance(version=version).PlugIn(self)
 | 
								return roster_nb.NonBlockingRoster.get_instance(version=version).PlugIn(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def getRoster(self, on_ready=None, force=False):
 | 
						def getRoster(self, on_ready=None, force=False):
 | 
				
			||||||
		''' Return the Roster instance, previously plugging it in and
 | 
							"""
 | 
				
			||||||
			requesting roster from server if needed. '''
 | 
							Return the Roster instance, previously plugging it in and requesting
 | 
				
			||||||
 | 
							roster from server if needed
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if self.__dict__.has_key('NonBlockingRoster'):
 | 
							if self.__dict__.has_key('NonBlockingRoster'):
 | 
				
			||||||
			return self.NonBlockingRoster.getRoster(on_ready, force)
 | 
								return self.NonBlockingRoster.getRoster(on_ready, force)
 | 
				
			||||||
		return None
 | 
							return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def sendPresence(self, jid=None, typ=None, requestRoster=0):
 | 
						def sendPresence(self, jid=None, typ=None, requestRoster=0):
 | 
				
			||||||
		''' Send some specific presence state.
 | 
							"""
 | 
				
			||||||
			Can also request roster from server if according agrument is set.'''
 | 
							Send some specific presence state. Can also request roster from server if
 | 
				
			||||||
 | 
							according agrument is set
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if requestRoster:
 | 
							if requestRoster:
 | 
				
			||||||
			# FIXME: used somewhere?
 | 
								# FIXME: used somewhere?
 | 
				
			||||||
			roster_nb.NonBlockingRoster.get_instance().PlugIn(self)
 | 
								roster_nb.NonBlockingRoster.get_instance().PlugIn(self)
 | 
				
			||||||
| 
						 | 
					@ -528,31 +557,38 @@ class NonBlockingClient:
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterDisconnectHandler(self,handler):
 | 
						def RegisterDisconnectHandler(self,handler):
 | 
				
			||||||
		''' Register handler that will be called on disconnect.'''
 | 
							"""
 | 
				
			||||||
 | 
							Register handler that will be called on disconnect
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.disconnect_handlers.append(handler)
 | 
							self.disconnect_handlers.append(handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def UnregisterDisconnectHandler(self,handler):
 | 
						def UnregisterDisconnectHandler(self,handler):
 | 
				
			||||||
		''' Unregister handler that is called on disconnect.'''
 | 
							"""
 | 
				
			||||||
 | 
							Unregister handler that is called on disconnect
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.disconnect_handlers.remove(handler)
 | 
							self.disconnect_handlers.remove(handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def DisconnectHandler(self):
 | 
						def DisconnectHandler(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Default disconnect handler. Just raises an IOError. If you choosed to use
 | 
							Default disconnect handler. Just raises an IOError. If you choosed to use
 | 
				
			||||||
		this class in your production client, override this method or at least
 | 
							this class in your production client, override this method or at least
 | 
				
			||||||
		unregister it.
 | 
							unregister it.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		raise IOError('Disconnected from server.')
 | 
							raise IOError('Disconnected from server.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def get_connect_type(self):
 | 
						def get_connect_type(self):
 | 
				
			||||||
		''' Returns connection state. F.e.: None / 'tls' / 'plain+non_sasl'. '''
 | 
							"""
 | 
				
			||||||
 | 
							Return connection state. F.e.: None / 'tls' / 'plain+non_sasl'
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		return self.connected
 | 
							return self.connected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def get_peerhost(self):
 | 
						def get_peerhost(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Gets the ip address of the account, from which is made connection to the
 | 
							Gets the ip address of the account, from which is made connection to the
 | 
				
			||||||
		server (e.g. IP and port of gajim's socket).
 | 
							server (e.g. IP and port of gajim's socket)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		We will create listening socket on the same ip
 | 
							We will create listening socket on the same ip
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		# FIXME: tuple (ip, port) is expected (and checked for) but port num is
 | 
							# FIXME: tuple (ip, port) is expected (and checked for) but port num is
 | 
				
			||||||
		# useless
 | 
							# useless
 | 
				
			||||||
		return self.socket.peerhost
 | 
							return self.socket.peerhost
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,10 +15,10 @@
 | 
				
			||||||
##   GNU General Public License for more details.
 | 
					##   GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
Main xmpp decision making logic. Provides library with methods to assign
 | 
					Main xmpp decision making logic. Provides library with methods to assign
 | 
				
			||||||
different handlers to different XMPP stanzas and namespaces.
 | 
					different handlers to different XMPP stanzas and namespaces
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import simplexml, sys, locale
 | 
					import simplexml, sys, locale
 | 
				
			||||||
from xml.parsers.expat import ExpatError
 | 
					from xml.parsers.expat import ExpatError
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ XML_DECLARATION = '<?xml version=\'1.0\'?>'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# FIXME: ugly
 | 
					# FIXME: ugly
 | 
				
			||||||
class Dispatcher():
 | 
					class Dispatcher():
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Why is this here - I needed to redefine Dispatcher for BOSH and easiest way
 | 
						Why is this here - I needed to redefine Dispatcher for BOSH and easiest way
 | 
				
			||||||
	was to inherit original Dispatcher (now renamed to XMPPDispatcher). Trouble
 | 
						was to inherit original Dispatcher (now renamed to XMPPDispatcher). Trouble
 | 
				
			||||||
	is that reference used to access dispatcher instance is in Client attribute
 | 
						is that reference used to access dispatcher instance is in Client attribute
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,8 @@ class Dispatcher():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	If having two kinds of dispatcher will go well, I will rewrite the dispatcher
 | 
						If having two kinds of dispatcher will go well, I will rewrite the dispatcher
 | 
				
			||||||
	references in other scripts
 | 
						references in other scripts
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def PlugIn(self, client_obj, after_SASL=False, old_features=None):
 | 
						def PlugIn(self, client_obj, after_SASL=False, old_features=None):
 | 
				
			||||||
		if client_obj.protocol_type == 'XMPP':
 | 
							if client_obj.protocol_type == 'XMPP':
 | 
				
			||||||
			XMPPDispatcher().PlugIn(client_obj)
 | 
								XMPPDispatcher().PlugIn(client_obj)
 | 
				
			||||||
| 
						 | 
					@ -57,22 +58,23 @@ class Dispatcher():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@classmethod
 | 
						@classmethod
 | 
				
			||||||
	def get_instance(cls, *args, **kwargs):
 | 
						def get_instance(cls, *args, **kwargs):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Factory Method for object creation.
 | 
							Factory Method for object creation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Use this instead of directly initializing the class in order to make
 | 
							Use this instead of directly initializing the class in order to make
 | 
				
			||||||
		unit testing much easier.
 | 
							unit testing much easier.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		return cls(*args, **kwargs)
 | 
							return cls(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class XMPPDispatcher(PlugIn):
 | 
					class XMPPDispatcher(PlugIn):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Handles XMPP stream and is the first who takes control over a fresh stanza.
 | 
						Handles XMPP stream and is the first who takes control over a fresh stanza
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Is plugged into NonBlockingClient but can be replugged to restart handled
 | 
						Is plugged into NonBlockingClient but can be replugged to restart handled
 | 
				
			||||||
	stream headers (used by SASL f.e.).
 | 
						stream headers (used by SASL f.e.).
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self):
 | 
						def __init__(self):
 | 
				
			||||||
		PlugIn.__init__(self)
 | 
							PlugIn.__init__(self)
 | 
				
			||||||
		self.handlers = {}
 | 
							self.handlers = {}
 | 
				
			||||||
| 
						 | 
					@ -94,25 +96,24 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
		return repr(outgoingID)
 | 
							return repr(outgoingID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def dumpHandlers(self):
 | 
						def dumpHandlers(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
			Return set of user-registered callbacks in it's internal format.
 | 
							Return set of user-registered callbacks in it's internal format. Used
 | 
				
			||||||
			Used within the library to carry user handlers set over Dispatcher
 | 
							within the library to carry user handlers set over Dispatcher replugins
 | 
				
			||||||
			replugins.
 | 
							"""
 | 
				
			||||||
		'''
 | 
					 | 
				
			||||||
		return self.handlers
 | 
							return self.handlers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def restoreHandlers(self, handlers):
 | 
						def restoreHandlers(self, handlers):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
			Restores user-registered callbacks structure from dump previously
 | 
							Restore user-registered callbacks structure from dump previously obtained
 | 
				
			||||||
			obtained via dumpHandlers. Used within the library to carry user
 | 
							via dumpHandlers. Used within the library to carry user handlers set over
 | 
				
			||||||
			handlers set over Dispatcher replugins.
 | 
							Dispatcher replugins.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self.handlers = handlers
 | 
							self.handlers = handlers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _init(self):
 | 
						def _init(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
			Registers default namespaces/protocols/handlers. Used internally.
 | 
							Register default namespaces/protocols/handlers. Used internally
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		# FIXME: inject dependencies, do not rely that they are defined by our
 | 
							# FIXME: inject dependencies, do not rely that they are defined by our
 | 
				
			||||||
		# owner
 | 
							# owner
 | 
				
			||||||
		self.RegisterNamespace('unknown')
 | 
							self.RegisterNamespace('unknown')
 | 
				
			||||||
| 
						 | 
					@ -126,10 +127,10 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
		self.on_responses = {}
 | 
							self.on_responses = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def plugin(self, owner):
 | 
						def plugin(self, owner):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
			Plug the Dispatcher instance into Client class instance and send
 | 
							Plug the Dispatcher instance into Client class instance and send initial
 | 
				
			||||||
			initial stream header. Used internally.
 | 
							stream header. Used internally
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self._init()
 | 
							self._init()
 | 
				
			||||||
		self._owner.lastErrNode = None
 | 
							self._owner.lastErrNode = None
 | 
				
			||||||
		self._owner.lastErr = None
 | 
							self._owner.lastErr = None
 | 
				
			||||||
| 
						 | 
					@ -140,7 +141,9 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
			self.StreamInit()
 | 
								self.StreamInit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def plugout(self):
 | 
						def plugout(self):
 | 
				
			||||||
		''' Prepares instance to be destructed. '''
 | 
							"""
 | 
				
			||||||
 | 
							Prepare instance to be destructed
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.Stream.dispatch = None
 | 
							self.Stream.dispatch = None
 | 
				
			||||||
		self.Stream.features = None
 | 
							self.Stream.features = None
 | 
				
			||||||
		self.Stream.destroy()
 | 
							self.Stream.destroy()
 | 
				
			||||||
| 
						 | 
					@ -148,7 +151,9 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
		self.Stream = None
 | 
							self.Stream = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def StreamInit(self):
 | 
						def StreamInit(self):
 | 
				
			||||||
		''' Send an initial stream header. '''
 | 
							"""
 | 
				
			||||||
 | 
							Send an initial stream header
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.Stream = simplexml.NodeBuilder()
 | 
							self.Stream = simplexml.NodeBuilder()
 | 
				
			||||||
		self.Stream.dispatch = self.dispatch
 | 
							self.Stream.dispatch = self.dispatch
 | 
				
			||||||
		self.Stream._dispatch_depth = 2
 | 
							self.Stream._dispatch_depth = 2
 | 
				
			||||||
| 
						 | 
					@ -170,15 +175,15 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
				% (tag, ns))
 | 
									% (tag, ns))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def ProcessNonBlocking(self, data):
 | 
						def ProcessNonBlocking(self, data):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Check incoming stream for data waiting.
 | 
							Check incoming stream for data waiting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param data: data received from transports/IO sockets
 | 
							:param data: data received from transports/IO sockets
 | 
				
			||||||
		:return:
 | 
							:return:
 | 
				
			||||||
			1) length of processed data if some data were processed;
 | 
								1) length of processed data if some data were processed;
 | 
				
			||||||
			2) '0' string if no data were processed but link is alive;
 | 
								2) '0' string if no data were processed but link is alive;
 | 
				
			||||||
			3) 0 (zero) if underlying connection is closed.
 | 
								3) 0 (zero) if underlying connection is closed.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		# FIXME:
 | 
							# FIXME:
 | 
				
			||||||
		# When an error occurs we disconnect the transport directly. Client's
 | 
							# When an error occurs we disconnect the transport directly. Client's
 | 
				
			||||||
		# disconnect method will never be called.
 | 
							# disconnect method will never be called.
 | 
				
			||||||
| 
						 | 
					@ -211,24 +216,25 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
		return len(data)
 | 
							return len(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterNamespace(self, xmlns, order='info'):
 | 
						def RegisterNamespace(self, xmlns, order='info'):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Creates internal structures for newly registered namespace.
 | 
							Create internal structures for newly registered namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		You can register handlers for this namespace afterwards. By default
 | 
							You can register handlers for this namespace afterwards. By default
 | 
				
			||||||
		one namespace is already registered
 | 
							one namespace is already registered
 | 
				
			||||||
		(jabber:client or jabber:component:accept depending on context.
 | 
							(jabber:client or jabber:component:accept depending on context.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		log.debug('Registering namespace "%s"' % xmlns)
 | 
							log.debug('Registering namespace "%s"' % xmlns)
 | 
				
			||||||
		self.handlers[xmlns] = {}
 | 
							self.handlers[xmlns] = {}
 | 
				
			||||||
		self.RegisterProtocol('unknown', Protocol, xmlns=xmlns)
 | 
							self.RegisterProtocol('unknown', Protocol, xmlns=xmlns)
 | 
				
			||||||
		self.RegisterProtocol('default', Protocol, xmlns=xmlns)
 | 
							self.RegisterProtocol('default', Protocol, xmlns=xmlns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterProtocol(self, tag_name, Proto, xmlns=None, order='info'):
 | 
						def RegisterProtocol(self, tag_name, Proto, xmlns=None, order='info'):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Used to declare some top-level stanza name to dispatcher.
 | 
							Used to declare some top-level stanza name to dispatcher
 | 
				
			||||||
		Needed to start registering handlers for such stanzas.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Iq, message and presence protocols are registered by default.
 | 
							Needed to start registering handlers for such stanzas. Iq, message and
 | 
				
			||||||
		'''
 | 
							presence protocols are registered by default.
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if not xmlns:
 | 
							if not xmlns:
 | 
				
			||||||
			xmlns=self._owner.defaultNamespace
 | 
								xmlns=self._owner.defaultNamespace
 | 
				
			||||||
		log.debug('Registering protocol "%s" as %s(%s)' %(tag_name, Proto, xmlns))
 | 
							log.debug('Registering protocol "%s" as %s(%s)' %(tag_name, Proto, xmlns))
 | 
				
			||||||
| 
						 | 
					@ -236,16 +242,16 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterNamespaceHandler(self, xmlns, handler, typ='', ns='',
 | 
						def RegisterNamespaceHandler(self, xmlns, handler, typ='', ns='',
 | 
				
			||||||
			makefirst=0, system=0):
 | 
								makefirst=0, system=0):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Register handler for processing all stanzas for specified namespace.
 | 
							Register handler for processing all stanzas for specified namespace
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self.RegisterHandler('default', handler, typ, ns, xmlns, makefirst,
 | 
							self.RegisterHandler('default', handler, typ, ns, xmlns, makefirst,
 | 
				
			||||||
			system)
 | 
								system)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterHandler(self, name, handler, typ='', ns='', xmlns=None,
 | 
						def RegisterHandler(self, name, handler, typ='', ns='', xmlns=None,
 | 
				
			||||||
			makefirst=False, system=False):
 | 
								makefirst=False, system=False):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Register user callback as stanzas handler of declared type.
 | 
							Register user callback as stanzas handler of declared type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Callback arguments:
 | 
							Callback arguments:
 | 
				
			||||||
		dispatcher instance (for replying), incoming return of previous handlers.
 | 
							dispatcher instance (for replying), incoming return of previous handlers.
 | 
				
			||||||
| 
						 | 
					@ -263,7 +269,7 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
			and " will be called first nevertheless.
 | 
								and " will be called first nevertheless.
 | 
				
			||||||
		:param system: call handler even if NodeProcessed Exception were raised
 | 
							:param system: call handler even if NodeProcessed Exception were raised
 | 
				
			||||||
			already.
 | 
								already.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if not xmlns:
 | 
							if not xmlns:
 | 
				
			||||||
			xmlns=self._owner.defaultNamespace
 | 
								xmlns=self._owner.defaultNamespace
 | 
				
			||||||
		log.debug('Registering handler %s for "%s" type->%s ns->%s(%s)' %
 | 
							log.debug('Registering handler %s for "%s" type->%s ns->%s(%s)' %
 | 
				
			||||||
| 
						 | 
					@ -285,17 +291,19 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterHandlerOnce(self, name, handler, typ='', ns='', xmlns=None,
 | 
						def RegisterHandlerOnce(self, name, handler, typ='', ns='', xmlns=None,
 | 
				
			||||||
			makefirst=0, system=0):
 | 
								makefirst=0, system=0):
 | 
				
			||||||
		''' Unregister handler after first call (not implemented yet).	'''
 | 
							"""
 | 
				
			||||||
 | 
							Unregister handler after first call (not implemented yet)
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		# FIXME Drop or implement
 | 
							# FIXME Drop or implement
 | 
				
			||||||
		if not xmlns:
 | 
							if not xmlns:
 | 
				
			||||||
			xmlns = self._owner.defaultNamespace
 | 
								xmlns = self._owner.defaultNamespace
 | 
				
			||||||
		self.RegisterHandler(name, handler, typ, ns, xmlns, makefirst, system)
 | 
							self.RegisterHandler(name, handler, typ, ns, xmlns, makefirst, system)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def UnregisterHandler(self, name, handler, typ='', ns='', xmlns=None):
 | 
						def UnregisterHandler(self, name, handler, typ='', ns='', xmlns=None):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Unregister handler. "typ" and "ns" must be specified exactly the same as
 | 
							Unregister handler. "typ" and "ns" must be specified exactly the same as
 | 
				
			||||||
		with registering.
 | 
							with registering.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if not xmlns:
 | 
							if not xmlns:
 | 
				
			||||||
			xmlns = self._owner.defaultNamespace
 | 
								xmlns = self._owner.defaultNamespace
 | 
				
			||||||
		if not typ and not ns:
 | 
							if not typ and not ns:
 | 
				
			||||||
| 
						 | 
					@ -314,58 +322,59 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
					pass
 | 
										pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterDefaultHandler(self, handler):
 | 
						def RegisterDefaultHandler(self, handler):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Specify the handler that will be used if no NodeProcessed exception were
 | 
							Specify the handler that will be used if no NodeProcessed exception were
 | 
				
			||||||
		raised. This is returnStanzaHandler by default.
 | 
							raised. This is returnStanzaHandler by default.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self._defaultHandler = handler
 | 
							self._defaultHandler = handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterEventHandler(self, handler):
 | 
						def RegisterEventHandler(self, handler):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Register handler that will process events. F.e.
 | 
							Register handler that will process events. F.e. "FILERECEIVED" event. See
 | 
				
			||||||
		"FILERECEIVED" event. See common/connection: _event_dispatcher()
 | 
							common/connection: _event_dispatcher()
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self._eventHandler = handler
 | 
							self._eventHandler = handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def returnStanzaHandler(self, conn, stanza):
 | 
						def returnStanzaHandler(self, conn, stanza):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Return stanza back to the sender with <feature-not-implemented/> error set
 | 
							Return stanza back to the sender with <feature-not-implemented/> error
 | 
				
			||||||
		'''
 | 
							set
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if stanza.getType() in ('get','set'):
 | 
							if stanza.getType() in ('get','set'):
 | 
				
			||||||
			conn._owner.send(Error(stanza, ERR_FEATURE_NOT_IMPLEMENTED))
 | 
								conn._owner.send(Error(stanza, ERR_FEATURE_NOT_IMPLEMENTED))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def RegisterCycleHandler(self, handler):
 | 
						def RegisterCycleHandler(self, handler):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Register handler that will be called on every Dispatcher.Process() call.
 | 
							Register handler that will be called on every Dispatcher.Process() call
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if handler not in self._cycleHandlers:
 | 
							if handler not in self._cycleHandlers:
 | 
				
			||||||
			self._cycleHandlers.append(handler)
 | 
								self._cycleHandlers.append(handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def UnregisterCycleHandler(self, handler):
 | 
						def UnregisterCycleHandler(self, handler):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Unregister handler that will is called on every Dispatcher.Process() call
 | 
							Unregister handler that will is called on every Dispatcher.Process() call
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if handler in self._cycleHandlers:
 | 
							if handler in self._cycleHandlers:
 | 
				
			||||||
			self._cycleHandlers.remove(handler)
 | 
								self._cycleHandlers.remove(handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def Event(self, realm, event, data):
 | 
						def Event(self, realm, event, data):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Raise some event.
 | 
							Raise some event
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param realm: scope of event. Usually a namespace.
 | 
							:param realm: scope of event. Usually a namespace.
 | 
				
			||||||
		:param event: the event itself. F.e. "SUCCESSFUL SEND".
 | 
							:param event: the event itself. F.e. "SUCCESSFUL SEND".
 | 
				
			||||||
		:param data: data that comes along with event. Depends on event.
 | 
							:param data: data that comes along with event. Depends on event.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if self._eventHandler:
 | 
							if self._eventHandler:
 | 
				
			||||||
			self._eventHandler(realm, event, data)
 | 
								self._eventHandler(realm, event, data)
 | 
				
			||||||
		else:
 | 
							else:
 | 
				
			||||||
			log.warning('Received unhandled event: %s' % event)
 | 
								log.warning('Received unhandled event: %s' % event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def dispatch(self, stanza, session=None, direct=0):
 | 
						def dispatch(self, stanza, session=None, direct=0):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Main procedure that performs XMPP stanza recognition and calling
 | 
							Main procedure that performs XMPP stanza recognition and calling
 | 
				
			||||||
		apppropriate handlers for it. Called by simplexml.
 | 
							apppropriate handlers for it. Called by simplexml
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		# FIXME: Where do we set session and direct. Why? What are those intended
 | 
							# FIXME: Where do we set session and direct. Why? What are those intended
 | 
				
			||||||
		# to do?
 | 
							# to do?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -450,9 +459,9 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
			self._defaultHandler(session, stanza)
 | 
								self._defaultHandler(session, stanza)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _WaitForData(self, data):
 | 
						def _WaitForData(self, data):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Internal wrapper around ProcessNonBlocking. Will check for
 | 
							Internal wrapper around ProcessNonBlocking. Will check for
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if data is None:
 | 
							if data is None:
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		res = self.ProcessNonBlocking(data)
 | 
							res = self.ProcessNonBlocking(data)
 | 
				
			||||||
| 
						 | 
					@ -481,12 +490,12 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
				del self._expected[_id]
 | 
									del self._expected[_id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def SendAndWaitForResponse(self, stanza, timeout=None, func=None, args=None):
 | 
						def SendAndWaitForResponse(self, stanza, timeout=None, func=None, args=None):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Send stanza and wait for recipient's response to it. Will call transports
 | 
							Send stanza and wait for recipient's response to it. Will call transports
 | 
				
			||||||
		on_timeout callback if response is not retrieved in time.
 | 
							on_timeout callback if response is not retrieved in time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Be aware: Only timeout of latest call of SendAndWait is active.
 | 
							Be aware: Only timeout of latest call of SendAndWait is active.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if timeout is None:
 | 
							if timeout is None:
 | 
				
			||||||
			timeout = DEFAULT_TIMEOUT_SECONDS
 | 
								timeout = DEFAULT_TIMEOUT_SECONDS
 | 
				
			||||||
		_waitid = self.send(stanza)
 | 
							_waitid = self.send(stanza)
 | 
				
			||||||
| 
						 | 
					@ -499,15 +508,17 @@ class XMPPDispatcher(PlugIn):
 | 
				
			||||||
		return _waitid
 | 
							return _waitid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def SendAndCallForResponse(self, stanza, func=None, args=None):
 | 
						def SendAndCallForResponse(self, stanza, func=None, args=None):
 | 
				
			||||||
		''' Put stanza on the wire and call back when recipient replies.
 | 
							"""
 | 
				
			||||||
			Additional callback arguments can be specified in args. '''
 | 
							Put stanza on the wire and call back when recipient replies. Additional
 | 
				
			||||||
 | 
							callback arguments can be specified in args
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.SendAndWaitForResponse(stanza, 0, func, args)
 | 
							self.SendAndWaitForResponse(stanza, 0, func, args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def send(self, stanza, now=False):
 | 
						def send(self, stanza, now=False):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Wraps transports send method when plugged into NonBlockingClient.
 | 
							Wrap transports send method when plugged into NonBlockingClient. Makes
 | 
				
			||||||
		Makes sure stanzas get ID and from tag.
 | 
							sure stanzas get ID and from tag.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		ID = None
 | 
							ID = None
 | 
				
			||||||
		if type(stanza) not in [type(''), type(u'')]:
 | 
							if type(stanza) not in [type(''), type(u'')]:
 | 
				
			||||||
			if isinstance(stanza, Protocol):
 | 
								if isinstance(stanza, Protocol):
 | 
				
			||||||
| 
						 | 
					@ -529,7 +540,9 @@ class BOSHDispatcher(XMPPDispatcher):
 | 
				
			||||||
		XMPPDispatcher.PlugIn(self, owner)
 | 
							XMPPDispatcher.PlugIn(self, owner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def StreamInit(self):
 | 
						def StreamInit(self):
 | 
				
			||||||
		''' Send an initial stream header. '''
 | 
							"""
 | 
				
			||||||
 | 
							Send an initial stream header
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.Stream = simplexml.NodeBuilder()
 | 
							self.Stream = simplexml.NodeBuilder()
 | 
				
			||||||
		self.Stream.dispatch = self.dispatch
 | 
							self.Stream.dispatch = self.dispatch
 | 
				
			||||||
		self.Stream._dispatch_depth = 2
 | 
							self.Stream._dispatch_depth = 2
 | 
				
			||||||
| 
						 | 
					@ -549,7 +562,9 @@ class BOSHDispatcher(XMPPDispatcher):
 | 
				
			||||||
		self._owner.Connection.send_init(after_SASL=self.after_SASL)
 | 
							self._owner.Connection.send_init(after_SASL=self.after_SASL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def StreamTerminate(self):
 | 
						def StreamTerminate(self):
 | 
				
			||||||
		''' Send a stream terminator. '''
 | 
							"""
 | 
				
			||||||
 | 
							Send a stream terminator
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self._owner.Connection.send_terminator()
 | 
							self._owner.Connection.send_terminator()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def ProcessNonBlocking(self, data=None):
 | 
						def ProcessNonBlocking(self, data=None):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,10 +15,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# $Id: features.py,v 1.22 2005/09/30 20:13:04 mikealbon Exp $
 | 
					# $Id: features.py,v 1.22 2005/09/30 20:13:04 mikealbon Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
Different stuff that wasn't worth separating it into modules
 | 
					Different stuff that wasn't worth separating it into modules
 | 
				
			||||||
(Registration, Privacy Lists, ...)
 | 
					(Registration, Privacy Lists, ...)
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from protocol import NS_REGISTER, NS_PRIVACY, NS_DATA, Iq, isResultNode, Node
 | 
					from protocol import NS_REGISTER, NS_PRIVACY, NS_DATA, Iq, isResultNode, Node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,13 +38,13 @@ def _on_default_response(disp, iq, cb):
 | 
				
			||||||
REGISTER_DATA_RECEIVED = 'REGISTER DATA RECEIVED'
 | 
					REGISTER_DATA_RECEIVED = 'REGISTER DATA RECEIVED'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getRegInfo(disp, host, info={}, sync=True):
 | 
					def getRegInfo(disp, host, info={}, sync=True):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Gets registration form from remote host. Info dict can be prefilled
 | 
						Get registration form from remote host. Info dict can be prefilled
 | 
				
			||||||
	:param disp: plugged dispatcher instance
 | 
						:param disp: plugged dispatcher instance
 | 
				
			||||||
	:param info: dict, like {'username':'joey'}.
 | 
						:param info: dict, like {'username':'joey'}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	See JEP-0077 for details.
 | 
						See JEP-0077 for details.
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	iq=Iq('get',NS_REGISTER,to=host)
 | 
						iq=Iq('get',NS_REGISTER,to=host)
 | 
				
			||||||
	for i in info.keys():
 | 
						for i in info.keys():
 | 
				
			||||||
		iq.setTagData(i,info[i])
 | 
							iq.setTagData(i,info[i])
 | 
				
			||||||
| 
						 | 
					@ -77,12 +77,12 @@ def _ReceivedRegInfo(con, resp, agent):
 | 
				
			||||||
	con.Event(NS_REGISTER, REGISTER_DATA_RECEIVED, (agent,df,False,''))
 | 
						con.Event(NS_REGISTER, REGISTER_DATA_RECEIVED, (agent,df,False,''))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def register(disp, host, info, cb):
 | 
					def register(disp, host, info, cb):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Perform registration on remote server with provided info.
 | 
						Perform registration on remote server with provided info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	If registration fails you can get additional info from the dispatcher's
 | 
						If registration fails you can get additional info from the dispatcher's
 | 
				
			||||||
	owner	attributes lastErrNode, lastErr and lastErrCode.
 | 
						owner	attributes lastErrNode, lastErr and lastErrCode.
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	iq=Iq('set', NS_REGISTER, to=host)
 | 
						iq=Iq('set', NS_REGISTER, to=host)
 | 
				
			||||||
	if not isinstance(info, dict):
 | 
						if not isinstance(info, dict):
 | 
				
			||||||
		info=info.asDict()
 | 
							info=info.asDict()
 | 
				
			||||||
| 
						 | 
					@ -91,17 +91,17 @@ def register(disp, host, info, cb):
 | 
				
			||||||
	disp.SendAndCallForResponse(iq, cb)
 | 
						disp.SendAndCallForResponse(iq, cb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def unregister(disp, host, cb):
 | 
					def unregister(disp, host, cb):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Unregisters with host (permanently removes account). Returns true on success
 | 
						Unregisters with host (permanently removes account). Returns true on success
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	iq = Iq('set', NS_REGISTER, to=host, payload=[Node('remove')])
 | 
						iq = Iq('set', NS_REGISTER, to=host, payload=[Node('remove')])
 | 
				
			||||||
	_on_default_response(disp, iq, cb)
 | 
						_on_default_response(disp, iq, cb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def changePasswordTo(disp, newpassword, host=None, cb = None):
 | 
					def changePasswordTo(disp, newpassword, host=None, cb = None):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Changes password on specified or current (if not specified) server.
 | 
						Changes password on specified or current (if not specified) server. Returns
 | 
				
			||||||
	Returns true on success.
 | 
						true on success.
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	if not host:
 | 
						if not host:
 | 
				
			||||||
		host = disp._owner.Server
 | 
							host = disp._owner.Server
 | 
				
			||||||
	iq = Iq('set',NS_REGISTER,to=host, payload=[Node('username',
 | 
						iq = Iq('set',NS_REGISTER,to=host, payload=[Node('username',
 | 
				
			||||||
| 
						 | 
					@ -123,10 +123,10 @@ PRIVACY_LIST_RECEIVED = 'PRIVACY LIST RECEIVED'
 | 
				
			||||||
PRIVACY_LISTS_ACTIVE_DEFAULT = 'PRIVACY LISTS ACTIVE DEFAULT'
 | 
					PRIVACY_LISTS_ACTIVE_DEFAULT = 'PRIVACY LISTS ACTIVE DEFAULT'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getPrivacyLists(disp):
 | 
					def getPrivacyLists(disp):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Requests privacy lists from connected server.
 | 
						Request privacy lists from connected server. Returns dictionary of existing
 | 
				
			||||||
	Returns dictionary of existing lists on success.
 | 
						lists on success.
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	iq = Iq('get', NS_PRIVACY)
 | 
						iq = Iq('get', NS_PRIVACY)
 | 
				
			||||||
	def _on_response(resp):
 | 
						def _on_response(resp):
 | 
				
			||||||
		dict_ = {'lists': []}
 | 
							dict_ = {'lists': []}
 | 
				
			||||||
| 
						 | 
					@ -157,10 +157,10 @@ def getActiveAndDefaultPrivacyLists(disp):
 | 
				
			||||||
	disp.SendAndCallForResponse(iq, _on_response)
 | 
						disp.SendAndCallForResponse(iq, _on_response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getPrivacyList(disp, listname):
 | 
					def getPrivacyList(disp, listname):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Requests specific privacy list listname. Returns list of XML nodes (rules)
 | 
						Request specific privacy list listname. Returns list of XML nodes (rules)
 | 
				
			||||||
	taken from the server responce.
 | 
						taken from the server responce.
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	def _on_response(resp):
 | 
						def _on_response(resp):
 | 
				
			||||||
		if not isResultNode(resp):
 | 
							if not isResultNode(resp):
 | 
				
			||||||
			disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (False))
 | 
								disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (False))
 | 
				
			||||||
| 
						 | 
					@ -170,10 +170,10 @@ def getPrivacyList(disp, listname):
 | 
				
			||||||
	disp.SendAndCallForResponse(iq, _on_response)
 | 
						disp.SendAndCallForResponse(iq, _on_response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setActivePrivacyList(disp, listname=None, typ='active', cb=None):
 | 
					def setActivePrivacyList(disp, listname=None, typ='active', cb=None):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Switches privacy list 'listname' to specified type.
 | 
						Switch privacy list 'listname' to specified type. By default the type is
 | 
				
			||||||
	By default the type is 'active'. Returns true on success.
 | 
						'active'. Returns true on success.
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	if listname:
 | 
						if listname:
 | 
				
			||||||
		attrs={'name':listname}
 | 
							attrs={'name':listname}
 | 
				
			||||||
	else:
 | 
						else:
 | 
				
			||||||
| 
						 | 
					@ -182,15 +182,20 @@ def setActivePrivacyList(disp, listname=None, typ='active', cb=None):
 | 
				
			||||||
	_on_default_response(disp, iq, cb)
 | 
						_on_default_response(disp, iq, cb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setDefaultPrivacyList(disp, listname=None):
 | 
					def setDefaultPrivacyList(disp, listname=None):
 | 
				
			||||||
	''' Sets the default privacy list as 'listname'. Returns true on success. '''
 | 
						"""
 | 
				
			||||||
 | 
						Set the default privacy list as 'listname'. Returns true on success
 | 
				
			||||||
 | 
						"""
 | 
				
			||||||
	return setActivePrivacyList(disp, listname,'default')
 | 
						return setActivePrivacyList(disp, listname,'default')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setPrivacyList(disp, listname, tags):
 | 
					def setPrivacyList(disp, listname, tags):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Set the ruleset.
 | 
						Set the ruleset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	'list' should be the simpleXML node formatted according to RFC 3921 (XMPP-IM) 	I.e. Node('list',{'name':listname},payload=[...]).	Returns true on success.
 | 
						'list' should be the simpleXML node formatted according to RFC 3921
 | 
				
			||||||
	'''
 | 
						(XMPP-IM) I.e. Node('list',{'name':listname},payload=[...]).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Returns true on success.
 | 
				
			||||||
 | 
						"""
 | 
				
			||||||
	iq = Iq('set', NS_PRIVACY, xmlns = '')
 | 
						iq = Iq('set', NS_PRIVACY, xmlns = '')
 | 
				
			||||||
	list_query = iq.getTag('query').setTag('list', {'name': listname})
 | 
						list_query = iq.getTag('query').setTag('list', {'name': listname})
 | 
				
			||||||
	for item in tags:
 | 
						for item in tags:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,10 +12,12 @@
 | 
				
			||||||
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
##   GNU General Public License for more details.
 | 
					##   GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'''
 | 
					
 | 
				
			||||||
Idlequeues are Gajim's network heartbeat. Transports can be plugged as
 | 
					"""
 | 
				
			||||||
idle objects and be informed about possible IO.
 | 
					Idlequeues are Gajim's network heartbeat. Transports can be plugged as idle
 | 
				
			||||||
'''
 | 
					objects and be informed about possible IO
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import select
 | 
					import select
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
| 
						 | 
					@ -45,7 +47,9 @@ IS_CLOSED			= 16 # channel closed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_idlequeue():
 | 
					def get_idlequeue():
 | 
				
			||||||
	''' Get an appropriate idlequeue '''
 | 
						"""
 | 
				
			||||||
 | 
						Get an appropriate idlequeue
 | 
				
			||||||
 | 
						"""
 | 
				
			||||||
	if os.name == 'nt':
 | 
						if os.name == 'nt':
 | 
				
			||||||
		# gobject.io_add_watch does not work on windows
 | 
							# gobject.io_add_watch does not work on windows
 | 
				
			||||||
		return SelectIdleQueue()
 | 
							return SelectIdleQueue()
 | 
				
			||||||
| 
						 | 
					@ -59,34 +63,44 @@ def get_idlequeue():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IdleObject:
 | 
					class IdleObject:
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Idle listener interface. Listed methods are called by IdleQueue.
 | 
						Idle listener interface. Listed methods are called by IdleQueue.
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self):
 | 
						def __init__(self):
 | 
				
			||||||
		self.fd = -1 #: filedescriptor, must be unique for each IdleObject
 | 
							self.fd = -1 #: filedescriptor, must be unique for each IdleObject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def pollend(self):
 | 
						def pollend(self):
 | 
				
			||||||
		''' called on stream failure '''
 | 
							"""
 | 
				
			||||||
 | 
							Called on stream failure
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		pass
 | 
							pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def pollin(self):
 | 
						def pollin(self):
 | 
				
			||||||
		''' called on new read event '''
 | 
							"""
 | 
				
			||||||
 | 
							Called on new read event
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		pass
 | 
							pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def pollout(self):
 | 
						def pollout(self):
 | 
				
			||||||
		''' called on new write event (connect in sockets is a pollout) '''
 | 
							"""
 | 
				
			||||||
 | 
							Called on new write event (connect in sockets is a pollout)
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		pass
 | 
							pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def read_timeout(self):
 | 
						def read_timeout(self):
 | 
				
			||||||
		''' called when timeout happened '''
 | 
							"""
 | 
				
			||||||
 | 
							Called when timeout happened
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		pass
 | 
							pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IdleCommand(IdleObject):
 | 
					class IdleCommand(IdleObject):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Can be subclassed to execute commands asynchronously by the idlequeue.
 | 
						Can be subclassed to execute commands asynchronously by the idlequeue.
 | 
				
			||||||
	Result will be optained via file descriptor of created pipe
 | 
						Result will be optained via file descriptor of created pipe
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self, on_result):
 | 
						def __init__(self, on_result):
 | 
				
			||||||
		IdleObject.__init__(self)
 | 
							IdleObject.__init__(self)
 | 
				
			||||||
		# how long (sec.) to wait for result ( 0 - forever )
 | 
							# how long (sec.) to wait for result ( 0 - forever )
 | 
				
			||||||
| 
						 | 
					@ -111,7 +125,9 @@ class IdleCommand(IdleObject):
 | 
				
			||||||
		return ['echo', 'da']
 | 
							return ['echo', 'da']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _compose_command_line(self):
 | 
						def _compose_command_line(self):
 | 
				
			||||||
		''' return one line representation of command and its arguments '''
 | 
							"""
 | 
				
			||||||
 | 
							Return one line representation of command and its arguments
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		return  reduce(lambda left, right: left + ' ' + right,
 | 
							return  reduce(lambda left, right: left + ' ' + right,
 | 
				
			||||||
			self._compose_command_args())
 | 
								self._compose_command_args())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,7 +203,7 @@ class IdleCommand(IdleObject):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IdleQueue:
 | 
					class IdleQueue:
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	IdleQueue provide three distinct time based features. Uses select.poll()
 | 
						IdleQueue provide three distinct time based features. Uses select.poll()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		1. Alarm timeout: Execute a callback after foo seconds
 | 
							1. Alarm timeout: Execute a callback after foo seconds
 | 
				
			||||||
| 
						 | 
					@ -195,7 +211,8 @@ class IdleQueue:
 | 
				
			||||||
		has been set, but not removed in time.
 | 
							has been set, but not removed in time.
 | 
				
			||||||
		3. Check file descriptor of plugged objects for read, write and error
 | 
							3. Check file descriptor of plugged objects for read, write and error
 | 
				
			||||||
		events
 | 
							events
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# (timeout, boolean)
 | 
						# (timeout, boolean)
 | 
				
			||||||
	# Boolean is True if timeout is specified in seconds, False means miliseconds
 | 
						# Boolean is True if timeout is specified in seconds, False means miliseconds
 | 
				
			||||||
	PROCESS_TIMEOUT = (200, False)
 | 
						PROCESS_TIMEOUT = (200, False)
 | 
				
			||||||
| 
						 | 
					@ -215,13 +232,15 @@ class IdleQueue:
 | 
				
			||||||
		self._init_idle()
 | 
							self._init_idle()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _init_idle(self):
 | 
						def _init_idle(self):
 | 
				
			||||||
		''' Hook method for subclassed. Will be called by __init__. '''
 | 
							"""
 | 
				
			||||||
 | 
							Hook method for subclassed. Will be called by __init__
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.selector = select.poll()
 | 
							self.selector = select.poll()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def set_alarm(self, alarm_cb, seconds):
 | 
						def set_alarm(self, alarm_cb, seconds):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Sets up a new alarm. alarm_cb will be called after specified seconds.
 | 
							Set up a new alarm. alarm_cb will be called after specified seconds.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		alarm_time = self.current_time() + seconds
 | 
							alarm_time = self.current_time() + seconds
 | 
				
			||||||
		# almost impossible, but in case we have another alarm_cb at this time
 | 
							# almost impossible, but in case we have another alarm_cb at this time
 | 
				
			||||||
		if alarm_time in self.alarms:
 | 
							if alarm_time in self.alarms:
 | 
				
			||||||
| 
						 | 
					@ -231,10 +250,10 @@ class IdleQueue:
 | 
				
			||||||
		return alarm_time
 | 
							return alarm_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def remove_alarm(self, alarm_cb, alarm_time):
 | 
						def remove_alarm(self, alarm_cb, alarm_time):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Removes alarm callback alarm_cb scheduled on alarm_time.
 | 
							Remove alarm callback alarm_cb scheduled on alarm_time. Returns True if
 | 
				
			||||||
		Returns True if it was removed sucessfully, otherwise False
 | 
							it was removed sucessfully, otherwise False
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if not alarm_time in self.alarms:
 | 
							if not alarm_time in self.alarms:
 | 
				
			||||||
			return False
 | 
								return False
 | 
				
			||||||
		i = -1
 | 
							i = -1
 | 
				
			||||||
| 
						 | 
					@ -251,7 +270,9 @@ class IdleQueue:
 | 
				
			||||||
			return False
 | 
								return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def remove_timeout(self, fd, timeout=None):
 | 
						def remove_timeout(self, fd, timeout=None):
 | 
				
			||||||
		''' Removes the read timeout '''
 | 
							"""
 | 
				
			||||||
 | 
							Remove the read timeout
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		log.info('read timeout removed for fd %s' % fd)
 | 
							log.info('read timeout removed for fd %s' % fd)
 | 
				
			||||||
		if fd in self.read_timeouts:
 | 
							if fd in self.read_timeouts:
 | 
				
			||||||
			if timeout:
 | 
								if timeout:
 | 
				
			||||||
| 
						 | 
					@ -263,12 +284,12 @@ class IdleQueue:
 | 
				
			||||||
				del(self.read_timeouts[fd])
 | 
									del(self.read_timeouts[fd])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def set_read_timeout(self, fd, seconds, func=None):
 | 
						def set_read_timeout(self, fd, seconds, func=None):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Sets a new timeout. If it is not removed after specified seconds,
 | 
							Seta a new timeout. If it is not removed after specified seconds,
 | 
				
			||||||
		func or obj.read_timeout() will be called.
 | 
							func or obj.read_timeout() will be called
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		A filedescriptor fd can have several timeouts.
 | 
							A filedescriptor fd can have several timeouts.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		log_txt = 'read timeout set for fd %s on %s seconds' % (fd, seconds)
 | 
							log_txt = 'read timeout set for fd %s on %s seconds' % (fd, seconds)
 | 
				
			||||||
		if func:
 | 
							if func:
 | 
				
			||||||
			log_txt += ' with function ' + str(func)
 | 
								log_txt += ' with function ' + str(func)
 | 
				
			||||||
| 
						 | 
					@ -280,10 +301,10 @@ class IdleQueue:
 | 
				
			||||||
			self.read_timeouts[fd] = {timeout: func}
 | 
								self.read_timeouts[fd] = {timeout: func}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _check_time_events(self):
 | 
						def _check_time_events(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Execute and remove alarm callbacks and execute func() or read_timeout()
 | 
							Execute and remove alarm callbacks and execute func() or read_timeout()
 | 
				
			||||||
		for plugged objects if specified time has ellapsed.
 | 
							for plugged objects if specified time has ellapsed
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		log.info('check time evs')
 | 
							log.info('check time evs')
 | 
				
			||||||
		current_time = self.current_time()
 | 
							current_time = self.current_time()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -313,13 +334,13 @@ class IdleQueue:
 | 
				
			||||||
					del(self.alarms[alarm_time])
 | 
										del(self.alarms[alarm_time])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def plug_idle(self, obj, writable=True, readable=True):
 | 
						def plug_idle(self, obj, writable=True, readable=True):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Plug an IdleObject into idlequeue. Filedescriptor fd must be set.
 | 
							Plug an IdleObject into idlequeue. Filedescriptor fd must be set
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		:param obj: the IdleObject
 | 
							:param obj: the IdleObject
 | 
				
			||||||
		:param writable: True if obj has data to sent
 | 
							:param writable: True if obj has data to sent
 | 
				
			||||||
		:param readable: True if obj expects data to be reiceived
 | 
							:param readable: True if obj expects data to be reiceived
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if obj.fd == -1:
 | 
							if obj.fd == -1:
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		if obj.fd in self.queue:
 | 
							if obj.fd in self.queue:
 | 
				
			||||||
| 
						 | 
					@ -339,11 +360,15 @@ class IdleQueue:
 | 
				
			||||||
		self._add_idle(obj.fd, flags)
 | 
							self._add_idle(obj.fd, flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _add_idle(self, fd, flags):
 | 
						def _add_idle(self, fd, flags):
 | 
				
			||||||
		''' Hook method for subclasses, called by plug_idle '''
 | 
							"""
 | 
				
			||||||
 | 
							Hook method for subclasses, called by plug_idle
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.selector.register(fd, flags)
 | 
							self.selector.register(fd, flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def unplug_idle(self, fd):
 | 
						def unplug_idle(self, fd):
 | 
				
			||||||
		''' Removed plugged IdleObject, specified by filedescriptor fd.  '''
 | 
							"""
 | 
				
			||||||
 | 
							Remove plugged IdleObject, specified by filedescriptor fd
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if fd in self.queue:
 | 
							if fd in self.queue:
 | 
				
			||||||
			del(self.queue[fd])
 | 
								del(self.queue[fd])
 | 
				
			||||||
			self._remove_idle(fd)
 | 
								self._remove_idle(fd)
 | 
				
			||||||
| 
						 | 
					@ -353,7 +378,9 @@ class IdleQueue:
 | 
				
			||||||
		return time()
 | 
							return time()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _remove_idle(self, fd):
 | 
						def _remove_idle(self, fd):
 | 
				
			||||||
		''' Hook method for subclassed, called by unplug_idle '''
 | 
							"""
 | 
				
			||||||
 | 
							Hook method for subclassed, called by unplug_idle
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		self.selector.unregister(fd)
 | 
							self.selector.unregister(fd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _process_events(self, fd, flags):
 | 
						def _process_events(self, fd, flags):
 | 
				
			||||||
| 
						 | 
					@ -379,13 +406,13 @@ class IdleQueue:
 | 
				
			||||||
		return False
 | 
							return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def process(self):
 | 
						def process(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Process idlequeue. Check for any pending timeout or alarm events.
 | 
							Process idlequeue. Check for any pending timeout or alarm events.  Call
 | 
				
			||||||
		Call IdleObjects on possible and requested read, write and error events
 | 
							IdleObjects on possible and requested read, write and error events on
 | 
				
			||||||
		on their file descriptors.
 | 
							their file descriptors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Call this in regular intervals.
 | 
							Call this in regular intervals.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		if not self.queue:
 | 
							if not self.queue:
 | 
				
			||||||
			# check for timeouts/alert also when there are no active fds
 | 
								# check for timeouts/alert also when there are no active fds
 | 
				
			||||||
			self._check_time_events()
 | 
								self._check_time_events()
 | 
				
			||||||
| 
						 | 
					@ -403,24 +430,26 @@ class IdleQueue:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SelectIdleQueue(IdleQueue):
 | 
					class SelectIdleQueue(IdleQueue):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Extends IdleQueue to use select.select() for polling
 | 
						Extends IdleQueue to use select.select() for polling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	This class exisists for the sake of gtk2.8 on windows, which
 | 
						This class exisists for the sake of gtk2.8 on windows, which doesn't seem to
 | 
				
			||||||
	doesn't seem to support io_add_watch properly (yet)
 | 
						support io_add_watch properly (yet)
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _init_idle(self):
 | 
						def _init_idle(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Creates a dict, which maps file/pipe/sock descriptor to glib event id
 | 
							Create a dict, which maps file/pipe/sock descriptor to glib event id
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self.read_fds = {}
 | 
							self.read_fds = {}
 | 
				
			||||||
		self.write_fds = {}
 | 
							self.write_fds = {}
 | 
				
			||||||
		self.error_fds = {}
 | 
							self.error_fds = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _add_idle(self, fd, flags):
 | 
						def _add_idle(self, fd, flags):
 | 
				
			||||||
		''' this method is called when we plug a new idle object.
 | 
							"""
 | 
				
			||||||
		Remove descriptor to read/write/error lists, according flags
 | 
							This method is called when we plug a new idle object. Remove descriptor
 | 
				
			||||||
		'''
 | 
							to read/write/error lists, according flags
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if flags & 3:
 | 
							if flags & 3:
 | 
				
			||||||
			self.read_fds[fd] = fd
 | 
								self.read_fds[fd] = fd
 | 
				
			||||||
		if flags & 4:
 | 
							if flags & 4:
 | 
				
			||||||
| 
						 | 
					@ -428,9 +457,10 @@ class SelectIdleQueue(IdleQueue):
 | 
				
			||||||
		self.error_fds[fd] = fd
 | 
							self.error_fds[fd] = fd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _remove_idle(self, fd):
 | 
						def _remove_idle(self, fd):
 | 
				
			||||||
		''' this method is called when we unplug a new idle object.
 | 
							"""
 | 
				
			||||||
		Remove descriptor from read/write/error lists
 | 
							This method is called when we unplug a new idle object. Remove descriptor
 | 
				
			||||||
		'''
 | 
							from read/write/error lists
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if fd in self.read_fds:
 | 
							if fd in self.read_fds:
 | 
				
			||||||
			del(self.read_fds[fd])
 | 
								del(self.read_fds[fd])
 | 
				
			||||||
		if fd in self.write_fds:
 | 
							if fd in self.write_fds:
 | 
				
			||||||
| 
						 | 
					@ -466,27 +496,29 @@ class SelectIdleQueue(IdleQueue):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GlibIdleQueue(IdleQueue):
 | 
					class GlibIdleQueue(IdleQueue):
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Extends IdleQueue to use glib io_add_wath, instead of select/poll
 | 
						Extends IdleQueue to use glib io_add_wath, instead of select/poll In another
 | 
				
			||||||
	In another 'non gui' implementation of Gajim IdleQueue can be used safetly.
 | 
						'non gui' implementation of Gajim IdleQueue can be used safetly
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# (timeout, boolean)
 | 
						# (timeout, boolean)
 | 
				
			||||||
	# Boolean is True if timeout is specified in seconds, False means miliseconds
 | 
						# Boolean is True if timeout is specified in seconds, False means miliseconds
 | 
				
			||||||
	PROCESS_TIMEOUT = (2, True)
 | 
						PROCESS_TIMEOUT = (2, True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _init_idle(self):
 | 
						def _init_idle(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Creates a dict, which maps file/pipe/sock descriptor to glib event id
 | 
							Creates a dict, which maps file/pipe/sock descriptor to glib event id
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self.events = {}
 | 
							self.events = {}
 | 
				
			||||||
		# time() is already called in glib, we just get the last value
 | 
							# time() is already called in glib, we just get the last value
 | 
				
			||||||
		# overrides IdleQueue.current_time()
 | 
							# overrides IdleQueue.current_time()
 | 
				
			||||||
		self.current_time = gobject.get_current_time
 | 
							self.current_time = gobject.get_current_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _add_idle(self, fd, flags):
 | 
						def _add_idle(self, fd, flags):
 | 
				
			||||||
		''' this method is called when we plug a new idle object.
 | 
							"""
 | 
				
			||||||
		Start listening for events from fd
 | 
							This method is called when we plug a new idle object. Start listening for
 | 
				
			||||||
		'''
 | 
							events from fd
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		res = gobject.io_add_watch(fd, flags, self._process_events,
 | 
							res = gobject.io_add_watch(fd, flags, self._process_events,
 | 
				
			||||||
			priority=gobject.PRIORITY_LOW)
 | 
								priority=gobject.PRIORITY_LOW)
 | 
				
			||||||
		# store the id of the watch, so that we can remove it on unplug
 | 
							# store the id of the watch, so that we can remove it on unplug
 | 
				
			||||||
| 
						 | 
					@ -501,9 +533,10 @@ class GlibIdleQueue(IdleQueue):
 | 
				
			||||||
			raise
 | 
								raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def _remove_idle(self, fd):
 | 
						def _remove_idle(self, fd):
 | 
				
			||||||
		''' this method is called when we unplug a new idle object.
 | 
							"""
 | 
				
			||||||
		Stop listening for events from fd
 | 
							This method is called when we unplug a new idle object. Stop listening
 | 
				
			||||||
		'''
 | 
							for events from fd
 | 
				
			||||||
 | 
							"""
 | 
				
			||||||
		if not fd in self.events:
 | 
							if not fd in self.events:
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		gobject.source_remove(self.events[fd])
 | 
							gobject.source_remove(self.events[fd])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,33 +14,34 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# $Id: client.py,v 1.52 2006/01/02 19:40:55 normanr Exp $
 | 
					# $Id: client.py,v 1.52 2006/01/02 19:40:55 normanr Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
Provides PlugIn class functionality to develop extentions for xmpppy.
 | 
					Provides PlugIn class functionality to develop extentions for xmpppy
 | 
				
			||||||
'''
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
log = logging.getLogger('gajim.c.x.plugin')
 | 
					log = logging.getLogger('gajim.c.x.plugin')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PlugIn:
 | 
					class PlugIn:
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
	Abstract xmpppy plugin infrastructure code, providing plugging in/out and
 | 
						Abstract xmpppy plugin infrastructure code, providing plugging in/out and
 | 
				
			||||||
	debugging functionality.
 | 
						debugging functionality
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Inherit to develop pluggable objects. No code change on the owner class
 | 
						Inherit to develop pluggable objects. No code change on the owner class
 | 
				
			||||||
	required (the object where we plug into)
 | 
						required (the object where we plug into)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	For every instance of PlugIn class the 'owner' is the class in what the plug
 | 
						For every instance of PlugIn class the 'owner' is the class in what the plug
 | 
				
			||||||
	was plugged.
 | 
						was plugged.
 | 
				
			||||||
	'''
 | 
						"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def __init__(self):
 | 
						def __init__(self):
 | 
				
			||||||
		self._exported_methods=[]
 | 
							self._exported_methods=[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def PlugIn(self, owner):
 | 
						def PlugIn(self, owner):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Attach to owner and register ourself and our _exported_methods in it.
 | 
							Attach to owner and register ourself and our _exported_methods in it.
 | 
				
			||||||
		If defined by a subclass, call self.plugin(owner) to execute hook
 | 
							If defined by a subclass, call self.plugin(owner) to execute hook
 | 
				
			||||||
		code after plugging.
 | 
							code after plugging
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		self._owner=owner
 | 
							self._owner=owner
 | 
				
			||||||
		log.info('Plugging %s __INTO__ %s' % (self, self._owner))
 | 
							log.info('Plugging %s __INTO__ %s' % (self, self._owner))
 | 
				
			||||||
		if self.__class__.__name__ in owner.__dict__:
 | 
							if self.__class__.__name__ in owner.__dict__:
 | 
				
			||||||
| 
						 | 
					@ -63,11 +64,11 @@ class PlugIn:
 | 
				
			||||||
			return self.plugin(owner)
 | 
								return self.plugin(owner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def PlugOut(self):
 | 
						def PlugOut(self):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Unregister our _exported_methods from owner and detach from it.
 | 
							Unregister our _exported_methods from owner and detach from it.
 | 
				
			||||||
		If defined by a subclass, call self.plugout() after unplugging to execute
 | 
							If defined by a subclass, call self.plugout() after unplugging to execute
 | 
				
			||||||
		hook code.
 | 
							hook code
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		log.info('Plugging %s __OUT__ of %s.' % (self, self._owner))
 | 
							log.info('Plugging %s __OUT__ of %s.' % (self, self._owner))
 | 
				
			||||||
		for method in self._exported_methods:
 | 
							for method in self._exported_methods:
 | 
				
			||||||
			del self._owner.__dict__[method.__name__]
 | 
								del self._owner.__dict__[method.__name__]
 | 
				
			||||||
| 
						 | 
					@ -85,13 +86,13 @@ class PlugIn:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@classmethod
 | 
						@classmethod
 | 
				
			||||||
	def get_instance(cls, *args, **kwargs):
 | 
						def get_instance(cls, *args, **kwargs):
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		Factory Method for object creation.
 | 
							Factory Method for object creation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Use this instead of directly initializing the class in order to make
 | 
							Use this instead of directly initializing the class in order to make
 | 
				
			||||||
		unit testing easier. For testing, this method can be patched to inject
 | 
							unit testing easier. For testing, this method can be patched to inject
 | 
				
			||||||
		mock objects.
 | 
							mock objects.
 | 
				
			||||||
		'''
 | 
							"""
 | 
				
			||||||
		return cls(*args, **kwargs)
 | 
							return cls(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# vim: se ts=3:
 | 
					# vim: se ts=3:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		
		Reference in a new issue