def plugin_init(self): register_stanza_plugin(Iq, RPCQuery) register_stanza_plugin(RPCQuery, MethodCall) register_stanza_plugin(RPCQuery, MethodResponse) self.xmpp.registerHandler( Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), self._handle_method_call) ) self.xmpp.registerHandler( Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), self._handle_method_response) ) self.xmpp.registerHandler( Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)), self._handle_error) ) self.xmpp.add_event_handler('jabber_rpc_method_call', self._on_jabber_rpc_method_call) self.xmpp.add_event_handler('jabber_rpc_method_response', self._on_jabber_rpc_method_response) self.xmpp.add_event_handler('jabber_rpc_method_fault', self._on_jabber_rpc_method_fault) self.xmpp.add_event_handler('jabber_rpc_error', self._on_jabber_rpc_error) self.xmpp.add_event_handler('error', self._handle_error) #self.activeCalls = [] self.xmpp['xep_0030'].add_feature('jabber:iq:rpc') self.xmpp['xep_0030'].add_identity('automation','rpc')
def __init__(self, jid, password, ssl=False, plugin_config={}, plugin_whitelist=[], escape_quotes=True, sasl_mech=None): BaseXMPP.__init__(self, jid, 'jabber:client') self.set_jid(jid) self.escape_quotes = escape_quotes self.plugin_config = plugin_config self.plugin_whitelist = plugin_whitelist self.default_port = 5222 self.credentials = {} self.password = password self.stream_header = "<stream:stream to='%s' %s %s version='1.0'>" % ( self.boundjid.host, "xmlns:stream='%s'" % self.stream_ns, "xmlns='%s'" % self.default_ns) self.stream_footer = "</stream:stream>" self.features = set() self._stream_feature_handlers = {} self._stream_feature_order = [] #TODO: Use stream state here self.authenticated = False self.sessionstarted = False self.bound = False self.bindfail = False self.add_event_handler('connected', self._handle_connected) self.add_event_handler('session_bind', self._handle_session_bind) self.register_stanza(StreamFeatures) self.register_handler( Callback('Stream Features', MatchXPath('{%s}features' % self.stream_ns), self._handle_stream_features)) self.register_handler( Callback('Roster Update', MatchXPath('{%s}iq/{%s}query' % ( self.default_ns, 'jabber:iq:roster')), self._handle_roster)) # Setup default stream features self.register_plugin('feature_starttls') self.register_plugin('feature_bind') self.register_plugin('feature_session') self.register_plugin('feature_mechanisms', pconfig={'use_mech': sasl_mech} if sasl_mech else None) self.register_plugin('feature_rosterver')
def __init__(self, jid, secret, host=None, port=None, plugin_config={}, plugin_whitelist=[], use_jc_ns=False): if use_jc_ns: default_ns = 'jabber:client' else: default_ns = 'jabber:component:accept' BaseXMPP.__init__(self, jid, default_ns) self.auto_authorize = None self.stream_header = "<stream:stream %s %s to='%s'>" % ( 'xmlns="jabber:component:accept"', 'xmlns:stream="%s"' % self.stream_ns, jid) self.stream_footer = "</stream:stream>" self.server_host = host self.server_port = port self.secret = secret self.plugin_config = plugin_config self.plugin_whitelist = plugin_whitelist self.is_component = True self.register_handler( Callback('Handshake', MatchXPath('{jabber:component:accept}handshake'), self._handle_handshake)) self.add_event_handler('presence_probe', self._handle_probe)
def testIqErrorException(self): """Test using error exceptions with Iq stanzas.""" def handle_iq(iq): raise XMPPError(condition='feature-not-implemented', text="We don't do things that way here.", etype='cancel', clear=False) self.stream_start() self.xmpp.register_handler( Callback('Test Iq', MatchXPath('{%s}iq/{test}query' % self.xmpp.default_ns), handle_iq)) self.recv(""" <iq type="get" id="0"> <query xmlns="test" /> </iq> """) self.send(""" <iq type="error" id="0"> <query xmlns="test" /> <error type="cancel" code="501"> <feature-not-implemented xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /> <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"> We don't do things that way here. </text> </error> </iq> """, use_values=False)
def start(self): """ Démarre le service """ xmppDomain = self.configService.value("XMPP_DOMAIN_NAME") xmppUser = self.configService.value("XMPP_USERNAME") self.xmpp = ClientXMPP(xmppUser, self.configService.value("XMPP_PASSWORD")) # ajout des listeners et plugins self.xmpp.add_event_handler("session_start", self.session_start) self.xmpp.register_plugin('XmppMessagePlugin', module=xmpp) self.xmpp.register_handler( Callback( 'SEN1 Message', MatchXPath('{%s}message/{http://xmpp.rocks}Sen1Message' % self.xmpp.default_ns), self.receiveMessage)) register_stanza_plugin(Message, XmppMessageStanza) if (not self.xmpp.connect(address=(xmppDomain, 5222))): raise Exception("Cannot bind XMPP session to {}".format(xmppUser)) self.logger.info( "Start XMPP protocol : bind session {}...".format(xmppUser)) self.xmpp.process()
def __init__(self, jid, password, plugin_config={}, plugin_whitelist=[], escape_quotes=True, sasl_mech=None, lang='en'): BaseXMPP.__init__(self, jid, 'jabber:client') self.escape_quotes = escape_quotes self.plugin_config = plugin_config self.plugin_whitelist = plugin_whitelist self.default_port = 5222 self.default_lang = lang self.credentials = {} self.password = password self.stream_header = "<stream:stream to='%s' %s %s %s %s>" % ( self.boundjid.host, "xmlns:stream='%s'" % self.stream_ns, "xmlns='%s'" % self.default_ns, "xml:lang='%s'" % self.default_lang, "version='1.0'") self.stream_footer = "</stream:stream>" self.features = set() self._stream_feature_handlers = {} self._stream_feature_order = [] self.dns_service = 'xmpp-client' #TODO: Use stream state here self.authenticated = False self.sessionstarted = False self.bound = False self.bindfail = False self.add_event_handler('connected', self._reset_connection_state) self.add_event_handler('session_bind', self._handle_session_bind) self.add_event_handler('roster_update', self._handle_roster) self.register_stanza(StreamFeatures) self.register_handler( Callback('Stream Features', MatchXPath('{%s}features' % self.stream_ns), self._handle_stream_features)) self.register_handler( Callback('Roster Update', StanzaPath('iq@type=set/roster'), lambda iq: self.event('roster_update', iq))) # Setup default stream features self.register_plugin('feature_starttls') self.register_plugin('feature_bind') self.register_plugin('feature_session') self.register_plugin('feature_rosterver') self.register_plugin('feature_preapproval') self.register_plugin('feature_mechanisms') if sasl_mech: self['feature_mechanisms'].use_mech = sasl_mech
def plugin_init(self): if self.sasl_callback is None: self.sasl_callback = self._default_credentials if self.security_callback is None: self.security_callback = self._default_security creds = self.sasl_callback(set(['username']), set()) if not self.use_mech and not creds['username']: self.use_mech = 'ANONYMOUS' self.mech = None self.mech_list = set() self.attempted_mechs = set() register_stanza_plugin(StreamFeatures, stanza.Mechanisms) self.xmpp.register_stanza(stanza.Success) self.xmpp.register_stanza(stanza.Failure) self.xmpp.register_stanza(stanza.Auth) self.xmpp.register_stanza(stanza.Challenge) self.xmpp.register_stanza(stanza.Response) self.xmpp.register_stanza(stanza.Abort) self.xmpp.register_handler( Callback('SASL Success', MatchXPath(stanza.Success.tag_name()), self._handle_success, instream=True)) self.xmpp.register_handler( Callback('SASL Failure', MatchXPath(stanza.Failure.tag_name()), self._handle_fail, instream=True)) self.xmpp.register_handler( Callback('SASL Challenge', MatchXPath(stanza.Challenge.tag_name()), self._handle_challenge)) self.xmpp.register_feature('mechanisms', self._handle_sasl_auth, restart=True, order=self.order)
def _handle_sm_feature(self, features): """ Enable or resume stream management. If no SM-ID is stored, and resource binding has taken place, stream management will be enabled. If an SM-ID is known, and the server allows resumption, the previous stream will be resumed. """ if 'stream_management' in self.xmpp.features: # We've already negotiated stream management, # so no need to do it again. return False if not self.sm_id: if 'bind' in self.xmpp.features: self.enabled.set() enable = stanza.Enable(self.xmpp) enable['resume'] = self.allow_resume enable.send(now=True) self.handled = 0 elif self.sm_id and self.allow_resume: self.enabled.set() resume = stanza.Resume(self.xmpp) resume['h'] = self.handled resume['previd'] = self.sm_id resume.send(now=True) # Wait for a response before allowing stream feature processing # to continue. The actual result processing will be done in the # _handle_resumed() or _handle_failed() methods. waiter = Waiter( 'resumed_or_failed', MatchMany([ MatchXPath(stanza.Resumed.tag_name()), MatchXPath(stanza.Failed.tag_name()) ])) self.xmpp.register_handler(waiter) result = waiter.wait() if result is not None and result.name == 'resumed': return True return False
def __init__(self, server, callback, lang='en', ns='jabber:client', get_ca=False): super(StreamFeatureClient, self).__init__(server.domain, default_ns=ns) self._listed_server = server self.use_ipv6 = settings.USE_IP6 self.auto_reconnect = False self.callback = callback self.ca_certs = '/etc/ssl/certs/ca-certificates.crt' # copied from ClientXMPP self.default_lang = lang self.stream_header = "<stream:stream to='%s' %s %s %s %s>" % ( self.boundjid.host, "xmlns:stream='%s'" % self.stream_ns, "xmlns='%s'" % self.default_ns, "xml:lang='%s'" % self.default_lang, "version='1.0'") self.stream_footer = "</stream:stream>" self.features = set() self._stream_feature_handlers = {} self._stream_feature_order = [] # register known features: self.register_plugin('feature_amp', module=amp) self.register_plugin('feature_auth', module=auth) self.register_plugin('feature_bind', module=bind) self.register_plugin('feature_caps', module=caps) self.register_plugin('feature_compression', module=compression) self.register_plugin('feature_mechanisms', pconfig={'sasl_callback': self.sasl_callback}) self.register_plugin('feature_register', module=register) self.register_plugin('feature_session', module=session) self.register_plugin('feature_sm', module=sm) self.register_plugin('feature_starttls') self.register_plugin('feature_rosterver', module=rosterver) self.register_plugin('feature_dialback', module=dialback) self.register_stanza(StreamFeatures) self.register_handler( Callback('Stream Features', MatchXPath('{%s}features' % self.stream_ns), self.get_features)) self.add_event_handler('ssl_invalid_chain', self._invalid_chain) self.add_event_handler('ssl_invalid_cert', self._invalid_cert) self.add_event_handler('socket_error', self._socket_error) if get_ca: self.add_event_handler('ssl_cert', self._handle_cert) # do not reparse features: self._features = None
def plugin_init(self): register_stanza_plugin(Iq, stanza.GmailQuery) register_stanza_plugin(Iq, stanza.MailBox) register_stanza_plugin(Iq, stanza.NewMail) self.xmpp.register_handler( Callback( 'Gmail New Mail', MatchXPath('{%s}iq/{%s}%s' % (self.xmpp.default_ns, stanza.NewMail.namespace, stanza.NewMail.name)), self._handle_new_mail)) self._last_result_time = None self._last_result_tid = None
def plugin_init(self): self.xmpp.register_handler( Callback('STARTTLS Proceed', MatchXPath(stanza.Proceed.tag_name()), self._handle_starttls_proceed, instream=True)) self.xmpp.register_feature('starttls', self._handle_starttls, restart=True, order=self.config.get('order', 0)) self.xmpp.register_stanza(stanza.Proceed) self.xmpp.register_stanza(stanza.Failure) register_stanza_plugin(StreamFeatures, stanza.STARTTLS)
def plugin_init(self): self.xep = '0004' self.description = 'Data Forms' self.xmpp.register_handler( Callback( 'Data Form', MatchXPath('{%s}message/{%s}x' % (self.xmpp.default_ns, Form.namespace)), self.handle_form)) register_stanza_plugin(FormField, FieldOption) register_stanza_plugin(Form, FormField) register_stanza_plugin(Message, Form)
def __init__(self, jid, password): sleekxmpp.ClientXMPP.__init__(self, jid, password) # The session_start event will be triggered when # the bot establishes its connection with the server # and the XML streams are ready for use. We want to # listen for this event so that we we can initialize # our roster. self.register_handler( Callback( 'GcmMessage', MatchXPath('{%s}message/{%s}gcm' % (self.default_ns, 'google:mobile:data')), self.message_callback)) self.add_event_handler("session_start", self.start)
def plugin_init(self): register_stanza_plugin(RPCQuery, stanza.MethodTimeout) self.xmpp.register_handler( Callback( "RPC Call", MatchXPath( "{%s}iq/{%s}query/{%s}methodTimeout" % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace) ), self._handle_method_timeout, ) ) self.xmpp.add_event_handler("jabber_rpc_method_timeout", self._on_jabber_rpc_method_timeout, threaded=True)
def changed_status(self, pres): # Here we keep track of the status changes. # If it's a MUC presence, we're going to ignore it. MUC presence stanzas are handled elswhere. if MatchXPath("{%s}presence/{%s}x" % (self.xmpp.default_ns, 'http://jabber.org/protocol/muc#user')).match(pres): return; if pres['from'].user == self.xmpp.boundjid.user: return; if pres['type'] == 'available': status = "Online"; elif pres['type'] == 'xa' or pres['type'] == 'away' or pres['type'] == 'dnd': status = "Away"; else: #elif pres['type'] == 'unavailable' or pres['type'] == 'error' or pres['type'] == 'probe': status = "Offline"; if "savage" in self.xmpp.client_roster.presence( pres['from'].bare): status = "Ingame"; self.chatEvent("chat_contact_update", pres['from'].user, status);
def __init__(self, test, jid, lang='en'): super(StreamFeatureServer, self).__init__(jid, default_ns='jabber:server') self.test = test self.use_ipv6 = settings.USE_IP6 self.auto_reconnect = False self.test = test self._stream_features = {} # adapted from ClientXMPP self.default_port = 5269 self.default_lang = lang self.stream_header = "<stream:stream to='%s' %s %s %s %s>" % ( self.boundjid.host, "xmlns:stream='%s'" % self.stream_ns, "xmlns='%s'" % self.default_ns, "xml:lang='%s'" % self.default_lang, "version='1.0'") self.stream_footer = "</stream:stream>" self.features = set() self._stream_feature_handlers = {} self._stream_feature_order = [] self.dns_service = 'xmpp-server' self.register_stanza(StreamFeatures) self.register_handler( Callback('Stream Features', MatchXPath('{%s}features' % self.stream_ns), self._handle_stream_features)) self.register_plugin('feature_starttls') self.register_plugin('feature_dialback', module=dialback) self.register_plugin('feature_sm', module=sm) self.add_event_handler('stream_negotiated', self._stream_negotiated)
def plugin_init(self): self.use_mech = self.config.get('use_mech', None) if not self.use_mech and not self.xmpp.boundjid.user: self.use_mech = 'ANONYMOUS' def tls_active(): return 'starttls' in self.xmpp.features def basic_callback(mech, values): creds = self.xmpp.credentials for value in values: if value == 'username': values['username'] = self.xmpp.boundjid.user elif value == 'password': values['password'] = creds['password'] elif value == 'email': jid = self.xmpp.boundjid.bare values['email'] = creds.get('email', jid) elif value in creds: values[value] = creds[value] mech.fulfill(values) sasl_callback = self.config.get('sasl_callback', None) if sasl_callback is None: sasl_callback = basic_callback self.mech = None self.sasl = suelta.SASL(self.xmpp.boundjid.domain, 'xmpp', username=self.xmpp.boundjid.user, sec_query=suelta.sec_query_allow, request_values=sasl_callback, tls_active=tls_active, mech=self.use_mech) self.mech_list = set() self.attempted_mechs = set() register_stanza_plugin(StreamFeatures, stanza.Mechanisms) self.xmpp.register_stanza(stanza.Success) self.xmpp.register_stanza(stanza.Failure) self.xmpp.register_stanza(stanza.Auth) self.xmpp.register_stanza(stanza.Challenge) self.xmpp.register_stanza(stanza.Response) self.xmpp.register_stanza(stanza.Abort) self.xmpp.register_handler( Callback('SASL Success', MatchXPath(stanza.Success.tag_name()), self._handle_success, instream=True)) self.xmpp.register_handler( Callback('SASL Failure', MatchXPath(stanza.Failure.tag_name()), self._handle_fail, instream=True)) self.xmpp.register_handler( Callback('SASL Challenge', MatchXPath(stanza.Challenge.tag_name()), self._handle_challenge)) self.xmpp.register_feature('mechanisms', self._handle_sasl_auth, restart=True, order=self.config.get('order', 100))
def __init__(self, jid='', default_ns='jabber:client'): XMLStream.__init__(self) self.default_ns = default_ns self.stream_ns = 'http://etherx.jabber.org/streams' self.namespace_map[self.stream_ns] = 'stream' #: An identifier for the stream as given by the server. self.stream_id = None #: The JabberID (JID) requested for this connection. self.requested_jid = JID(jid, cache_lock=True) #: The JabberID (JID) used by this connection, #: as set after session binding. This may even be a #: different bare JID than what was requested. self.boundjid = JID(jid, cache_lock=True) self._expected_server_name = self.boundjid.host self._redirect_attempts = 0 #: The maximum number of consecutive see-other-host #: redirections that will be followed before quitting. self.max_redirects = 5 self.session_bind_event = threading.Event() #: A dictionary mapping plugin names to plugins. self.plugin = PluginManager(self) #: Configuration options for whitelisted plugins. #: If a plugin is registered without any configuration, #: and there is an entry here, it will be used. self.plugin_config = {} #: A list of plugins that will be loaded if #: :meth:`register_plugins` is called. self.plugin_whitelist = [] #: The main roster object. This roster supports multiple #: owner JIDs, as in the case for components. For clients #: which only have a single JID, see :attr:`client_roster`. self.roster = roster.Roster(self) self.roster.add(self.boundjid) #: The single roster for the bound JID. This is the #: equivalent of:: #: #: self.roster[self.boundjid.bare] self.client_roster = self.roster[self.boundjid] #: The distinction between clients and components can be #: important, primarily for choosing how to handle the #: ``'to'`` and ``'from'`` JIDs of stanzas. self.is_component = False #: Messages may optionally be tagged with ID values. Setting #: :attr:`use_message_ids` to `True` will assign all outgoing #: messages an ID. Some plugin features require enabling #: this option. self.use_message_ids = False #: Presence updates may optionally be tagged with ID values. #: Setting :attr:`use_message_ids` to `True` will assign all #: outgoing messages an ID. self.use_presence_ids = False #: The API registry is a way to process callbacks based on #: JID+node combinations. Each callback in the registry is #: marked with: #: #: - An API name, e.g. xep_0030 #: - The name of an action, e.g. get_info #: - The JID that will be affected #: - The node that will be affected #: #: API handlers with no JID or node will act as global handlers, #: while those with a JID and no node will service all nodes #: for a JID, and handlers with both a JID and node will be #: used only for that specific combination. The handler that #: provides the most specificity will be used. self.api = APIRegistry(self) #: Flag indicating that the initial presence broadcast has #: been sent. Until this happens, some servers may not #: behave as expected when sending stanzas. self.sentpresence = False #: A reference to :mod:`sleekxmpp.stanza` to make accessing #: stanza classes easier. self.stanza = stanza self.register_handler( Callback('IM', MatchXPath('{%s}message/{%s}body' % (self.default_ns, self.default_ns)), self._handle_message)) self.register_handler( Callback('Presence', MatchXPath("{%s}presence" % self.default_ns), self._handle_presence)) self.register_handler( Callback('Stream Error', MatchXPath("{%s}error" % self.stream_ns), self._handle_stream_error)) self.add_event_handler('session_start', self._handle_session_start) self.add_event_handler('disconnected', self._handle_disconnected) self.add_event_handler('presence_available', self._handle_available) self.add_event_handler('presence_dnd', self._handle_available) self.add_event_handler('presence_xa', self._handle_available) self.add_event_handler('presence_chat', self._handle_available) self.add_event_handler('presence_away', self._handle_available) self.add_event_handler('presence_unavailable', self._handle_unavailable) self.add_event_handler('presence_subscribe', self._handle_subscribe) self.add_event_handler('presence_subscribed', self._handle_subscribed) self.add_event_handler('presence_unsubscribe', self._handle_unsubscribe) self.add_event_handler('presence_unsubscribed', self._handle_unsubscribed) self.add_event_handler('roster_subscription_request', self._handle_new_subscription) # Set up the XML stream with XMPP's root stanzas. self.register_stanza(Message) self.register_stanza(Iq) self.register_stanza(Presence) self.register_stanza(StreamError) # Initialize a few default stanza plugins. register_stanza_plugin(Iq, Roster) register_stanza_plugin(Message, Nick)
def __init__(self, jid='', default_ns='jabber:client'): XMLStream.__init__(self) self.default_ns = default_ns self.stream_ns = 'http://etherx.jabber.org/streams' self.namespace_map[self.stream_ns] = 'stream' #: An identifier for the stream as given by the server. self.stream_id = None #: The JabberID (JID) used by this connection. self.boundjid = JID(jid) #: A dictionary mapping plugin names to plugins. self.plugin = PluginManager(self) #: Configuration options for whitelisted plugins. #: If a plugin is registered without any configuration, #: and there is an entry here, it will be used. self.plugin_config = {} #: A list of plugins that will be loaded if #: :meth:`register_plugins` is called. self.plugin_whitelist = [] #: The main roster object. This roster supports multiple #: owner JIDs, as in the case for components. For clients #: which only have a single JID, see :attr:`client_roster`. self.roster = roster.Roster(self) self.roster.add(self.boundjid.bare) #: The single roster for the bound JID. This is the #: equivalent of:: #: #: self.roster[self.boundjid.bare] self.client_roster = self.roster[self.boundjid.bare] #: The distinction between clients and components can be #: important, primarily for choosing how to handle the #: ``'to'`` and ``'from'`` JIDs of stanzas. self.is_component = False #: Flag indicating that the initial presence broadcast has #: been sent. Until this happens, some servers may not #: behave as expected when sending stanzas. self.sentpresence = False #: A reference to :mod:`sleekxmpp.stanza` to make accessing #: stanza classes easier. self.stanza = sleekxmpp.stanza self.register_handler( Callback( 'IM', MatchXPath('{%s}message/{%s}body' % (self.default_ns, self.default_ns)), self._handle_message)) self.register_handler( Callback('Presence', MatchXPath("{%s}presence" % self.default_ns), self._handle_presence)) self.register_handler( Callback('Stream Error', MatchXPath("{%s}error" % self.stream_ns), self._handle_stream_error)) self.add_event_handler('disconnected', self._handle_disconnected) self.add_event_handler('presence_available', self._handle_available) self.add_event_handler('presence_dnd', self._handle_available) self.add_event_handler('presence_xa', self._handle_available) self.add_event_handler('presence_chat', self._handle_available) self.add_event_handler('presence_away', self._handle_available) self.add_event_handler('presence_unavailable', self._handle_unavailable) self.add_event_handler('presence_subscribe', self._handle_subscribe) self.add_event_handler('presence_subscribed', self._handle_subscribed) self.add_event_handler('presence_unsubscribe', self._handle_unsubscribe) self.add_event_handler('presence_unsubscribed', self._handle_unsubscribed) self.add_event_handler('roster_subscription_request', self._handle_new_subscription) # Set up the XML stream with XMPP's root stanzas. self.register_stanza(Message) self.register_stanza(Iq) self.register_stanza(Presence) self.register_stanza(StreamError) # Initialize a few default stanza plugins. register_stanza_plugin(Iq, Roster) register_stanza_plugin(Message, Nick) register_stanza_plugin(Message, HTMLIM)
def plugin_init(self): """Start the XEP-0198 plugin.""" # Only enable stream management for non-components, # since components do not yet perform feature negotiation. if self.xmpp.is_component: return self.window_counter = self.window self.window_counter_lock = threading.Lock() self.enabled = threading.Event() self.unacked_queue = collections.deque() self.seq_lock = threading.Lock() self.handled_lock = threading.Lock() self.ack_lock = threading.Lock() register_stanza_plugin(StreamFeatures, stanza.StreamManagement) self.xmpp.register_stanza(stanza.Enable) self.xmpp.register_stanza(stanza.Enabled) self.xmpp.register_stanza(stanza.Resume) self.xmpp.register_stanza(stanza.Resumed) self.xmpp.register_stanza(stanza.Ack) self.xmpp.register_stanza(stanza.RequestAck) # Only end the session when a </stream> element is sent, # not just because the connection has died. self.xmpp.end_session_on_disconnect = False # Register the feature twice because it may be ordered two # different ways: enabling after binding and resumption # before binding. self.xmpp.register_feature('sm', self._handle_sm_feature, restart=True, order=self.order) self.xmpp.register_feature('sm', self._handle_sm_feature, restart=True, order=self.resume_order) self.xmpp.register_handler( Callback('Stream Management Enabled', MatchXPath(stanza.Enabled.tag_name()), self._handle_enabled, instream=True)) self.xmpp.register_handler( Callback('Stream Management Resumed', MatchXPath(stanza.Resumed.tag_name()), self._handle_resumed, instream=True)) self.xmpp.register_handler( Callback('Stream Management Failed', MatchXPath(stanza.Failed.tag_name()), self._handle_failed, instream=True)) self.xmpp.register_handler( Callback('Stream Management Ack', MatchXPath(stanza.Ack.tag_name()), self._handle_ack, instream=True)) self.xmpp.register_handler( Callback('Stream Management Request Ack', MatchXPath(stanza.RequestAck.tag_name()), self._handle_request_ack, instream=True)) self.xmpp.add_filter('in', self._handle_incoming) self.xmpp.add_filter('out_sync', self._handle_outgoing) self.xmpp.add_event_handler('session_end', self.session_end)
def plugin_init(self): """Start the XEP-0198 plugin.""" # Only enable stream management for non-components, # since components do not yet perform feature negotiation. if self.xmpp.is_component: return #: The stream management ID for the stream. Knowing this value is #: required in order to do stream resumption. self.sm_id = self.config.get('sm_id', None) #: A counter of handled incoming stanzas, mod 2^32. self.handled = self.config.get('handled', 0) #: A counter of unacked outgoing stanzas, mod 2^32. self.seq = self.config.get('seq', 0) #: The last ack number received from the server. self.last_ack = self.config.get('last_ack', 0) #: The number of stanzas to wait between sending ack requests to #: the server. Setting this to ``1`` will send an ack request after #: every sent stanza. Defaults to ``5``. self.window = self.config.get('window', 5) self.window_counter = self.window self.window_counter_lock = threading.Lock() #: Control whether or not the ability to resume the stream will be #: requested when enabling stream management. Defaults to ``True``. self.allow_resume = self.config.get('allow_resume', True) self.enabled = threading.Event() self.unacked_queue = collections.deque() self.seq_lock = threading.Lock() self.handled_lock = threading.Lock() self.ack_lock = threading.Lock() register_stanza_plugin(StreamFeatures, stanza.StreamManagement) self.xmpp.register_stanza(stanza.Enable) self.xmpp.register_stanza(stanza.Enabled) self.xmpp.register_stanza(stanza.Resume) self.xmpp.register_stanza(stanza.Resumed) self.xmpp.register_stanza(stanza.Ack) self.xmpp.register_stanza(stanza.RequestAck) # Only end the session when a </stream> element is sent, # not just because the connection has died. self.xmpp.end_session_on_disconnect = False # Register the feature twice because it may be ordered two # different ways: enabling after binding and resumption # before binding. self.xmpp.register_feature('sm', self._handle_sm_feature, restart=True, order=self.config.get('order', 10100)) self.xmpp.register_feature('sm', self._handle_sm_feature, restart=True, order=self.config.get('resume_order', 9000)) self.xmpp.register_handler( Callback('Stream Management Enabled', MatchXPath(stanza.Enabled.tag_name()), self._handle_enabled, instream=True)) self.xmpp.register_handler( Callback('Stream Management Resumed', MatchXPath(stanza.Resumed.tag_name()), self._handle_resumed, instream=True)) self.xmpp.register_handler( Callback('Stream Management Failed', MatchXPath(stanza.Failed.tag_name()), self._handle_failed, instream=True)) self.xmpp.register_handler( Callback('Stream Management Ack', MatchXPath(stanza.Ack.tag_name()), self._handle_ack, instream=True)) self.xmpp.register_handler( Callback('Stream Management Request Ack', MatchXPath(stanza.RequestAck.tag_name()), self._handle_request_ack, instream=True)) self.xmpp.add_filter('in', self._handle_incoming) self.xmpp.add_filter('out_sync', self._handle_outgoing) self.xmpp.add_event_handler('session_end', self.session_end)