def __init__(self, host, address, port, *args, **kwargs): self._test_host = host self._test_address = address self._test_port = port self._test_success = False self._test_starttls_required = None super().__init__(*args, **kwargs) self.stream_header = "<stream:stream to='%s' %s %s %s %s>" % ( 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.register_stanza(StreamFeatures) self.register_handler( CoroutineCallback('Stream Features', MatchXPath('{%s}features' % self.stream_ns), self._handle_stream_features)) self.register_plugin('feature_starttls') self.add_event_handler('stream_negotiated', self.handle_stream_negotiated) self.add_event_handler('session_end', self.handle_stream_end) self.add_event_handler('connection_failed', self.handle_connection_failed) self.register_handler( CoroutineCallback('Stream Features for TLS', MatchXPath('{%s}features' % self.stream_ns), self._tls_stream_features))
def _listener(self) -> None: """Enable callback""" def message_received(event): payload = event.get_payload() if len(payload) == 0: _LOGGER.error("%s: Invalid payload length of 0 received.", self._ip_address, len(payload)) return for message in payload: data = {} # Try to convert JSON object if JSON object was received if message.text is not None and message.text != '': try: data = json.loads(message.text) except json.JSONDecodeError: # Should mean only a single value was received. for item in message.text.split(':'): item_split = item.split('=') if len(item_split) == 2: data.update({item_split[0]: item_split[1]}) # Create response dictionary response = { 'id': event.get('id'), 'xmlns': message.attrib.get('xmlns'), 'cmd': message.attrib.get('mime'), 'type': message.attrib.get('type'), 'code': int(message.attrib.get('errorcode', '0')), 'codestring': message.attrib.get('errorstring'), 'data': data, } _LOGGER.debug("%s: Response payload: %s", self._ip_address, response) # Put response on queue. self._response_queue.put_nowait(response) self._listener_message_received = message_received self._listener_message_received = message_received # Register our callback. self.register_handler( Callback('Listener', MatchXPath('{{{0}}}iq/{{{1}}}oa'.format(self.default_ns, DEFAULT_NS)), message_received)) self.register_handler( Callback('Listener', MatchXPath('{{{0}}}message/{{{1}}}event'.format( self.default_ns, DEFAULT_NS)), message_received))
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: enable = stanza.Enable(self.xmpp) enable['resume'] = self.allow_resume enable.send() self.enabled = True self.handled = 0 self.unacked_queue.clear() waiter = Waiter( 'enabled_or_failed', MatchMany([ MatchXPath(stanza.Enabled.tag_name()), MatchXPath(stanza.Failed.tag_name()) ])) self.xmpp.register_handler(waiter) result = yield from waiter.wait() elif self.sm_id and self.allow_resume and 'bind' not in self.xmpp.features: self.enabled = True resume = stanza.Resume(self.xmpp) resume['h'] = self.handled resume['previd'] = self.sm_id resume.send() # 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 = yield from waiter.wait() if result is not None and result.name == 'resumed': return True return False
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 __init__(self, jid, secret, host=None, port=None, plugin_config=None, plugin_whitelist=None, use_jc_ns=False): if not plugin_whitelist: plugin_whitelist = [] if not plugin_config: plugin_config = {} 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.sessionstarted = False self.register_handler( Callback('Handshake', MatchXPath('{jabber:component:accept}handshake'), self._handle_handshake)) self.add_event_handler('presence_probe', self._handle_probe)
def plugin_init(self) -> None: stanza.register_plugins() self.xmpp.register_handler( Callback( "MIX message received", MatchXPath('{%s}message[@type="groupchat"]/{%s}mix' % (self.xmpp.default_ns, self.namespace)), self._handle_mix_message, ))
def plugin_init(self) -> None: stanza.register_plugins() self.xmpp.register_handler( Callback( 'MIX Presence received', MatchXPath('{%s}presence/{%s}mix' % (self.xmpp.default_ns, stanza.NS)), self._handle_mix_presence, ))
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({'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 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)
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( CoroutineCallback('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): register_stanza_plugin(Iq, RPCQuery) register_stanza_plugin(RPCQuery, MethodCall) register_stanza_plugin(RPCQuery, MethodResponse) self.xmpp.register_handler( Callback( 'RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), self._handle_method_call)) self.xmpp.register_handler( Callback( 'RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), self._handle_method_response)) self.xmpp.register_handler( 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 run(self): self.log_debug("def run") if os.name == "nt": asyncio.set_event_loop_policy( asyncio.WindowsSelectorEventLoopPolicy()) loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) xmpp = XMPPClient( self.jid, self.config.get("pw"), self.log_info, self.log_debug, ) self.log_debug("activate xmpp") xmpp.use_ipv6 = self.config.get("use_ipv6") xmpp.register_plugin("xep_0030") # Service Discovery xmpp.register_plugin("xep_0004") # Data Forms xmpp.register_plugin("xep_0060") # PubSub xmpp.register_plugin("xep_0199") # XMPP Ping xmpp.ssl_version = ssl.PROTOCOL_TLSv1_2 # The message event is triggered whenever a message # stanza is received. Be aware that that includes # MUC messages and error messages. xmpp.add_event_handler("message", self.message) xmpp.add_event_handler("connected", self.connected) xmpp.add_event_handler("connection_failed", self.connection_failed) xmpp.add_event_handler("disconnected", self.disconnected) xmpp.add_event_handler("failed_auth", self.failed_auth) xmpp.add_event_handler("changed_status", self.changed_status) xmpp.add_event_handler("presence_error", self.presence_error) xmpp.add_event_handler("presence_unavailable", self.presence_unavailable) xmpp.register_handler( Callback( "Stream Error", MatchXPath(f"{{{xmpp.stream_ns}}}error"), self.stream_error, )) self.xmpp = xmpp self.xmpp.connect( use_ssl=self.config.get("use_ssl"), force_starttls=self.config.get("tls"), ) self.xmpp.process(forever=True)
def __init__(self, *args, **kwargs): super(TestClient, self).__init__(*args, **kwargs) 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.register_stanza(StreamFeatures) self.register_handler( CoroutineCallback('Stream Features', MatchXPath('{%s}features' % self.stream_ns), self._handle_stream_features)) self.register_plugin('feature_starttls') self.add_event_handler('stream_negotiated', self.test)
def __init__(self, jid, password, plugin_config=None, plugin_whitelist=None, escape_quotes=True, sasl_mech=None, lang='en', **kwargs): if not plugin_whitelist: plugin_whitelist = [] if not plugin_config: plugin_config = {} BaseXMPP.__init__(self, jid, 'jabber:client', **kwargs) 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( CoroutineCallback('Stream Features', MatchXPath('{%s}features' % self.stream_ns), self._handle_stream_features)) def roster_push_filter(iq): from_ = iq['from'] if from_ and from_ != JID('') and from_ != self.boundjid.bare: reply = iq.reply() reply['type'] = 'error' reply['error']['type'] = 'cancel' reply['error']['code'] = 503 reply['error']['condition'] = 'service-unavailable' reply.send() return self.event('roster_update', iq) self.register_handler( Callback('Roster Update', StanzaPath('iq@type=set/roster'), roster_push_filter)) # 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 __init__(self, jid='', default_ns='jabber:client', **kwargs): XMLStream.__init__(self, **kwargs) 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) #: 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) 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 = asyncio.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 = True #: 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 = True #: XEP-0359 <origin-id/> tag that gets added to <message/> stanzas. self.use_origin_id = True #: 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:`slixmpp.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( 'IMError', MatchXPath('{%s}message/{%s}error' % (self.default_ns, self.default_ns)), self._handle_message_error)) 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)
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.enabled = False self.unacked_queue = collections.deque() 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)