More doc-string (and not only) refactoring
This commit is contained in:
parent
99472b1702
commit
6d0f28c47d
|
@ -13,12 +13,14 @@
|
|||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
'''
|
||||
|
||||
"""
|
||||
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
|
||||
'''
|
||||
"""
|
||||
|
||||
from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH
|
||||
from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID
|
||||
from plugin import PlugIn
|
||||
|
@ -49,7 +51,8 @@ SASL_UNSUPPORTED = 'not-supported'
|
|||
SASL_IN_PROCESS = 'in-process'
|
||||
|
||||
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:
|
||||
username="example.org",realm="somerealm",\
|
||||
|
@ -59,7 +62,7 @@ def challenge_splitter(data):
|
|||
Expected result for challan:
|
||||
dict['qop'] = ('auth','auth-int','auth-conf')
|
||||
dict['realm'] = 'somerealm'
|
||||
'''
|
||||
"""
|
||||
X_KEYWORD, X_VALUE, X_END = 0, 1, 2
|
||||
quotes_open = False
|
||||
keyword, value = '', ''
|
||||
|
@ -112,16 +115,17 @@ def challenge_splitter(data):
|
|||
|
||||
|
||||
class SASL(PlugIn):
|
||||
'''
|
||||
"""
|
||||
Implements SASL authentication. Can be plugged into NonBlockingClient
|
||||
to start authentication.
|
||||
'''
|
||||
to start authentication
|
||||
"""
|
||||
|
||||
def __init__(self, username, password, on_sasl):
|
||||
'''
|
||||
"""
|
||||
:param user: XMPP username
|
||||
:param password: XMPP password
|
||||
:param on_sasl: Callback, will be called after each SASL auth-step.
|
||||
'''
|
||||
"""
|
||||
PlugIn.__init__(self)
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
@ -141,7 +145,9 @@ class SASL(PlugIn):
|
|||
self.startsasl = None
|
||||
|
||||
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__:
|
||||
self._owner.UnregisterHandler('features', self.FeaturesHandler,
|
||||
xmlns=NS_STREAMS)
|
||||
|
@ -156,13 +162,13 @@ class SASL(PlugIn):
|
|||
xmlns=NS_SASL)
|
||||
|
||||
def auth(self):
|
||||
'''
|
||||
"""
|
||||
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()
|
||||
calls.
|
||||
'''
|
||||
"""
|
||||
if self.startsasl:
|
||||
pass
|
||||
elif self._owner.Dispatcher.Stream.features:
|
||||
|
@ -176,7 +182,9 @@ class SASL(PlugIn):
|
|||
self.FeaturesHandler, xmlns=NS_STREAMS)
|
||||
|
||||
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):
|
||||
self.startsasl='not-supported'
|
||||
log.error('SASL not supported by server')
|
||||
|
@ -235,7 +243,9 @@ class SASL(PlugIn):
|
|||
return
|
||||
|
||||
def SASLHandler(self, conn, challenge):
|
||||
''' Perform next SASL auth step. Used internally. '''
|
||||
"""
|
||||
Perform next SASL auth step. Used internally
|
||||
"""
|
||||
if challenge.getNamespace() != NS_SASL:
|
||||
return
|
||||
### Handle Auth result
|
||||
|
@ -359,12 +369,15 @@ class SASL(PlugIn):
|
|||
|
||||
|
||||
class NonBlockingNonSASL(PlugIn):
|
||||
'''
|
||||
"""
|
||||
Implements old Non-SASL (JEP-0078) authentication used in jabberd1.4 and
|
||||
transport authentication.
|
||||
'''
|
||||
transport authentication
|
||||
"""
|
||||
|
||||
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)
|
||||
self.user = user
|
||||
if password is None:
|
||||
|
@ -375,10 +388,10 @@ class NonBlockingNonSASL(PlugIn):
|
|||
self.on_auth = on_auth
|
||||
|
||||
def plugin(self, owner):
|
||||
'''
|
||||
"""
|
||||
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')
|
||||
self.owner = owner
|
||||
|
||||
|
@ -438,10 +451,11 @@ class NonBlockingNonSASL(PlugIn):
|
|||
|
||||
|
||||
class NonBlockingBind(PlugIn):
|
||||
'''
|
||||
"""
|
||||
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):
|
||||
PlugIn.__init__(self)
|
||||
self.bound = None
|
||||
|
@ -459,10 +473,10 @@ class NonBlockingBind(PlugIn):
|
|||
xmlns=NS_STREAMS)
|
||||
|
||||
def FeaturesHandler(self, conn, feats):
|
||||
'''
|
||||
"""
|
||||
Determine if server supports resource binding and set some internal
|
||||
attributes accordingly.
|
||||
'''
|
||||
attributes accordingly
|
||||
"""
|
||||
if not feats.getTag('bind', namespace=NS_BIND):
|
||||
log.error('Server does not requested binding.')
|
||||
# we try to bind resource anyway
|
||||
|
@ -476,14 +490,16 @@ class NonBlockingBind(PlugIn):
|
|||
self.bound = []
|
||||
|
||||
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,
|
||||
xmlns=NS_STREAMS)
|
||||
|
||||
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._resource = 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))
|
||||
|
||||
def on_http_request_possible(self):
|
||||
'''
|
||||
"""
|
||||
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.
|
||||
'''
|
||||
"""
|
||||
log.debug('on_http_req possible, state:\n%s' % self.get_current_state())
|
||||
if self.get_state()==DISCONNECTED: return
|
||||
|
||||
|
@ -149,14 +150,18 @@ class NonBlockingBOSH(NonBlockingTransport):
|
|||
|
||||
|
||||
def get_socket_in(self, state):
|
||||
''' gets sockets in desired state '''
|
||||
"""
|
||||
Get sockets in desired state
|
||||
"""
|
||||
for s in self.http_socks:
|
||||
if s.get_state()==state: return s
|
||||
return None
|
||||
|
||||
|
||||
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:
|
||||
return self.get_socket_in(CONNECTED)
|
||||
else:
|
||||
|
@ -176,10 +181,10 @@ class NonBlockingBOSH(NonBlockingTransport):
|
|||
|
||||
|
||||
def send_BOSH(self, payload):
|
||||
'''
|
||||
"""
|
||||
Tries to send a stanza in payload by appeding it to a buffer and plugging a
|
||||
free socket for writing.
|
||||
'''
|
||||
"""
|
||||
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
|
||||
|
@ -236,15 +241,16 @@ class NonBlockingBOSH(NonBlockingTransport):
|
|||
log.error('=====!!!!!!!!====> Couldn\'t get free socket in plug_socket())')
|
||||
|
||||
def build_stanza(self, socket):
|
||||
'''
|
||||
Builds a BOSH body tag from data in buffers and adds key, rid and ack
|
||||
attributes to it.
|
||||
"""
|
||||
Build a BOSH body tag from data in buffers and adds key, rid and ack
|
||||
attributes to it
|
||||
|
||||
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
|
||||
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
|
||||
in violating the BOSH session and server-side disconnect.
|
||||
'''
|
||||
ensure rid and keys will be processed in correct order. If I generate
|
||||
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 in violating the BOSH session and server-side disconnect.
|
||||
"""
|
||||
if self.prio_bosh_stanzas:
|
||||
stanza, add_payload = self.prio_bosh_stanzas.pop(0)
|
||||
if add_payload:
|
||||
|
@ -285,10 +291,11 @@ class NonBlockingBOSH(NonBlockingTransport):
|
|||
self.wait_cb_time)
|
||||
|
||||
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
|
||||
'''
|
||||
"""
|
||||
if socket.http_persistent:
|
||||
log.warn('Fallback to nonpersistent HTTP (no pipelining as well)')
|
||||
socket.http_persistent = False
|
||||
|
@ -302,9 +309,10 @@ class NonBlockingBOSH(NonBlockingTransport):
|
|||
|
||||
|
||||
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()
|
||||
|
||||
if self.after_init:
|
||||
|
@ -345,7 +353,9 @@ class NonBlockingBOSH(NonBlockingTransport):
|
|||
|
||||
|
||||
def append_stanza(self, stanza):
|
||||
''' appends stanza to a buffer to send '''
|
||||
"""
|
||||
Append stanza to a buffer to send
|
||||
"""
|
||||
if stanza:
|
||||
if isinstance(stanza, tuple):
|
||||
# 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):
|
||||
''' 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))
|
||||
tag = BOSHBody(attrs={'sid': self.bosh_sid})
|
||||
tag.setPayload(stanzas)
|
||||
|
@ -470,10 +482,10 @@ def get_rand_number():
|
|||
|
||||
|
||||
class AckChecker():
|
||||
'''
|
||||
"""
|
||||
Class for generating rids and generating and checking acknowledgements in
|
||||
BOSH messages.
|
||||
'''
|
||||
BOSH messages
|
||||
"""
|
||||
def __init__(self):
|
||||
self.rid = get_rand_number()
|
||||
self.ack = 1
|
||||
|
@ -516,9 +528,9 @@ class AckChecker():
|
|||
|
||||
|
||||
class KeyStack():
|
||||
'''
|
||||
"""
|
||||
Class implementing key sequences for BOSH messages
|
||||
'''
|
||||
"""
|
||||
def __init__(self, count):
|
||||
self.count = count
|
||||
self.keys = []
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
## 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
|
||||
|
||||
def c14n(node, is_buggy):
|
||||
|
|
|
@ -16,9 +16,10 @@
|
|||
|
||||
# $Id: client.py,v 1.52 2006/01/02 19:40:55 normanr Exp $
|
||||
|
||||
'''
|
||||
"""
|
||||
Client class establishs connection to XMPP Server and handles authentication
|
||||
'''
|
||||
"""
|
||||
|
||||
import socket
|
||||
import transports_nb, dispatcher_nb, auth_nb, roster_nb, protocol, bosh
|
||||
from protocol import NS_TLS
|
||||
|
@ -28,21 +29,22 @@ log = logging.getLogger('gajim.c.x.client_nb')
|
|||
|
||||
|
||||
class NonBlockingClient:
|
||||
'''
|
||||
"""
|
||||
Client class is XMPP connection mountpoint. Objects for authentication,
|
||||
network communication, roster, xml parsing ... are plugged to client object.
|
||||
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):
|
||||
'''
|
||||
Caches connection data:
|
||||
"""
|
||||
Caches connection data
|
||||
|
||||
:param domain: domain - for to: attribute (from account info)
|
||||
:param idlequeue: processing idlequeue
|
||||
:param caller: calling object - it has to implement methods
|
||||
_event_dispatcher which is called from dispatcher instance
|
||||
'''
|
||||
"""
|
||||
self.Namespace = protocol.NS_CLIENT
|
||||
self.defaultNamespace = self.Namespace
|
||||
|
||||
|
@ -69,10 +71,10 @@ class NonBlockingClient:
|
|||
self.protocol_type = 'XMPP'
|
||||
|
||||
def disconnect(self, message=''):
|
||||
'''
|
||||
Called on disconnection - disconnect callback is picked based on state
|
||||
of the client.
|
||||
'''
|
||||
"""
|
||||
Called on disconnection - disconnect callback is picked based on state of
|
||||
the client.
|
||||
"""
|
||||
# to avoid recursive calls
|
||||
if self.disconnecting: return
|
||||
|
||||
|
@ -132,9 +134,10 @@ class NonBlockingClient:
|
|||
self.disconnecting = False
|
||||
|
||||
def connect(self, on_connect, on_connect_failure, hostname=None, port=5222,
|
||||
on_proxy_failure=None, proxy=None, secure_tuple=('plain', None, None)):
|
||||
'''
|
||||
Open XMPP connection (open XML streams in both directions).
|
||||
on_proxy_failure=None, proxy=None, secure_tuple=('plain', None,
|
||||
None)):
|
||||
"""
|
||||
Open XMPP connection (open XML streams in both directions)
|
||||
|
||||
:param on_connect: called after stream is successfully opened
|
||||
: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'.
|
||||
cacerts, mycerts - see tls_nb.NonBlockingTLS constructor for more
|
||||
details
|
||||
'''
|
||||
"""
|
||||
self.on_connect = on_connect
|
||||
self.on_connect_failure=on_connect_failure
|
||||
self.on_proxy_failure = on_proxy_failure
|
||||
|
@ -223,7 +226,11 @@ class NonBlockingClient:
|
|||
on_success=self._try_next_ip)
|
||||
|
||||
def _resolve_hostname(self, hostname, port, on_success):
|
||||
''' wrapper for getaddinfo call. FIXME: getaddinfo blocks'''
|
||||
"""
|
||||
Wrapper for getaddinfo call
|
||||
|
||||
FIXME: getaddinfo blocks
|
||||
"""
|
||||
try:
|
||||
self.ip_addresses = socket.getaddrinfo(hostname, port,
|
||||
socket.AF_UNSPEC, socket.SOCK_STREAM)
|
||||
|
@ -234,7 +241,9 @@ class NonBlockingClient:
|
|||
on_success()
|
||||
|
||||
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:
|
||||
log.debug('While looping over DNS A records: %s' % err_message)
|
||||
if self.ip_addresses == []:
|
||||
|
@ -249,18 +258,20 @@ class NonBlockingClient:
|
|||
on_connect_failure=self._try_next_ip)
|
||||
|
||||
def incoming_stream_version(self):
|
||||
''' gets version of xml stream'''
|
||||
"""
|
||||
Get version of xml stream
|
||||
"""
|
||||
if 'version' in self.Dispatcher.Stream._document_attrs:
|
||||
return self.Dispatcher.Stream._document_attrs['version']
|
||||
else:
|
||||
return 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
|
||||
negotiated with <starttls>.
|
||||
'''
|
||||
"""
|
||||
# socket_type contains info which transport connection was established
|
||||
if not socket_type:
|
||||
if self.Connection.ssl_lib:
|
||||
|
@ -273,19 +284,19 @@ class NonBlockingClient:
|
|||
self._xmpp_connect_machine()
|
||||
|
||||
def _xmpp_connect_machine(self, mode=None, data=None):
|
||||
'''
|
||||
Finite automaton taking care of stream opening and features tag
|
||||
handling. Calls _on_stream_start when stream is started, and disconnect()
|
||||
on failure.
|
||||
'''
|
||||
"""
|
||||
Finite automaton taking care of stream opening and features tag handling.
|
||||
Calls _on_stream_start when stream is started, and disconnect() on
|
||||
failure.
|
||||
"""
|
||||
log.info('-------------xmpp_connect_machine() >> mode: %s, data: %s...' %
|
||||
(mode, str(data)[:20]))
|
||||
|
||||
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.
|
||||
'''
|
||||
"""
|
||||
log.info('setting %s on next receive' % mode)
|
||||
if mode is None:
|
||||
self.onreceive(None) # switch to Dispatcher.ProcessNonBlocking
|
||||
|
@ -346,10 +357,10 @@ class NonBlockingClient:
|
|||
self._on_stream_start()
|
||||
|
||||
def _on_stream_start(self):
|
||||
'''
|
||||
"""
|
||||
Called after XMPP stream is opened. TLS negotiation may follow if
|
||||
supported and desired.
|
||||
'''
|
||||
"""
|
||||
self.stream_started = True
|
||||
self.onreceive(None)
|
||||
|
||||
|
@ -381,7 +392,9 @@ class NonBlockingClient:
|
|||
assert False, 'Stream opened for unsupported connection'
|
||||
|
||||
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)
|
||||
if not con and not tag:
|
||||
# starting state when we send the <starttls>
|
||||
|
@ -407,15 +420,17 @@ class NonBlockingClient:
|
|||
on_fail = lambda: self.disconnect('error while etabilishing TLS'))
|
||||
|
||||
def _on_connect(self):
|
||||
''' preceeds call of on_connect callback '''
|
||||
"""
|
||||
Preceed call of on_connect callback
|
||||
"""
|
||||
self.onreceive(None)
|
||||
self.on_connect(self, self.connected)
|
||||
|
||||
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
|
||||
'''
|
||||
"""
|
||||
log.info('raising event from transport: :::::%s::::\n_____________\n%s\n_____________\n' % (event_type,data))
|
||||
if hasattr(self, 'Dispatcher'):
|
||||
self.Dispatcher.Event('', event_type, data)
|
||||
|
@ -425,9 +440,9 @@ class NonBlockingClient:
|
|||
###############################################################################
|
||||
|
||||
def auth(self, user, password, resource='', sasl=True, on_auth=None):
|
||||
'''
|
||||
"""
|
||||
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 password: XMPP password
|
||||
|
@ -435,7 +450,7 @@ class NonBlockingClient:
|
|||
:param sasl: Boolean indicating if SASL shall be used. (default: True)
|
||||
:param on_auth: Callback, called after auth. On auth failure, argument
|
||||
is None.
|
||||
'''
|
||||
"""
|
||||
self._User, self._Password = user, password
|
||||
self._Resource, self._sasl = resource, sasl
|
||||
self.on_auth = on_auth
|
||||
|
@ -443,7 +458,9 @@ class NonBlockingClient:
|
|||
return
|
||||
|
||||
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:
|
||||
self.connected += '+old_auth'
|
||||
self.on_auth(self, 'old_auth')
|
||||
|
@ -451,7 +468,9 @@ class NonBlockingClient:
|
|||
self.on_auth(self, None)
|
||||
|
||||
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)
|
||||
if res:
|
||||
self.connected += '+sasl'
|
||||
|
@ -460,7 +479,9 @@ class NonBlockingClient:
|
|||
self.on_auth(self, None)
|
||||
|
||||
def _on_doc_attrs(self):
|
||||
''' Plug authentication objects and start auth. '''
|
||||
"""
|
||||
Plug authentication objects and start auth
|
||||
"""
|
||||
if self._sasl:
|
||||
auth_nb.SASL.get_instance(self._User, self._Password,
|
||||
self._on_start_sasl).PlugIn(self)
|
||||
|
@ -474,7 +495,9 @@ class NonBlockingClient:
|
|||
return True
|
||||
|
||||
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:
|
||||
self.Dispatcher.ProcessNonBlocking(data)
|
||||
if not 'SASL' in self.__dict__:
|
||||
|
@ -504,20 +527,26 @@ class NonBlockingClient:
|
|||
return True
|
||||
|
||||
def initRoster(self, version=''):
|
||||
''' Plug in the roster. '''
|
||||
"""
|
||||
Plug in the roster
|
||||
"""
|
||||
if not self.__dict__.has_key('NonBlockingRoster'):
|
||||
return roster_nb.NonBlockingRoster.get_instance(version=version).PlugIn(self)
|
||||
|
||||
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'):
|
||||
return self.NonBlockingRoster.getRoster(on_ready, force)
|
||||
return None
|
||||
|
||||
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:
|
||||
# FIXME: used somewhere?
|
||||
roster_nb.NonBlockingRoster.get_instance().PlugIn(self)
|
||||
|
@ -528,31 +557,38 @@ class NonBlockingClient:
|
|||
###############################################################################
|
||||
|
||||
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)
|
||||
|
||||
def UnregisterDisconnectHandler(self,handler):
|
||||
''' Unregister handler that is called on disconnect.'''
|
||||
"""
|
||||
Unregister handler that is called on disconnect
|
||||
"""
|
||||
self.disconnect_handlers.remove(handler)
|
||||
|
||||
def DisconnectHandler(self):
|
||||
'''
|
||||
"""
|
||||
Default disconnect handler. Just raises an IOError. If you choosed to use
|
||||
this class in your production client, override this method or at least
|
||||
unregister it.
|
||||
'''
|
||||
"""
|
||||
raise IOError('Disconnected from server.')
|
||||
|
||||
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
|
||||
|
||||
def get_peerhost(self):
|
||||
'''
|
||||
"""
|
||||
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
|
||||
'''
|
||||
"""
|
||||
# FIXME: tuple (ip, port) is expected (and checked for) but port num is
|
||||
# useless
|
||||
return self.socket.peerhost
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
## GNU General Public License for more details.
|
||||
|
||||
|
||||
'''
|
||||
"""
|
||||
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
|
||||
from xml.parsers.expat import ExpatError
|
||||
|
@ -36,7 +36,7 @@ XML_DECLARATION = '<?xml version=\'1.0\'?>'
|
|||
|
||||
# FIXME: ugly
|
||||
class Dispatcher():
|
||||
'''
|
||||
"""
|
||||
Why is this here - I needed to redefine Dispatcher for BOSH and easiest way
|
||||
was to inherit original Dispatcher (now renamed to XMPPDispatcher). Trouble
|
||||
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
|
||||
references in other scripts
|
||||
'''
|
||||
"""
|
||||
|
||||
def PlugIn(self, client_obj, after_SASL=False, old_features=None):
|
||||
if client_obj.protocol_type == 'XMPP':
|
||||
XMPPDispatcher().PlugIn(client_obj)
|
||||
|
@ -57,22 +58,23 @@ class Dispatcher():
|
|||
|
||||
@classmethod
|
||||
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
|
||||
unit testing much easier.
|
||||
'''
|
||||
"""
|
||||
return cls(*args, **kwargs)
|
||||
|
||||
|
||||
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
|
||||
stream headers (used by SASL f.e.).
|
||||
'''
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
PlugIn.__init__(self)
|
||||
self.handlers = {}
|
||||
|
@ -94,25 +96,24 @@ class XMPPDispatcher(PlugIn):
|
|||
return repr(outgoingID)
|
||||
|
||||
def dumpHandlers(self):
|
||||
'''
|
||||
Return set of user-registered callbacks in it's internal format.
|
||||
Used within the library to carry user handlers set over Dispatcher
|
||||
replugins.
|
||||
'''
|
||||
"""
|
||||
Return set of user-registered callbacks in it's internal format. Used
|
||||
within the library to carry user handlers set over Dispatcher replugins
|
||||
"""
|
||||
return self.handlers
|
||||
|
||||
def restoreHandlers(self, handlers):
|
||||
'''
|
||||
Restores user-registered callbacks structure from dump previously
|
||||
obtained via dumpHandlers. Used within the library to carry user
|
||||
handlers set over Dispatcher replugins.
|
||||
'''
|
||||
"""
|
||||
Restore user-registered callbacks structure from dump previously obtained
|
||||
via dumpHandlers. Used within the library to carry user handlers set over
|
||||
Dispatcher replugins.
|
||||
"""
|
||||
self.handlers = handlers
|
||||
|
||||
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
|
||||
# owner
|
||||
self.RegisterNamespace('unknown')
|
||||
|
@ -126,10 +127,10 @@ class XMPPDispatcher(PlugIn):
|
|||
self.on_responses = {}
|
||||
|
||||
def plugin(self, owner):
|
||||
'''
|
||||
Plug the Dispatcher instance into Client class instance and send
|
||||
initial stream header. Used internally.
|
||||
'''
|
||||
"""
|
||||
Plug the Dispatcher instance into Client class instance and send initial
|
||||
stream header. Used internally
|
||||
"""
|
||||
self._init()
|
||||
self._owner.lastErrNode = None
|
||||
self._owner.lastErr = None
|
||||
|
@ -140,7 +141,9 @@ class XMPPDispatcher(PlugIn):
|
|||
self.StreamInit()
|
||||
|
||||
def plugout(self):
|
||||
''' Prepares instance to be destructed. '''
|
||||
"""
|
||||
Prepare instance to be destructed
|
||||
"""
|
||||
self.Stream.dispatch = None
|
||||
self.Stream.features = None
|
||||
self.Stream.destroy()
|
||||
|
@ -148,7 +151,9 @@ class XMPPDispatcher(PlugIn):
|
|||
self.Stream = None
|
||||
|
||||
def StreamInit(self):
|
||||
''' Send an initial stream header. '''
|
||||
"""
|
||||
Send an initial stream header
|
||||
"""
|
||||
self.Stream = simplexml.NodeBuilder()
|
||||
self.Stream.dispatch = self.dispatch
|
||||
self.Stream._dispatch_depth = 2
|
||||
|
@ -170,15 +175,15 @@ class XMPPDispatcher(PlugIn):
|
|||
% (tag, ns))
|
||||
|
||||
def ProcessNonBlocking(self, data):
|
||||
'''
|
||||
Check incoming stream for data waiting.
|
||||
"""
|
||||
Check incoming stream for data waiting
|
||||
|
||||
:param data: data received from transports/IO sockets
|
||||
:return:
|
||||
1) length of processed data if some data were processed;
|
||||
2) '0' string if no data were processed but link is alive;
|
||||
3) 0 (zero) if underlying connection is closed.
|
||||
'''
|
||||
"""
|
||||
# FIXME:
|
||||
# When an error occurs we disconnect the transport directly. Client's
|
||||
# disconnect method will never be called.
|
||||
|
@ -211,41 +216,42 @@ class XMPPDispatcher(PlugIn):
|
|||
return len(data)
|
||||
|
||||
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
|
||||
one namespace is already registered
|
||||
(jabber:client or jabber:component:accept depending on context.
|
||||
'''
|
||||
"""
|
||||
log.debug('Registering namespace "%s"' % xmlns)
|
||||
self.handlers[xmlns] = {}
|
||||
self.RegisterProtocol('unknown', Protocol, xmlns=xmlns)
|
||||
self.RegisterProtocol('default', Protocol, xmlns=xmlns)
|
||||
|
||||
def RegisterProtocol(self, tag_name, Proto, xmlns=None, order='info'):
|
||||
'''
|
||||
Used to declare some top-level stanza name to dispatcher.
|
||||
Needed to start registering handlers for such stanzas.
|
||||
"""
|
||||
Used to declare some top-level stanza name to dispatcher
|
||||
|
||||
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:
|
||||
xmlns=self._owner.defaultNamespace
|
||||
log.debug('Registering protocol "%s" as %s(%s)' %(tag_name, Proto, xmlns))
|
||||
self.handlers[xmlns][tag_name] = {type:Proto, 'default':[]}
|
||||
|
||||
def RegisterNamespaceHandler(self, xmlns, handler, typ='', ns='',
|
||||
makefirst=0, system=0):
|
||||
'''
|
||||
Register handler for processing all stanzas for specified namespace.
|
||||
'''
|
||||
makefirst=0, system=0):
|
||||
"""
|
||||
Register handler for processing all stanzas for specified namespace
|
||||
"""
|
||||
self.RegisterHandler('default', handler, typ, ns, xmlns, makefirst,
|
||||
system)
|
||||
|
||||
def RegisterHandler(self, name, handler, typ='', ns='', xmlns=None,
|
||||
makefirst=False, system=False):
|
||||
'''
|
||||
Register user callback as stanzas handler of declared type.
|
||||
"""
|
||||
Register user callback as stanzas handler of declared type
|
||||
|
||||
Callback arguments:
|
||||
dispatcher instance (for replying), incoming return of previous handlers.
|
||||
|
@ -263,7 +269,7 @@ class XMPPDispatcher(PlugIn):
|
|||
and " will be called first nevertheless.
|
||||
:param system: call handler even if NodeProcessed Exception were raised
|
||||
already.
|
||||
'''
|
||||
"""
|
||||
if not xmlns:
|
||||
xmlns=self._owner.defaultNamespace
|
||||
log.debug('Registering handler %s for "%s" type->%s ns->%s(%s)' %
|
||||
|
@ -284,18 +290,20 @@ class XMPPDispatcher(PlugIn):
|
|||
'system':system})
|
||||
|
||||
def RegisterHandlerOnce(self, name, handler, typ='', ns='', xmlns=None,
|
||||
makefirst=0, system=0):
|
||||
''' Unregister handler after first call (not implemented yet). '''
|
||||
makefirst=0, system=0):
|
||||
"""
|
||||
Unregister handler after first call (not implemented yet)
|
||||
"""
|
||||
# FIXME Drop or implement
|
||||
if not xmlns:
|
||||
xmlns = self._owner.defaultNamespace
|
||||
self.RegisterHandler(name, handler, typ, ns, xmlns, makefirst, system)
|
||||
|
||||
def UnregisterHandler(self, name, handler, typ='', ns='', xmlns=None):
|
||||
'''
|
||||
"""
|
||||
Unregister handler. "typ" and "ns" must be specified exactly the same as
|
||||
with registering.
|
||||
'''
|
||||
"""
|
||||
if not xmlns:
|
||||
xmlns = self._owner.defaultNamespace
|
||||
if not typ and not ns:
|
||||
|
@ -314,58 +322,59 @@ class XMPPDispatcher(PlugIn):
|
|||
pass
|
||||
|
||||
def RegisterDefaultHandler(self, handler):
|
||||
'''
|
||||
"""
|
||||
Specify the handler that will be used if no NodeProcessed exception were
|
||||
raised. This is returnStanzaHandler by default.
|
||||
'''
|
||||
"""
|
||||
self._defaultHandler = handler
|
||||
|
||||
def RegisterEventHandler(self, handler):
|
||||
'''
|
||||
Register handler that will process events. F.e.
|
||||
"FILERECEIVED" event. See common/connection: _event_dispatcher()
|
||||
'''
|
||||
"""
|
||||
Register handler that will process events. F.e. "FILERECEIVED" event. See
|
||||
common/connection: _event_dispatcher()
|
||||
"""
|
||||
self._eventHandler = handler
|
||||
|
||||
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'):
|
||||
conn._owner.send(Error(stanza, ERR_FEATURE_NOT_IMPLEMENTED))
|
||||
|
||||
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:
|
||||
self._cycleHandlers.append(handler)
|
||||
|
||||
def UnregisterCycleHandler(self, handler):
|
||||
'''
|
||||
"""
|
||||
Unregister handler that will is called on every Dispatcher.Process() call
|
||||
'''
|
||||
"""
|
||||
if handler in self._cycleHandlers:
|
||||
self._cycleHandlers.remove(handler)
|
||||
|
||||
def Event(self, realm, event, data):
|
||||
'''
|
||||
Raise some event.
|
||||
"""
|
||||
Raise some event
|
||||
|
||||
:param realm: scope of event. Usually a namespace.
|
||||
:param event: the event itself. F.e. "SUCCESSFUL SEND".
|
||||
:param data: data that comes along with event. Depends on event.
|
||||
'''
|
||||
"""
|
||||
if self._eventHandler:
|
||||
self._eventHandler(realm, event, data)
|
||||
else:
|
||||
log.warning('Received unhandled event: %s' % event)
|
||||
|
||||
def dispatch(self, stanza, session=None, direct=0):
|
||||
'''
|
||||
"""
|
||||
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
|
||||
# to do?
|
||||
|
||||
|
@ -450,9 +459,9 @@ class XMPPDispatcher(PlugIn):
|
|||
self._defaultHandler(session, stanza)
|
||||
|
||||
def _WaitForData(self, data):
|
||||
'''
|
||||
"""
|
||||
Internal wrapper around ProcessNonBlocking. Will check for
|
||||
'''
|
||||
"""
|
||||
if data is None:
|
||||
return
|
||||
res = self.ProcessNonBlocking(data)
|
||||
|
@ -481,12 +490,12 @@ class XMPPDispatcher(PlugIn):
|
|||
del self._expected[_id]
|
||||
|
||||
def SendAndWaitForResponse(self, stanza, timeout=None, func=None, args=None):
|
||||
'''
|
||||
"""
|
||||
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.
|
||||
'''
|
||||
"""
|
||||
if timeout is None:
|
||||
timeout = DEFAULT_TIMEOUT_SECONDS
|
||||
_waitid = self.send(stanza)
|
||||
|
@ -499,15 +508,17 @@ class XMPPDispatcher(PlugIn):
|
|||
return _waitid
|
||||
|
||||
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)
|
||||
|
||||
def send(self, stanza, now=False):
|
||||
'''
|
||||
Wraps transports send method when plugged into NonBlockingClient.
|
||||
Makes sure stanzas get ID and from tag.
|
||||
'''
|
||||
"""
|
||||
Wrap transports send method when plugged into NonBlockingClient. Makes
|
||||
sure stanzas get ID and from tag.
|
||||
"""
|
||||
ID = None
|
||||
if type(stanza) not in [type(''), type(u'')]:
|
||||
if isinstance(stanza, Protocol):
|
||||
|
@ -529,7 +540,9 @@ class BOSHDispatcher(XMPPDispatcher):
|
|||
XMPPDispatcher.PlugIn(self, owner)
|
||||
|
||||
def StreamInit(self):
|
||||
''' Send an initial stream header. '''
|
||||
"""
|
||||
Send an initial stream header
|
||||
"""
|
||||
self.Stream = simplexml.NodeBuilder()
|
||||
self.Stream.dispatch = self.dispatch
|
||||
self.Stream._dispatch_depth = 2
|
||||
|
@ -549,7 +562,9 @@ class BOSHDispatcher(XMPPDispatcher):
|
|||
self._owner.Connection.send_init(after_SASL=self.after_SASL)
|
||||
|
||||
def StreamTerminate(self):
|
||||
''' Send a stream terminator. '''
|
||||
"""
|
||||
Send a stream terminator
|
||||
"""
|
||||
self._owner.Connection.send_terminator()
|
||||
|
||||
def ProcessNonBlocking(self, data=None):
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
|
||||
# $Id: features.py,v 1.22 2005/09/30 20:13:04 mikealbon Exp $
|
||||
|
||||
'''
|
||||
"""
|
||||
Different stuff that wasn't worth separating it into modules
|
||||
(Registration, Privacy Lists, ...)
|
||||
'''
|
||||
"""
|
||||
|
||||
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'
|
||||
|
||||
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 info: dict, like {'username':'joey'}.
|
||||
|
||||
See JEP-0077 for details.
|
||||
'''
|
||||
"""
|
||||
iq=Iq('get',NS_REGISTER,to=host)
|
||||
for i in info.keys():
|
||||
iq.setTagData(i,info[i])
|
||||
|
@ -77,12 +77,12 @@ def _ReceivedRegInfo(con, resp, agent):
|
|||
con.Event(NS_REGISTER, REGISTER_DATA_RECEIVED, (agent,df,False,''))
|
||||
|
||||
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
|
||||
owner attributes lastErrNode, lastErr and lastErrCode.
|
||||
'''
|
||||
"""
|
||||
iq=Iq('set', NS_REGISTER, to=host)
|
||||
if not isinstance(info, dict):
|
||||
info=info.asDict()
|
||||
|
@ -91,17 +91,17 @@ def register(disp, host, info, cb):
|
|||
disp.SendAndCallForResponse(iq, cb)
|
||||
|
||||
def unregister(disp, host, cb):
|
||||
'''
|
||||
"""
|
||||
Unregisters with host (permanently removes account). Returns true on success
|
||||
'''
|
||||
"""
|
||||
iq = Iq('set', NS_REGISTER, to=host, payload=[Node('remove')])
|
||||
_on_default_response(disp, iq, cb)
|
||||
|
||||
def changePasswordTo(disp, newpassword, host=None, cb = None):
|
||||
'''
|
||||
Changes password on specified or current (if not specified) server.
|
||||
Returns true on success.
|
||||
'''
|
||||
"""
|
||||
Changes password on specified or current (if not specified) server. Returns
|
||||
true on success.
|
||||
"""
|
||||
if not host:
|
||||
host = disp._owner.Server
|
||||
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'
|
||||
|
||||
def getPrivacyLists(disp):
|
||||
'''
|
||||
Requests privacy lists from connected server.
|
||||
Returns dictionary of existing lists on success.
|
||||
'''
|
||||
"""
|
||||
Request privacy lists from connected server. Returns dictionary of existing
|
||||
lists on success.
|
||||
"""
|
||||
iq = Iq('get', NS_PRIVACY)
|
||||
def _on_response(resp):
|
||||
dict_ = {'lists': []}
|
||||
|
@ -157,10 +157,10 @@ def getActiveAndDefaultPrivacyLists(disp):
|
|||
disp.SendAndCallForResponse(iq, _on_response)
|
||||
|
||||
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.
|
||||
'''
|
||||
"""
|
||||
def _on_response(resp):
|
||||
if not isResultNode(resp):
|
||||
disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (False))
|
||||
|
@ -170,10 +170,10 @@ def getPrivacyList(disp, listname):
|
|||
disp.SendAndCallForResponse(iq, _on_response)
|
||||
|
||||
def setActivePrivacyList(disp, listname=None, typ='active', cb=None):
|
||||
'''
|
||||
Switches privacy list 'listname' to specified type.
|
||||
By default the type is 'active'. Returns true on success.
|
||||
'''
|
||||
"""
|
||||
Switch privacy list 'listname' to specified type. By default the type is
|
||||
'active'. Returns true on success.
|
||||
"""
|
||||
if listname:
|
||||
attrs={'name':listname}
|
||||
else:
|
||||
|
@ -182,15 +182,20 @@ def setActivePrivacyList(disp, listname=None, typ='active', cb=None):
|
|||
_on_default_response(disp, iq, cb)
|
||||
|
||||
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')
|
||||
|
||||
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 = '')
|
||||
list_query = iq.getTag('query').setTag('list', {'name': listname})
|
||||
for item in tags:
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## 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 select
|
||||
import logging
|
||||
|
@ -45,7 +47,9 @@ IS_CLOSED = 16 # channel closed
|
|||
|
||||
|
||||
def get_idlequeue():
|
||||
''' Get an appropriate idlequeue '''
|
||||
"""
|
||||
Get an appropriate idlequeue
|
||||
"""
|
||||
if os.name == 'nt':
|
||||
# gobject.io_add_watch does not work on windows
|
||||
return SelectIdleQueue()
|
||||
|
@ -59,34 +63,44 @@ def get_idlequeue():
|
|||
|
||||
|
||||
class IdleObject:
|
||||
'''
|
||||
Idle listener interface. Listed methods are called by IdleQueue.
|
||||
'''
|
||||
"""
|
||||
Idle listener interface. Listed methods are called by IdleQueue.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.fd = -1 #: filedescriptor, must be unique for each IdleObject
|
||||
|
||||
def pollend(self):
|
||||
''' called on stream failure '''
|
||||
"""
|
||||
Called on stream failure
|
||||
"""
|
||||
pass
|
||||
|
||||
def pollin(self):
|
||||
''' called on new read event '''
|
||||
"""
|
||||
Called on new read event
|
||||
"""
|
||||
pass
|
||||
|
||||
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
|
||||
|
||||
def read_timeout(self):
|
||||
''' called when timeout happened '''
|
||||
"""
|
||||
Called when timeout happened
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class IdleCommand(IdleObject):
|
||||
'''
|
||||
"""
|
||||
Can be subclassed to execute commands asynchronously by the idlequeue.
|
||||
Result will be optained via file descriptor of created pipe
|
||||
'''
|
||||
"""
|
||||
|
||||
def __init__(self, on_result):
|
||||
IdleObject.__init__(self)
|
||||
# how long (sec.) to wait for result ( 0 - forever )
|
||||
|
@ -111,7 +125,9 @@ class IdleCommand(IdleObject):
|
|||
return ['echo', 'da']
|
||||
|
||||
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,
|
||||
self._compose_command_args())
|
||||
|
||||
|
@ -187,7 +203,7 @@ class IdleCommand(IdleObject):
|
|||
|
||||
|
||||
class IdleQueue:
|
||||
'''
|
||||
"""
|
||||
IdleQueue provide three distinct time based features. Uses select.poll()
|
||||
|
||||
1. Alarm timeout: Execute a callback after foo seconds
|
||||
|
@ -195,7 +211,8 @@ class IdleQueue:
|
|||
has been set, but not removed in time.
|
||||
3. Check file descriptor of plugged objects for read, write and error
|
||||
events
|
||||
'''
|
||||
"""
|
||||
|
||||
# (timeout, boolean)
|
||||
# Boolean is True if timeout is specified in seconds, False means miliseconds
|
||||
PROCESS_TIMEOUT = (200, False)
|
||||
|
@ -215,13 +232,15 @@ class IdleQueue:
|
|||
self._init_idle()
|
||||
|
||||
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()
|
||||
|
||||
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
|
||||
# almost impossible, but in case we have another alarm_cb at this time
|
||||
if alarm_time in self.alarms:
|
||||
|
@ -231,10 +250,10 @@ class IdleQueue:
|
|||
return alarm_time
|
||||
|
||||
def remove_alarm(self, alarm_cb, alarm_time):
|
||||
'''
|
||||
Removes alarm callback alarm_cb scheduled on alarm_time.
|
||||
Returns True if it was removed sucessfully, otherwise False
|
||||
'''
|
||||
"""
|
||||
Remove alarm callback alarm_cb scheduled on alarm_time. Returns True if
|
||||
it was removed sucessfully, otherwise False
|
||||
"""
|
||||
if not alarm_time in self.alarms:
|
||||
return False
|
||||
i = -1
|
||||
|
@ -251,7 +270,9 @@ class IdleQueue:
|
|||
return False
|
||||
|
||||
def remove_timeout(self, fd, timeout=None):
|
||||
''' Removes the read timeout '''
|
||||
"""
|
||||
Remove the read timeout
|
||||
"""
|
||||
log.info('read timeout removed for fd %s' % fd)
|
||||
if fd in self.read_timeouts:
|
||||
if timeout:
|
||||
|
@ -263,12 +284,12 @@ class IdleQueue:
|
|||
del(self.read_timeouts[fd])
|
||||
|
||||
def set_read_timeout(self, fd, seconds, func=None):
|
||||
'''
|
||||
Sets a new timeout. If it is not removed after specified seconds,
|
||||
func or obj.read_timeout() will be called.
|
||||
"""
|
||||
Seta a new timeout. If it is not removed after specified seconds,
|
||||
func or obj.read_timeout() will be called
|
||||
|
||||
A filedescriptor fd can have several timeouts.
|
||||
'''
|
||||
"""
|
||||
log_txt = 'read timeout set for fd %s on %s seconds' % (fd, seconds)
|
||||
if func:
|
||||
log_txt += ' with function ' + str(func)
|
||||
|
@ -280,10 +301,10 @@ class IdleQueue:
|
|||
self.read_timeouts[fd] = {timeout: func}
|
||||
|
||||
def _check_time_events(self):
|
||||
'''
|
||||
"""
|
||||
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')
|
||||
current_time = self.current_time()
|
||||
|
||||
|
@ -313,13 +334,13 @@ class IdleQueue:
|
|||
del(self.alarms[alarm_time])
|
||||
|
||||
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 writable: True if obj has data to sent
|
||||
:param readable: True if obj expects data to be reiceived
|
||||
'''
|
||||
"""
|
||||
if obj.fd == -1:
|
||||
return
|
||||
if obj.fd in self.queue:
|
||||
|
@ -339,11 +360,15 @@ class IdleQueue:
|
|||
self._add_idle(obj.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)
|
||||
|
||||
def unplug_idle(self, fd):
|
||||
''' Removed plugged IdleObject, specified by filedescriptor fd. '''
|
||||
"""
|
||||
Remove plugged IdleObject, specified by filedescriptor fd
|
||||
"""
|
||||
if fd in self.queue:
|
||||
del(self.queue[fd])
|
||||
self._remove_idle(fd)
|
||||
|
@ -353,7 +378,9 @@ class IdleQueue:
|
|||
return time()
|
||||
|
||||
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)
|
||||
|
||||
def _process_events(self, fd, flags):
|
||||
|
@ -379,13 +406,13 @@ class IdleQueue:
|
|||
return False
|
||||
|
||||
def process(self):
|
||||
'''
|
||||
Process idlequeue. Check for any pending timeout or alarm events.
|
||||
Call IdleObjects on possible and requested read, write and error events
|
||||
on their file descriptors.
|
||||
"""
|
||||
Process idlequeue. Check for any pending timeout or alarm events. Call
|
||||
IdleObjects on possible and requested read, write and error events on
|
||||
their file descriptors
|
||||
|
||||
Call this in regular intervals.
|
||||
'''
|
||||
"""
|
||||
if not self.queue:
|
||||
# check for timeouts/alert also when there are no active fds
|
||||
self._check_time_events()
|
||||
|
@ -403,24 +430,26 @@ class IdleQueue:
|
|||
|
||||
|
||||
class SelectIdleQueue(IdleQueue):
|
||||
'''
|
||||
"""
|
||||
Extends IdleQueue to use select.select() for polling
|
||||
|
||||
This class exisists for the sake of gtk2.8 on windows, which
|
||||
doesn't seem to support io_add_watch properly (yet)
|
||||
'''
|
||||
This class exisists for the sake of gtk2.8 on windows, which doesn't seem to
|
||||
support io_add_watch properly (yet)
|
||||
"""
|
||||
|
||||
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.write_fds = {}
|
||||
self.error_fds = {}
|
||||
|
||||
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:
|
||||
self.read_fds[fd] = fd
|
||||
if flags & 4:
|
||||
|
@ -428,9 +457,10 @@ class SelectIdleQueue(IdleQueue):
|
|||
self.error_fds[fd] = 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:
|
||||
del(self.read_fds[fd])
|
||||
if fd in self.write_fds:
|
||||
|
@ -466,27 +496,29 @@ class SelectIdleQueue(IdleQueue):
|
|||
|
||||
|
||||
class GlibIdleQueue(IdleQueue):
|
||||
'''
|
||||
Extends IdleQueue to use glib io_add_wath, instead of select/poll
|
||||
In another 'non gui' implementation of Gajim IdleQueue can be used safetly.
|
||||
'''
|
||||
"""
|
||||
Extends IdleQueue to use glib io_add_wath, instead of select/poll In another
|
||||
'non gui' implementation of Gajim IdleQueue can be used safetly
|
||||
"""
|
||||
|
||||
# (timeout, boolean)
|
||||
# Boolean is True if timeout is specified in seconds, False means miliseconds
|
||||
PROCESS_TIMEOUT = (2, True)
|
||||
|
||||
def _init_idle(self):
|
||||
'''
|
||||
"""
|
||||
Creates a dict, which maps file/pipe/sock descriptor to glib event id
|
||||
'''
|
||||
"""
|
||||
self.events = {}
|
||||
# time() is already called in glib, we just get the last value
|
||||
# overrides IdleQueue.current_time()
|
||||
self.current_time = gobject.get_current_time
|
||||
|
||||
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,
|
||||
priority=gobject.PRIORITY_LOW)
|
||||
# store the id of the watch, so that we can remove it on unplug
|
||||
|
@ -501,9 +533,10 @@ class GlibIdleQueue(IdleQueue):
|
|||
raise
|
||||
|
||||
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:
|
||||
return
|
||||
gobject.source_remove(self.events[fd])
|
||||
|
|
|
@ -14,33 +14,34 @@
|
|||
|
||||
# $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
|
||||
log = logging.getLogger('gajim.c.x.plugin')
|
||||
|
||||
class PlugIn:
|
||||
'''
|
||||
"""
|
||||
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
|
||||
required (the object where we plug into)
|
||||
|
||||
For every instance of PlugIn class the 'owner' is the class in what the plug
|
||||
was plugged.
|
||||
'''
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._exported_methods=[]
|
||||
|
||||
def PlugIn(self, owner):
|
||||
'''
|
||||
"""
|
||||
Attach to owner and register ourself and our _exported_methods in it.
|
||||
If defined by a subclass, call self.plugin(owner) to execute hook
|
||||
code after plugging.
|
||||
'''
|
||||
code after plugging
|
||||
"""
|
||||
self._owner=owner
|
||||
log.info('Plugging %s __INTO__ %s' % (self, self._owner))
|
||||
if self.__class__.__name__ in owner.__dict__:
|
||||
|
@ -63,11 +64,11 @@ class PlugIn:
|
|||
return self.plugin(owner)
|
||||
|
||||
def PlugOut(self):
|
||||
'''
|
||||
"""
|
||||
Unregister our _exported_methods from owner and detach from it.
|
||||
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))
|
||||
for method in self._exported_methods:
|
||||
del self._owner.__dict__[method.__name__]
|
||||
|
@ -85,13 +86,13 @@ class PlugIn:
|
|||
|
||||
@classmethod
|
||||
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
|
||||
unit testing easier. For testing, this method can be patched to inject
|
||||
mock objects.
|
||||
'''
|
||||
"""
|
||||
return cls(*args, **kwargs)
|
||||
|
||||
# vim: se ts=3:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue