def _getConnection(self): if self.host: return reactor.connectTCP(self.host, self.port, self.factory) else: c = SRVConnector(reactor, 'xmpp-client', self.domain, self.factory) c.connect() return c
def start(self): myJid = jid.JID(self.username) factory = client.XMPPClientFactory(myJid, self.password) factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.authd) connector = SRVConnector(reactor, 'xmpp-client', self.jabberserver, factory) reactor.callLater(5, self.stop) connector.connect()
def connectSRV(self, service, domain, *args, **kwargs): SRVConnector = kwargs.pop('ConnectorClass', None) if SRVConnector is None: from twisted.names.srvconnect import SRVConnector gtransport, factory = self._make_transport_and_factory() c = SRVConnector(self.reactor, service, domain, factory, *args, **kwargs) c.connect() gtransport._init_transport() return gtransport
def connect(self): if callable(self.override): self.override(self.factory) elif not self._isQueryNeeded(): self.factory.doStart() self.factory.startedConnecting(self) self._reallyConnect() else: SRVConnector.connect(self)
def connectSRV(self, service, domain, *args, **kwargs): SRVConnector = kwargs.pop('ConnectorClass', None) if SRVConnector is None: from twisted.names.srvconnect import SRVConnector gtransport, factory = self._make_transport_and_factory() c = SRVConnector(self.reactor, service, domain, factory, *args, **kwargs) c.connect() gtransport._init_transport() return gtransport
def __init__(self, client_jid, secret): f = client.XMPPClientFactory(client_jid, secret) f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.connected) f.addBootstrap(xmlstream.STREAM_END_EVENT, self.disconnected) f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.authenticated) f.addBootstrap(xmlstream.INIT_FAILED_EVENT, self.init_failed) connector = SRVConnector(reactor, 'xmpp-client', client_jid.host, f, defaultPort=5222) connector.connect()
def __init__(self, reactor, jid, secret): self.reactor = reactor f = client.XMPPClientFactory(jid, secret) f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.connected) f.addBootstrap(xmlstream.STREAM_END_EVENT, self.disconnected) f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.authenticated) f.addBootstrap(xmlstream.INIT_FAILED_EVENT, self.init_failed) connector = SRVConnector(reactor, "xmpp-client", jid.host, f, defaultPort=5222) connector.connect() self.finished = Deferred()
def __init__(self, reactor, jid, secret): self.reactor = reactor f = client.XMPPClientFactory(jid, secret) f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.connected) f.addBootstrap(xmlstream.STREAM_END_EVENT, self.disconnected) f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.authenticated) f.addBootstrap(xmlstream.INIT_FAILED_EVENT, self.init_failed) connector = SRVConnector(reactor, "xmpp-client", jid.host, f, defaultPort=5222) connector.connect() self.finished = Deferred()
def __init__(self, service): jid = JID('127.0.0.1') f = client.XMPPClientFactory(jid, '') f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.connected) f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.authenticated) connector = SRVConnector( reactor, 'xmpp-client', jid.host, f, defaultPort=6523) connector.connect() self.finished = Deferred() self.files = {} self.service = service
def __init__(self, client_jid, secret): f = client.XMPPClientFactory(client_jid, secret) f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.connected) f.addBootstrap(xmlstream.STREAM_END_EVENT, self.disconnected) f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.authenticated) f.addBootstrap(xmlstream.INIT_FAILED_EVENT, self.init_failed) connector = SRVConnector(reactor, 'xmpp-client', client_jid.host, f, defaultPort=5222) connector.connect()
def connect(self, protocolFactory): def _canceller(deferred): connector.stopConnecting() deferred.errback( error.ConnectingCancelledError(connector.getDestination())) try: wf = _WrappingFactory(protocolFactory, _canceller) connector = SRVConnector(self._reactor, self._service, self._domain, wf, protocol=self._protocol) connector.connect() return wf._onConnection except: return defer.fail()
def __init__(self, service): jid = JID('127.0.0.1') f = client.XMPPClientFactory(jid, '') f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.connected) f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.authenticated) connector = SRVConnector(reactor, 'xmpp-client', jid.host, f, defaultPort=6523) connector.connect() self.finished = Deferred() self.files = {} self.service = service
def connect(self, server_address, service=None, protocol='tcp'): """ Connect to the given server_address. Without the 'service' keyword, the server_address can be formatted as HOST[:PORT] (if no port given, 8800 will be assumed). If 'service' is used, it must be the name of a service to look up using a DNS SRV record at the server_address (in this case, no port is expected in the server_address). The 'protocol' is also sent used in the DNS SRV lookup. The 'protocol' keyword is ignored if 'service' is not used. Examples: c = Client() # connect to example.com at port 8800 c.connect('example.com') # connect to example.com at port 45 c.connect('example.com:45') # look up the host and port using SRV, passing 'SIP' as the ## service name to the DNS SRV host at example.com c.connect('example.com', service='SIP') TODO: Twisted uses it's own lookup cache that appears to be cleared when the process terminates. I am unsure whether that cache respects SRV TTL; if not, long-living reconnecting clients *might* not get a new lookup. Further testing is needed to determine this. """ self.ip = server_address if service: connector = SRVConnector(reactor, service, server_address, self.factory, protocol=protocol) connector.connect() else: self.host, self.port = utils.parse_host_port(server_address, 8800) try: reactor.connectTCP(self.host, self.port, self.factory) except error.ConnectionRefusedError, e: logger.error(e) # wraps the error in a slightly more generic ClientError ## and reraises raise ClientError(str(e))
def connectSSL(self, server_address, cert_path, cert_chain_path=None, service=None, protocol='ssl'): """ Connect to the given server_address. See the docstring for Client.connect() for more information. """ self.ip = server_address # verify that the given key/cert files actually exist if not os.path.exists(cert_path): raise ClientError('Cert file %r does not exist!' % cert_path) if cert_chain_path and not os.path.exists(cert_chain_path): raise ClientError('Cert chain file %r does not exist!' % \ cert_chain_path) class CtxFactory(ssl.ClientContextFactory): def getContext(self): self.method = SSL.SSLv23_METHOD ctx = ssl.ClientContextFactory.getContext(self) if cert_chain_path: ctx.use_certificate_chain_file(cert_chain_path) ctx.use_certificate_file(cert_path) return ctx if service: connector = SRVConnector(reactor, service, server_address, self.factory, protocol=protocol, connectFuncName='connectSSL', connectFuncArgs=(CtxFactory(),)) connector.connect() else: self.host, self.port = utils.parse_host_port(server_address, 2220) try: reactor.connectSSL(self.host, self.port, self.factory, CtxFactory()) except error.ConnectionRefusedError, e: logger.error(e) # wraps the error in a slightly more generic ClientError ## and reraises raise ClientError(str(e))
class XMPPClient: ''' The XMPPClients uses the username, server and password to connect to the xmpp server. A message can be send using the sendMessage function, received presences and messages can be processed by a callback function. If the connection fails or is lost, the client will try to reconnect automatically. The disconnectedCallback can be used to catch the connection failed or connection lost event. At startup, a watchdog is started: if the server can't authenticate the user within the timeOut, the connection will be closed and the disconnectedCallback will be called. ''' def __init__(self, username, server, password, hostname, timeOut=5): self.username = username self.server = server self.password = password self.timeOut = timeOut self.hostname = hostname self.xmpp_user = None self.status = 'NOT_CONNECTED' self.messageReceivedCallback = None self.presenceReceivedCallback = None self.connectedCallback = None self.disconnectedCallback = None self.connector = None self.xmlstream = None def start(self): ''' Start the xmpp client, opens the connection to the server ''' if self.status <> 'NOT_CONNECTED': raise RuntimeError('The XmppClient has already been started.') q.logger.log("[XMPPCLIENT] Starting the xmpp client to " + self.username + "@" + self.server, 5) self.startup_watchdog = reactor.callLater(self.timeOut, self._watchdog_timeout) self._connect() def stop(self): ''' Stop the xmpp client ''' if self.status == 'NOT_CONNECTED': raise RuntimeError('The XmppClient has not yet been started.') q.logger.log("[XMPPCLIENT] Stopping the xmpp client to " + self.username + "@" + self.server, 5) self.connector.disconnect() def sendMessage(self, to, type, id, message=' '): ''' Send a message @param to: The username of the client to send the message to @type to: string @param type: The type of the message @type type: string @param id: The id of the message @type id: string @param message: The message to send @type message: string ''' if self.status <> 'RUNNING': raise NotConnectedException() q.logger.log("[XMPPCLIENT] Sending message '" + str(id) + "' of type '" + str(type) +"' to " + str(to) + " for " + self.username + "@" + self.server, 5) elemToSend = domish.Element(('jabber:client','message'), attribs={'to':to+"@"+self.server, 'type':type, 'id':id}) body = domish.Element((None, 'body')) body.addContent(message) elemToSend.addContent(body) self.xmlstream.send(elemToSend) def sendPresence(self, to=None, type=None): ''' Send a presence @param to: The username of the client to send the presence to. None=send to all your friends @type to: string @param type: The type of the presence. Possible values: None=available, unavailable, subscribe, subscribed @type type: string ''' if self.status <> 'RUNNING': raise NotConnectedException() q.logger.log("[XMPPCLIENT] Sending presence of type '" + str(type) +"' to " + str(to) + "'", 5) attribs={} if to <> None: attribs['to'] = to+"@"+self.server if type <> None: attribs['type'] = type presence = domish.Element(('jabber:client','presence'), attribs=attribs) self.xmlstream.send(presence) def _presence_received(self, elem): fromm = elem.getAttribute('from').split("@")[0] if not elem.hasAttribute('type'): type = 'available' else: type = elem.getAttribute('type') q.logger.log("[XMPPCLIENT] Presence received from '" + fromm + "' of type '" + type +"'", 5) if self.presenceReceivedCallback: self.presenceReceivedCallback(fromm, type) def setMessageReceivedCallback(self, callback): ''' @param callback: function to call when a message is received @type callback: function that expects 4 params: from, type, id and message ''' self.messageReceivedCallback = callback def setPresenceReceivedCallback(self, callback): ''' @param callback: function to call when a presence is received @type callback: function that expects 2 params: from and type ''' self.presenceReceivedCallback = callback def setDisconnectedCallback(self, callback): ''' Set the function to call when the client is disconnected from the xmpp server, if the keepAlive param is True in the constructor, the reconnect will be initiated after this callback. @param callback: function to call when the client is disconnected @type callback: function that expects 1 param: string containing the reason of the disconnect ''' self.disconnectedCallback = callback def setConnectedCallback(self, callback): ''' Set the function to call when the client is connected and authenticated with the xmpp server. @param callback: function to call when the client is connected and authenticated @type callback: function that expects no params ''' self.connectedCallback = callback def _connect(self): self.status = 'CONNECTING' if self.hostname != None: self.xmpp_user = self.username+"@"+self.hostname else: self.xmpp_user = self.username+"@"+self.server q.logger.log("[XMPPCLIENT] Connecting to server %s with xmpp user %s'" % (self.server, self.xmpp_user) ) c = client.XMPPClientFactory(jid.JID(self.xmpp_user), self.password) c.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self._connected) c.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self._authenticated) c.addBootstrap(xmlstream.INIT_FAILED_EVENT, self._init_failed) c.addBootstrap(xmlstream.STREAM_END_EVENT, self._end_stream) def _do_connect(): self.connector = SRVConnector(reactor,'xmpp-client' ,self.server, c) self.connector.pickServer = lambda: (self.server, 5222) self.connector.connect() reactor.callInThread(_do_connect) def _connected(self, xmlstream): self.status = 'CONNECTED' q.logger.log("[XMPPCLIENT] _connected: Connected to server [%s], trying with usersname [%s]" % (self.server, self.xmpp_user)) # Connected: capture the stream self.xmlstream = xmlstream self.xmlstream.addObserver('/presence', self._presence_received) self.xmlstream.addObserver('/message', self._message_received) def _authenticated(self, xmlstream): self.status = 'RUNNING' q.logger.log("[XMPPCLIENT] Server '" + self.server + "' authenticated user '" + self.xmpp_user + "'", 5) # Authentication succes: stop the startup watchdog if self.startup_watchdog: self.startup_watchdog.cancel() self.startup_watchdog = None # Put the agent controllers status to online self.sendPresence() if self.connectedCallback: self.connectedCallback() def _presence_received(self, elem): fromm = elem.getAttribute('from').split("@")[0] if not elem.hasAttribute('type'): type = 'available' else: type = elem.getAttribute('type') q.logger.log("[XMPPCLIENT] Presence received from '" + fromm + "' of type '" + type +"'", 5) if self.presenceReceivedCallback: self.presenceReceivedCallback(fromm, type) def _message_received(self, elem): fromm = elem.getAttribute('from').split("@")[0] type = elem.getAttribute('type') id = elem.getAttribute('id') message = str(elem.children[0].children[0]) q.logger.log("[XMPPCLIENT] Message '" + str(id) + "' of type '" + str(type) +"'" + "' received from '" + fromm + "'", 5) if self.messageReceivedCallback: self.messageReceivedCallback(fromm, type, id, message) def _init_failed(self, failure): self._disconnected('Init failed ' + str(failure)) def _end_stream(self, xmlstream): self._disconnected('Stream ended: connection lost') def _watchdog_timeout(self): self.connector.disconnect() self._disconnected('Connection timed out') def _disconnected(self, reason): self.status = 'DISCONNECTED' q.logger.log("[XMPPCLIENT] Disconnected: " + reason, 4) if self.disconnectedCallback: self.disconnectedCallback(reason)
class XmppService(Service): timeout = True active_controllers = [] def __init__(self, device, user='******', secret='password', userlist=[], web_server=None): self.log = Logger() self.description = None self.reactor = reactor self.user = user self.services = {} self.nodes = [] self.registrations = [] self.active_controllers = [] self.webserver = web_server self.resource = web_server.resource device.location = user def _map_context(ctx): ctx.udc = UserDefinedContext(device.player) self._jid = _jid = ''.join( (user, '/', device.deviceType, ':uuid:', device.uuid)) self.device = device device.parent = self for service in device.services: # if appreg.get_application(service.tns, service.name): # name = service.name + '_' # else: # name = service.name # soap_service = type( # service.name, (ServiceBase,), service.soap_functions) # soap_service.tns = service.tns # app = Application( # [soap_service], # tns=soap_service.tns, # in_protocol=Soap11(xml_declaration=False), # out_protocol=Soap11(xml_declaration=False), # name=name) # app.event_manager.add_listener('method_call', _map_context) self.services.update({ str(service.serviceId): { 'app': TwistedXMPPApp(service.app), 'svc': service } }) print('name: %s, methods: %s' % (device.name, service.app.interface.service_method_map)) for var in service.stateVariables.values(): if var.sendEvents: self.nodes.append((var, service.serviceType, service)) self.users = {user: False} for user in userlist: self.users.update({user: False}) self.jid = jid = JID(_jid) self.factory = f = client.XMPPClientFactory(jid, secret) f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.connected) f.addBootstrap(xmlstream.STREAM_END_EVENT, self.disconnected) f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.authenticated) f.addBootstrap(xmlstream.INIT_FAILED_EVENT, self.init_failed) # self.get_device_info(device) self.finished = defer.Deferred() # def get_device_info(self, device): # if len(device.icons) > 0: # icon = device.icons[0] # buf = read(open()) def startService(self): self.connector = SRVConnector(self.reactor, 'xmpp-client', self.jid.host, self.factory, defaultPort=5222) self.connector.connect() def stopService(self): for node in self.registrations: self.delete_ps_node(node) self.xmlstream.sendFooter() Service.stopService(self) def connected(self, xs): # print 'Connected.' # log.debug('!!!!!!!!!!!!!!!!!!!{app}', app=appreg._applications) self.xmlstream = xs # Log all traffic # xs.rawDataInFn = self.rawDataIn # xs.rawDataOutFn = self.rawDataOut def disconnected(self, xs): print 'Disconnected.' # self.finished.callback(None) def authenticated(self, xs): # print "Authenticated." xs.addObserver('/presence', self.on_presence) xs.addObserver('/iq', self.on_iq) presence = domish.Element((None, 'presence')) uc = domish.Element( ('urn:schemas-upnp-org:cloud-1-0', 'ConfigIdCloud')) uc['hash'] = 'uda' uc.addContent('1.0') # print(uc.toXml()) presence.addChild(uc) # print(presence.toXml()) xs.send(presence) disco = IQ(xs, 'get') disco.addElement(('http://jabber.org/protocol/disco#info', 'query')) disco.addCallback(self.check_server) disco.send(to='pubsub.xmpp.bertrandverdu.me') self.check_ps_nodes() self.reactor.callLater(30, self.ping) def ping(self): def pong(res): if res['type'] == 'result': # log.debug('pong !') self.timeout = False self.reactor.callLater(30, self.ping) else: self.log.error('ping error: %s' % res.toXml()) self.timeout = False # self.startService() def check_timeout(): if self.timeout: self.log.error('ping timeout !') # self.connector.connect() iq = IQ(self.xmlstream, 'get') iq.addElement('ping', 'urn:xmpp:ping') self.reactor.callLater(10, check_timeout) iq.addCallback(pong) self.timeout = True iq.send(to=self.jid.host) def rawDataIn(self, buf): print("Device RECV: %s" % unicode(buf, 'utf-8').encode('ascii', 'replace')) def rawDataOut(self, buf): print("Device SEND: %s" % unicode(buf, 'utf-8').encode('ascii', 'replace')) def check_server(self, result): def display_info(res): return e = fromstring(res.toXml()) dump(e) self.log.debug("server checked") display_info(result) # e = fromstring(result.toXml()) # dump(e) # iq = IQ(self.xmlstream, 'get') # ps = domish.Element( # ('http://jabber.org/protocol/pubsub#owner', 'pubsub')) # ps.addElement('default') # iq.addChild(ps) # iq.addCallback(display_info) # iq.send(to='pubsub.' + self.jid.host) # print(result.toXml()) def dump_description(self, dest): def sent(res): self.log.debug('description sent') pass self.log.debug('send description') # print(dest['id']) if self.description: self.log.debug('cached description') iq = IQ(self.xmlstream, 'result') iq.addRawXml(self.description) iq['id'] = dest['id'] else: self.log.debug('generate description') iq = IQ(self.xmlstream, 'result') query = domish.Element(('urn:schemas-upnp-org:cloud-1-0', 'query')) query['type'] = 'described' query['name'] = self.device.uuid d = tostring(self.device.dump(), encoding='unicode') query.addRawXml(d) # print(query.toXml()) for service in self.device.services: s = tostring(service.dump(), encoding='unicode') # print(s) query.addRawXml(s) # print(query.toXml()) self.description = query.toXml() iq.addChild(query) iq['id'] = dest['id'] # self.description = iq # print(iq.toXml()) iq.addCallback(sent) iq.send(to=dest['from']) def check_ps_nodes(self): def got_response(node, response): if response['type'] in ('error', 'cancel'): self.create_ps_node(node) elif response['type'] == 'result': node_name = '/'.join((self._jid, node[1])) if node_name in self.registrations: return self.registrations.append(node_name) self.log.debug('node {name} registered', name=node_name) event = XmppEvent(node_name, self, 'pubsub.' + self.jid.host) node[2].subscribe(event, 100) self.reactor.callLater(95, self.renew_subscription, *(node_name, node)) else: self.log.error('unknown response from server: %s' % response.toXml()) self.log.debug('check nodes: {nodes}', nodes=str(self.nodes)) IQ_ = IQ # Basic optimisation... element = domish.Element for node in self.nodes: iq = IQ_(self.xmlstream, 'get') query = element(('http://jabber.org/protocol/disco#info', 'query')) query['node'] = '/'.join((self._jid, node[1], node[0].name)) iq.addChild(query) iq.addCallback(got_response, node) iq.send(to='pubsub.' + self.jid.host) def create_ps_node(self, node): def registered(node, iq): if iq['type'] == 'result': node_name = '/'.join((self._jid, node[1])) if node_name in self.registrations: return event = XmppEvent(node_name, self, 'pubsub.' + self.jid.host) node[2].subscribe(event, 100) self.reactor.callLater(95, self.renew_subscription, *(node_name, node)) self.registrations.append(node_name) self.log.debug('node {node} registered', node=node_name) else: self.log.error('node creation {name} failed:{iq}', name=node, iq=iq.toXml()) iq = IQ(self.xmlstream, 'set') ps = domish.Element(('http://jabber.org/protocol/pubsub', 'pubsub')) create = domish.Element((None, 'create')) create['node'] = '/'.join((self._jid, node[1], node[0].name)) ps.addChild(create) configure = domish.Element((None, 'configure')) x = domish.Element(('jabber:x:data', 'x')) x['type'] = 'submit' field = domish.Element((None, 'field')) field['var'] = 'FORM_TYPE' field['type'] = 'hidden' field.addElement( 'value', content='http://jabber.org/protocol/pubsub#node_config') x.addChild(field) access = domish.Element((None, 'field')) access['var'] = 'pubsub#access_model' access.addElement('value', content='roster') x.addChild(access) # expire = domish.Element((None, 'field')) # expire['var'] = 'pubsub#item_expire' # expire.addElement('value', content='60') # x.addChild(expire) last = domish.Element((None, 'field')) last['var'] = 'pubsub#send_last_published_item' last.addElement('value', content='on_sub_and_presence') x.addChild(last) configure.addChild(x) ps.addChild(configure) iq.addChild(ps) iq.addCallback(registered, node) iq.send(to='pubsub.' + self.jid.host) def delete_ps_node(self, node): def deleted(res): if res['type'] == 'error': self.log.error('node deletion failed: %s' % res.toXml()) iq = IQ(self.xmlstream, 'set') ps = domish.Element( ('http://jabber.org/protocol/pubsub#owner', 'pubsub')) delete = domish.Element((None, 'delete')) delete['node'] = node ps.addChild(delete) iq.addChild(ps) iq.send(to='pubsub.' + self.jid.host) def renew_subscription(self, name, node): self.log.debug('renew %s : %s' % (name, (name in self.registrations))) if name in self.registrations: self.log.debug('renew: %s' % name) event = XmppEvent(name, self, 'pubsub.' + self.jid.host) node[2].subscribe(event, 100) self.reactor.callLater(95, self.renew_subscription, *(name, node)) def on_iq(self, iq): # print('received iq: %s' % iq.toXml().encode('utf-8')) user, host, res = parse(iq['from']) del (res) if not user: return jid = '@'.join((user, host)) self.log.debug('received request of type {typ} from {user}', typ=iq['type'], user=jid) if jid not in self.users and jid != self.user: self.log.info('rejected User: %s' % jid) return if iq['type'] == 'get': for child in iq.children: if child.name == 'query': if child['type'] == 'description': self.log.debug('description requested') self.dump_description(iq) elif iq['type'] == 'set': if iq.children[0].name == 'Envelope': self.log.debug('received rpc') root = iq.children[0] # print(root.toXml()) for child in root.children: if child.name == 'Header': res = self.services[ child.children[0]['serviceId']]['app'].handle_rpc( root.toXml(), child.children[0]['serviceId']) elif child.name == 'Body': decomposed = child.children[0].uri.split(':') guessed_id = ':'.join( (decomposed[0], decomposed[1], decomposed[2] + 'Id', decomposed[3])) res = self.services[str(guessed_id)]['app'].handle_rpc( root.toXml(), str(guessed_id)) else: self.log.warn('bad iq request: %s' % child.name) continue res.addCallback(self.respond_rpc, iq['from'], iq['id']) def respond_rpc(self, resp, to, queryID): # print('send: %s' % resp) # self.log.debug('respond rpc: %s' % resp[0][39:]) res = IQ(self.xmlstream, 'result') res['id'] = queryID if resp: for item in resp: res.addRawXml(item[39:].decode('utf-8')) # Skip the xml header res.send(to=to) def on_presence(self, presence): self.log.debug('received presence: %s' % presence.toXml().encode('utf-8')) if presence.hasAttribute('from'): user, host, res = parse(presence['from']) if presence['from'] in self.active_controllers: if presence.hasAttribute('type'): if presence['type'] == 'unavailable': self.active_controllers.remove(presence['from']) self.log.info('User {_from} disconnected', _from=presence['from']) return elif 'ControlPoint' in res: if presence.hasAttribute('type'): if presence['type'] == 'unavailable': return self.log.info('control point %s added' % presence['from']) if len(self.active_controllers) == 0: self.check_ps_nodes() self.active_controllers.append(presence['from']) del (res) jid = '@'.join((user, host)) if presence.hasAttribute('type'): if presence['type'] == 'subscribe': if jid in self.users: self.log.info('received subscription from %s' % jid) if self.users[jid] is False: iq = IQ(self.xmlstream, 'set') query = domish.Element( ('jabber:iq:roster', 'query')) item = domish.Element((None, 'item')) item['jid'] = jid item['name'] = jid item.addElement('group', content='UPnPCloud') query.addChild(item) iq.addChild(query) iq.addCallback(self.subscribed, jid) iq.send() else: self.log.error('subscription for user %s failed: %s' % (jid, 'Not in user list')) pres = domish.Element((None, 'presence')) pres['type'] = 'unsubscribed' pres['to'] = presence['from'] self.xmlstream.send(pres) def subscribed(self, jid, result): if result['type'] == 'result': self.log.info('user %s successfully suscribed' % jid) self.users.update({jid: True}) pres = domish.Element((None, 'presence')) pres['type'] = 'subscribed' pres['to'] = jid self.xmlstream.send(pres) else: self.log.error('subscription for user %s failed: %s' % (jid, result.toXml())) pres = domish.Element((None, 'presence')) pres['type'] = 'unsubscribed' pres['to'] = jid self.xmlstream.send(pres) def init_failed(self, failure): print "Initialization failed." print failure def register_art_url(self, url, cloud=False): if cloud: return None newurl = hashlib.md5(url).hexdigest() + url[-4:] self.resource.putChild(newurl, static.File(url)) return self.webserver.weburl % get_default_v4_address() + '/' + newurl
def clientCreator(factory): domain = factory.authenticator.jid.host c = SRVConnector(reactor, 'xmpp-client', domain, factory) c.connect() return factory.deferred
print "If the hostname and port are not specified, the MSRP relay will be discovered" print "through the the _msrps._tcp.domain SRV record. If a hostname is specified but" print "no port, the default port of 2855 will be used." else: username, domain = sys.argv[1].split("@", 1) cred = X509Credentials(None, None) cred.verify_peer = False ctx = TLSContext(cred) password = getpass() if len(sys.argv) == 2: factory = MSRPFileReceiverFactory(username, password, URI(domain, use_tls=True)) connector = SRVConnector(reactor, "msrps", domain, factory, connectFuncName="connectTLS", connectFuncArgs=[ctx]) connector.connect() else: relay_host = sys.argv[2] if len(sys.argv) == 4: relay_port = int(sys.argv[3]) else: relay_port = 2855 factory = MSRPFileReceiverFactory( username, password, URI(relay_host, port=relay_port, use_tls=True)) reactor.connectTLS(relay_host, relay_port, factory, ctx) reactor.run()
class XMPP(Listener): def init(self): self.username, self.server = self.mirror('username').split('@') self.password = self.mirror('password') listener = self.parent().get_listener(self._id) self.resource = listener['resource'] self.nickname = listener['nickname'] jid = "%s@%s/%s" % (self.username, self.server, self.resource) self.jid = JID(jid) self.f = client.XMPPClientFactory(self.jid, self.password) self.con = SRVConnector( reactor, 'xmpp-client', self.jid.host, self.f, defaultPort=5222) #self.con.connect() def is_twisted(self): return True def handlers(self): # Register event handlers. self.f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.on_connected) self.f.addBootstrap(xmlstream.STREAM_END_EVENT, self.on_disconnected) self.f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.on_authenticated) self.f.addBootstrap(xmlstream.INIT_FAILED_EVENT, self.on_init_failed) pass def signon(self): # Log in. self.con.connect() self.online(True) def loop(self): pass def rawDataIn(self, buf): #print "RECV: %s" % unicode(buf, 'utf-8').encode('ascii', 'replace') pass def rawDataOut(self, buf): #print "SEND: %s" % unicode(buf, 'utf-8').encode('ascii', 'replace') pass def send_message(self, to, content): message = domish.Element(('jabber:client', 'message')) message['to'] = JID(to).full() message['type'] = 'chat' message.addElement('body', 'jabber:client', content) self.xmlstream.send(message) def allow_subscribe(self, to): """Respond to an add (subscribe) request by allowing it.""" message = domish.Element({'jabber:client', 'presence'}) message['to'] = JID(to).full() message['type'] = 'subscribed' self.xmlstream.send(message) def deny_subscribe(self, to): """Respond to somebody removing us from their contact list.""" message = domish.Element({'jabber:client', 'presence'}) message['to'] = JID(to).full() message['type'] = 'unsubscribed' self.xmlstream.send(message) def on_connected(self, xs): #print 'Connected.' self.xmlstream = xs # Log all traffic. xs.rawDataInFn = self.rawDataIn xs.rawDataOutFn = self.rawDataOut def on_disconnected(self, xs): #print 'Disconnected.' pass def on_authenticated(self, xs): #print 'Authenticated.' presence = domish.Element(('jabber:client', 'presence')) xs.send(presence) # Register event handlers. xs.addObserver('/message', self.on_message) xs.addObserver('/presence', self.on_presence) xs.addObserver('/*', self.debug) # xs.sendFooter() # reactor.callLater(5, xs.sendFooter) def on_init_failed(self, failure): print 'Initialization failure.' print failure def on_message(self, el): #print "Received message!" # The sender. source = str(el['from']) username = singleton.format_name('XMPP', source.split("/")[0]) # Get the chat body. body = None for e in el.elements(): if e.name == 'body': if el['type'] == 'chat': body = str(e) #print "body:", body if body is None: return reply = singleton.get_reply(self._id, username, body) self.send_message(source, reply) def on_presence(self, el): #print "Received presence!" # The sender. source = str(el['from']) username = singleton.format_name('XMPP', source.split("/")[0]) # What type of presence message is this? if el['type'] == 'subscribe': # Somebody added us to their buddy list. Allow this. print "Allowing subscription by {}".format(source) self.allow_subscribe(source) elif el['type'] == 'unsubscribe': # They removed us from their list. Revoke the subscription. print "{} deleted us, removing subscription.".format(source) self.deny_subscribe(source) def debug(self, el): print el.toXml().encode('utf-8') def on_iq(self, con, iq): pass
class XMPPClient: ''' The XMPPClients uses the username, server and password to connect to the xmpp server. A message can be send using the sendMessage function, received presences and messages can be processed by a callback function. If the connection fails or is lost, the client will try to reconnect automatically. The disconnectedCallback can be used to catch the connection failed or connection lost event. At startup, a watchdog is started: if the server can't authenticate the user within the timeOut, the connection will be closed and the disconnectedCallback will be called. ''' def __init__(self, username, server, password, hostname, timeOut=5): self.username = username self.server = server self.password = password self.timeOut = timeOut self.hostname = hostname self.xmpp_user = None self.status = 'NOT_CONNECTED' self.messageReceivedCallback = None self.presenceReceivedCallback = None self.connectedCallback = None self.disconnectedCallback = None self.connector = None self.xmlstream = None def start(self): ''' Start the xmpp client, opens the connection to the server ''' if self.status <> 'NOT_CONNECTED': raise RuntimeError('The XmppClient has already been started.') q.logger.log( "[XMPPCLIENT] Starting the xmpp client to " + self.username + "@" + self.server, 5) self.startup_watchdog = reactor.callLater(self.timeOut, self._watchdog_timeout) self._connect() def stop(self): ''' Stop the xmpp client ''' if self.status == 'NOT_CONNECTED': raise RuntimeError('The XmppClient has not yet been started.') q.logger.log( "[XMPPCLIENT] Stopping the xmpp client to " + self.username + "@" + self.server, 5) self.connector.disconnect() def sendMessage(self, to, type, id, message=' '): ''' Send a message @param to: The username of the client to send the message to @type to: string @param type: The type of the message @type type: string @param id: The id of the message @type id: string @param message: The message to send @type message: string ''' if self.status <> 'RUNNING': raise NotConnectedException() q.logger.log( "[XMPPCLIENT] Sending message '" + str(id) + "' of type '" + str(type) + "' to " + str(to) + " for " + self.username + "@" + self.server, 5) elemToSend = domish.Element(('jabber:client', 'message'), attribs={ 'to': to + "@" + self.server, 'type': type, 'id': id }) body = domish.Element((None, 'body')) body.addContent(message) elemToSend.addContent(body) self.xmlstream.send(elemToSend) def sendPresence(self, to=None, type=None): ''' Send a presence @param to: The username of the client to send the presence to. None=send to all your friends @type to: string @param type: The type of the presence. Possible values: None=available, unavailable, subscribe, subscribed @type type: string ''' if self.status <> 'RUNNING': raise NotConnectedException() q.logger.log( "[XMPPCLIENT] Sending presence of type '" + str(type) + "' to " + str(to) + "'", 5) attribs = {} if to <> None: attribs['to'] = to + "@" + self.server if type <> None: attribs['type'] = type presence = domish.Element(('jabber:client', 'presence'), attribs=attribs) self.xmlstream.send(presence) def _presence_received(self, elem): fromm = elem.getAttribute('from').split("@")[0] if not elem.hasAttribute('type'): type = 'available' else: type = elem.getAttribute('type') q.logger.log( "[XMPPCLIENT] Presence received from '" + fromm + "' of type '" + type + "'", 5) if self.presenceReceivedCallback: self.presenceReceivedCallback(fromm, type) def setMessageReceivedCallback(self, callback): ''' @param callback: function to call when a message is received @type callback: function that expects 4 params: from, type, id and message ''' self.messageReceivedCallback = callback def setPresenceReceivedCallback(self, callback): ''' @param callback: function to call when a presence is received @type callback: function that expects 2 params: from and type ''' self.presenceReceivedCallback = callback def setDisconnectedCallback(self, callback): ''' Set the function to call when the client is disconnected from the xmpp server, if the keepAlive param is True in the constructor, the reconnect will be initiated after this callback. @param callback: function to call when the client is disconnected @type callback: function that expects 1 param: string containing the reason of the disconnect ''' self.disconnectedCallback = callback def setConnectedCallback(self, callback): ''' Set the function to call when the client is connected and authenticated with the xmpp server. @param callback: function to call when the client is connected and authenticated @type callback: function that expects no params ''' self.connectedCallback = callback def _connect(self): self.status = 'CONNECTING' if self.hostname != None: self.xmpp_user = self.username + "@" + self.hostname else: self.xmpp_user = self.username + "@" + self.server q.logger.log( "[XMPPCLIENT] Connecting to server %s with xmpp user %s'" % (self.server, self.xmpp_user)) c = client.XMPPClientFactory(jid.JID(self.xmpp_user), self.password) c.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self._connected) c.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self._authenticated) c.addBootstrap(xmlstream.INIT_FAILED_EVENT, self._init_failed) c.addBootstrap(xmlstream.STREAM_END_EVENT, self._end_stream) def _do_connect(): self.connector = SRVConnector(reactor, 'xmpp-client', self.server, c) self.connector.pickServer = lambda: (self.server, 5222) self.connector.connect() reactor.callInThread(_do_connect) def _connected(self, xmlstream): self.status = 'CONNECTED' q.logger.log( "[XMPPCLIENT] _connected: Connected to server [%s], trying with usersname [%s]" % (self.server, self.xmpp_user)) # Connected: capture the stream self.xmlstream = xmlstream self.xmlstream.addObserver('/presence', self._presence_received) self.xmlstream.addObserver('/message', self._message_received) def _authenticated(self, xmlstream): self.status = 'RUNNING' q.logger.log( "[XMPPCLIENT] Server '" + self.server + "' authenticated user '" + self.xmpp_user + "'", 5) # Authentication succes: stop the startup watchdog if self.startup_watchdog: self.startup_watchdog.cancel() self.startup_watchdog = None # Put the agent controllers status to online self.sendPresence() if self.connectedCallback: self.connectedCallback() def _presence_received(self, elem): fromm = elem.getAttribute('from').split("@")[0] if not elem.hasAttribute('type'): type = 'available' else: type = elem.getAttribute('type') q.logger.log( "[XMPPCLIENT] Presence received from '" + fromm + "' of type '" + type + "'", 5) if self.presenceReceivedCallback: self.presenceReceivedCallback(fromm, type) def _message_received(self, elem): fromm = elem.getAttribute('from').split("@")[0] type = elem.getAttribute('type') id = elem.getAttribute('id') message = str(elem.children[0].children[0]) q.logger.log( "[XMPPCLIENT] Message '" + str(id) + "' of type '" + str(type) + "'" + "' received from '" + fromm + "'", 5) if self.messageReceivedCallback: self.messageReceivedCallback(fromm, type, id, message) def _init_failed(self, failure): self._disconnected('Init failed ' + str(failure)) def _end_stream(self, xmlstream): self._disconnected('Stream ended: connection lost') def _watchdog_timeout(self): self.connector.disconnect() self._disconnected('Connection timed out') def _disconnected(self, reason): self.status = 'DISCONNECTED' q.logger.log("[XMPPCLIENT] Disconnected: " + reason, 4) if self.disconnectedCallback: self.disconnectedCallback(reason)
class XMPP(Listener): def init(self): self.username, self.server = self.mirror('username').split('@') self.password = self.mirror('password') listener = self.parent().get_listener(self._id) self.resource = listener['resource'] self.nickname = listener['nickname'] jid = "%s@%s/%s" % (self.username, self.server, self.resource) self.jid = JID(jid) self.f = client.XMPPClientFactory(self.jid, self.password) self.con = SRVConnector(reactor, 'xmpp-client', self.jid.host, self.f, defaultPort=5222) #self.con.connect() def is_twisted(self): return True def handlers(self): # Register event handlers. self.f.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, self.on_connected) self.f.addBootstrap(xmlstream.STREAM_END_EVENT, self.on_disconnected) self.f.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.on_authenticated) self.f.addBootstrap(xmlstream.INIT_FAILED_EVENT, self.on_init_failed) pass def signon(self): # Log in. self.con.connect() self.online(True) def loop(self): pass def rawDataIn(self, buf): #print "RECV: %s" % unicode(buf, 'utf-8').encode('ascii', 'replace') pass def rawDataOut(self, buf): #print "SEND: %s" % unicode(buf, 'utf-8').encode('ascii', 'replace') pass def send_message(self, to, content): message = domish.Element(('jabber:client', 'message')) message['to'] = JID(to).full() message['type'] = 'chat' message.addElement('body', 'jabber:client', content) self.xmlstream.send(message) def allow_subscribe(self, to): """Respond to an add (subscribe) request by allowing it.""" message = domish.Element({'jabber:client', 'presence'}) message['to'] = JID(to).full() message['type'] = 'subscribed' self.xmlstream.send(message) def deny_subscribe(self, to): """Respond to somebody removing us from their contact list.""" message = domish.Element({'jabber:client', 'presence'}) message['to'] = JID(to).full() message['type'] = 'unsubscribed' self.xmlstream.send(message) def on_connected(self, xs): #print 'Connected.' self.xmlstream = xs # Log all traffic. xs.rawDataInFn = self.rawDataIn xs.rawDataOutFn = self.rawDataOut def on_disconnected(self, xs): #print 'Disconnected.' pass def on_authenticated(self, xs): #print 'Authenticated.' presence = domish.Element(('jabber:client', 'presence')) xs.send(presence) # Register event handlers. xs.addObserver('/message', self.on_message) xs.addObserver('/presence', self.on_presence) xs.addObserver('/*', self.debug) # xs.sendFooter() # reactor.callLater(5, xs.sendFooter) def on_init_failed(self, failure): print 'Initialization failure.' print failure def on_message(self, el): #print "Received message!" # The sender. source = str(el['from']) username = singleton.format_name('XMPP', source.split("/")[0]) # Get the chat body. body = None for e in el.elements(): if e.name == 'body': if el['type'] == 'chat': body = str(e) #print "body:", body if body is None: return reply = singleton.get_reply(self._id, username, body) self.send_message(source, reply) def on_presence(self, el): #print "Received presence!" # The sender. source = str(el['from']) username = singleton.format_name('XMPP', source.split("/")[0]) # What type of presence message is this? if el['type'] == 'subscribe': # Somebody added us to their buddy list. Allow this. print "Allowing subscription by {}".format(source) self.allow_subscribe(source) elif el['type'] == 'unsubscribe': # They removed us from their list. Revoke the subscription. print "{} deleted us, removing subscription.".format(source) self.deny_subscribe(source) def debug(self, el): print el.toXml().encode('utf-8') def on_iq(self, con, iq): pass
def clientConnectionLost(self, connector, err): print "Connection lost" print err.value reactor.callLater(0, reactor.stop) if __name__ == "__main__": if len(sys.argv) < 2 or len(sys.argv) > 4: print "Usage: %s user@domain [relay-hostname [relay-port]]" % sys.argv[0] print "If the hostname and port are not specified, the MSRP relay will be discovered" print "through the the _msrps._tcp.domain SRV record. If a hostname is specified but" print "no port, the default port of 2855 will be used." else: username, domain = sys.argv[1].split("@", 1) cred = X509Credentials(None, None) cred.verify_peer = False ctx = TLSContext(cred) password = getpass() if len(sys.argv) == 2: factory = MSRPFileReceiverFactory(username, password, URI(domain, use_tls=True)) connector = SRVConnector(reactor, "msrps", domain, factory, connectFuncName="connectTLS", connectFuncArgs=[ctx]) connector.connect() else: relay_host = sys.argv[2] if len(sys.argv) == 4: relay_port = int(sys.argv[3]) else: relay_port = 2855 factory = MSRPFileReceiverFactory(username, password, URI(relay_host, port=relay_port, use_tls=True)) reactor.connectTLS(relay_host, relay_port, factory, ctx) reactor.run()