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 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, client_reactor, domain, factory): """ Init """ SRVConnector.__init__(self, client_reactor, 'xmpp-client', domain, factory) if isinstance(domain, unicode): warnings.warn( "Domain argument to XMPPClientConnector should be bytes, " "not unicode", stacklevel=2) domain = domain.encode('ascii') self.timeout = [1,3]
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, reactor, dn, factory, overrides=None, bindAddress=None): if not isinstance(dn, distinguishedname.DistinguishedName): dn = distinguishedname.DistinguishedName(stringValue=dn) if overrides is None: overrides = {} self.override = self._findOverRide(dn, overrides) domain = dn.getDomainName() or '' SRVConnector.__init__(self, reactor, 'ldap', domain, factory, connectFuncKwArgs={'bindAddress': bindAddress})
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 pickServer(self): if self.override is None: overriddenHost, overriddenPort = None, None else: overriddenHost, overriddenPort = self.override if (overriddenHost is not None and (overriddenPort is not None or self.domain is None)): host = overriddenHost port = overriddenPort else: host, port = SRVConnector.pickServer(self) if overriddenHost is not None: host = overriddenHost if overriddenPort is not None: port = overriddenPort try: port = int(port) except ValueError: pass assert host is not None if port is None: port = 389 return host, port
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 pickServer(self): host, port = SRVConnector.pickServer(self) if not self.servers and not self.orderedServers: # no SRV record, fall back.. port = int(config()['xmpp']['port']) return host, port
def pickServer(self): host, port = SRVConnector.pickServer(self) if not self.servers and not self.orderedServers: # no SRV record, fall back.. port = 5222 return host, port
def pickServer(self): assert self.servers is not None assert self.orderedServers is not None if not self.servers and not self.orderedServers: # no SRV record, fall back.. return self.domain, 2855 return SRVConnector.pickServer(self)
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))
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)
def pickServer(self): """ Pick a server and port to make the connection. """ host, port = SRVConnector.pickServer(self) if port == 5223 and ssl: context = ssl.ClientContextFactory() context.method = ssl.SSL.SSLv23_METHOD self.connectFuncName = 'connectSSL' self.connectFuncArgs = (context,) return host, port
def pickServer(self): """ Pick a server and port to make the connection. """ host, port = SRVConnector.pickServer(self) if port == 5223 and ssl: context = ssl.ClientContextFactory() context.method = ssl.SSL.SSLv23_METHOD self.connectFuncName = 'connectSSL' self.connectFuncArgs = (context, ) return host, port
def pickServer(self): """ Pick a server and port to make the connection. """ host, port = SRVConnector.pickServer(self) if not self.servers and not self.orderedServers: # no SRV record, fall back.. port = 5222 if port == 5223 and xmlstream.ssl: context = xmlstream.ssl.ClientContextFactory() context.method = xmlstream.ssl.SSL.SSLv23_METHOD self.connectFunc = 'connectSSL' self.connectFuncArgs = (context) return host, port
def fetch_server_key(server_name, ssl_context_factory): """Fetch the keys for a remote server.""" factory = SynapseKeyClientFactory() SRVConnector( reactor, "matrix", server_name, factory, protocol="tcp", connectFuncName="connectSSL", defaultPort=443, connectFuncKwArgs=dict(contextFactory=ssl_context_factory)).connect() server_key, server_certificate = yield factory.remote_key defer.returnValue((server_key, server_certificate))
def clientCreator(factory): domain = factory.authenticator.jid.host c = SRVConnector(reactor, 'xmpp-client', domain, factory) c.connect() return factory.deferred
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
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()
def pickServer(self): host, port = SRVConnector.pickServer(self) if not self.servers and not self.orderedServers: port = 5222 return host, port
def __init__(self, reactor, domain, factory, port=5222): self.port=port SRVConnector.__init__(self, reactor, 'xmpp-client', domain, factory)
def __init__(self, reactor, domain, factory, credentials, tls_reactor): self.tls_reactor = tls_reactor SRVConnector.__init__(self, reactor, 'xmpp-net', str(domain), factory, connectFuncName='connectTLS', connectFuncKwArgs={'credentials':credentials})
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)
def pickServer(self): host, port = SRVConnector.pickServer(self) print 'Resolved _%s._%s.%s --> %s:%s' % (self.service, self.protocol, self.domain, host, port) return host, port
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 __init__(self, reactor, domain, factory): SRVConnector.__init__(self, reactor, 'xmpp-server', domain, factory)
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()
def pickServer(self): host, port = SRVConnector.pickServer(self) print('Resolved _%s._%s.%s --> %s:%s' % (self.service, self.protocol, self.domain, host, port)) return host, port
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 __init__(self, reactor, domain, factory): SRVConnector.__init__(self, reactor, 'xmpp-client', domain, factory)
def __init__(self, client_reactor, domain, factory): """ Init """ SRVConnector.__init__(self, client_reactor, 'xmpp-client', domain, factory) self.timeout = [1,3]
def _do_connect(): self.connector = SRVConnector(reactor, 'xmpp-client', self.server, c) self.connector.pickServer = lambda: (self.server, 5222) self.connector.connect()
def __init__(self, client_reactor, domain, factory): """ Init """ SRVConnector.__init__(self, client_reactor, 'xmpp-client', domain, factory) self.timeout = [1, 3]
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)