Mercurial > libervia-backend
diff sat.tac @ 13:bd9e9997d540
wokkel integration (not finished yet)
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 30 Oct 2009 17:38:27 +0100 |
parents | ef8060d365cb |
children | a62d7d453f22 |
line wrap: on
line diff
--- a/sat.tac Wed Oct 28 00:39:29 2009 +0100 +++ b/sat.tac Fri Oct 30 17:38:27 2009 +0100 @@ -24,12 +24,14 @@ from twisted.internet import glib2reactor, protocol, task glib2reactor.install() -from twisted.words.protocols.jabber import client, jid, xmlstream, error +from twisted.words.protocols.jabber import jid, xmlstream, error from twisted.words.xish import domish from twisted.internet import reactor import pdb +from wokkel import client, disco, xmppim + from sat_bridge.DBus import DBusBridge import logging from logging import debug, info, error @@ -47,15 +49,132 @@ ### +class SatXMPPClient(client.XMPPClient): + + def __init__(self, jid, password, host=None, port=5222): + client.XMPPClient.__init__(self, jid, password, host, port) + self.factory.clientConnectionLost = self.connectionLost + self.__connected=False + + def _authd(self, xmlstream): + print "SatXMPPClient" + client.XMPPClient._authd(self, xmlstream) + self.__connected=True + print "********** CONNECTED **********" + self.streamInitialized() + + def streamInitialized(self): + """Called after _authd""" + self.keep_alife = task.LoopingCall(self.xmlstream.send, " ") #Needed to avoid disconnection (specially with openfire) + self.keep_alife.start(180) + + def isConnected(self): + return self.__connected + + def connectionLost(self, connector, unused_reason): + print "********** DISCONNECTED **********" + try: + self.keep_alife.stop() + except AttributeError: + debug("No keep_alife") -class SAT: +class SatMessageProtocol(xmppim.MessageProtocol): + + def __init__(self, host): + xmppim.MessageProtocol.__init__(self) + self.host = host + + def onMessage(self, message): + debug (u"got_message from: %s", message["from"]) + for e in message.elements(): + if e.name == "body": + self.host.bridge.newMessage(message["from"], e.children[0]) + self.host.memory.addToHistory(self.host.me, jid.JID(message["from"]), self.host.me, "chat", e.children[0]) + break + +class SatRosterProtocol(xmppim.RosterClientProtocol): + + def __init__(self, host): + xmppim.RosterClientProtocol.__init__(self) + self.host = host + + def rosterCb(self, roster): + for jid, item in roster.iteritems(): + info ("new contact in roster list: %s", jid) + #FIXME: fill attributes + self.host.memory.addContact(jid, {}, item.groups) + self.host.bridge.newContact(jid, {}, item.groups) + + def requestRoster(self): + """ ask the server for Roster list """ + debug("requestRoster") + self.getRoster().addCallback(self.rosterCb) + + def removeItem(self, to): + """Remove a contact from roster list""" + to_jid=jid.JID(to) + xmppim.RosterClientProtocol.removeItem(self, to_jid) + #TODO: check IQ result + + def addItem(self, to): + """Add a contact to roster list""" + to_jid=jid.JID(to) + xmppim.RosterClientProtocol.addItem(self, to_jid) + #TODO: check IQ result + +class SatPresenceProtocol(xmppim.PresenceClientProtocol): + + def __init__(self, host): + xmppim.PresenceClientProtocol.__init__(self) + self.host = host + + def availableReceived(self, entity, show=None, statuses=None, priority=0): + info ("presence update for [%s]", entity) + + ### we check if the status is not about subscription ### + #FIXME: type is not needed anymore + #TODO: management of differents statuses (differents languages) + status = statuses.values()[0] if len(statuses) else "" + self.host.memory.addPresenceStatus(entity.full(), "", show or "", + status or "", int(priority)) + + #now it's time to notify frontends + pdb.set_trace() + self.host.bridge.presenceUpdate(entity.full(), "", show or "", + status or "", int(priority)) + + def unavailableReceived(self, entity, statuses=None): + #TODO: management of differents statuses (differents languages) + status = statuses.values()[0] if len(statuses) else "" + self.host.memory.addPresenceStatus(entity.full(), "unavailable", "", + status or "", 0) + + #now it's time to notify frontends + self.host.bridge.presenceUpdate(entity.full(), "unavailable", "", + status or "", 0) + + + def subscribedReceived(self, entity): + debug ("subscription approved for [%s]" % entity) + + def unsubscribedReceived(self, entity): + debug ("unsubscription confirmed for [%s]" % entity) + + def subscribeReceived(self, entity): + #FIXME: auto answer for subscribe request, must be checked ! + debug ("subscription request for [%s]" % entity) + self.subscribed(entity) + + def unsubscribeReceived(self, entity): + debug ("unsubscription asked for [%s]" % entity) + +class SAT(service.Service): def __init__(self): #self.reactor=reactor self.memory=Memory() self.server_features=[] #XXX: temp dic, need to be transfered into self.memory in the future - self.connected=False #FIXME: use twisted var instead self._iq_cb_map = {} #callback called when ns is found on IQ self._waiting_conf = {} #callback called when a confirmation is received @@ -98,33 +217,39 @@ self.plugins[plug_info['import_name']] = getattr(mod, plug_info['main'])(self) def connect(self): - if (self.connected): + if (self.isConnected()): info("already connected !") return print "connecting..." - reactor.connectTCP(self.memory.getParamV("Server", "Connection"), 5222, self.factory) + self.me = jid.JID(self.memory.getParamV("JabberID", "Connection")) + self.xmppclient = SatXMPPClient(self.me, self.memory.getParamV("Password", "Connection"), + self.memory.getParamV("Server", "Connection"), 5222) + self.xmppclient.streamInitialized = self.streamInitialized + + self.messageProt = SatMessageProtocol(self) + self.messageProt.setHandlerParent(self.xmppclient) + + self.roster = SatRosterProtocol(self) + self.roster.setHandlerParent(self.xmppclient) + + self.presence = SatPresenceProtocol(self) + self.presence.setHandlerParent(self.xmppclient) + + self.xmppclient.startService() def disconnect(self): - if (not self.connected): + if (not self.isConnected()): info("not connected !") return info("Disconnecting...") - self.factory.stopTrying() - if self.xmlstream: - self.xmlstream.sendFooter() + self.xmppclient.stopService() - def getService(self): - print "GetService !" - """if (self.connected): - info("already connected !") - return""" - info("Getting service...") - self.me = jid.JID(self.memory.getParamV("JabberID", "Connection")) - self.factory = client.XMPPClientFactory(self.me, self.memory.getParamV("Password", "Connection")) - self.factory.clientConnectionLost = self.connectionLost - self.factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT,self.authd) - self.factory.addBootstrap(xmlstream.INIT_FAILED_EVENT,self.failed) - return internet.TCPClient(self.memory.getParamV("Server", "Connection"), 5222, self.factory) + def startService(self): + info("Salut à toi ô mon frère !") + self.connect() + + def stopService(self): + info("Salut aussi à Rantanplan") def run(self): debug("running app") @@ -134,38 +259,30 @@ debug("stopping app") reactor.stop() - def authd(self,xmlstream): - self.xmlstream=xmlstream - roster=client.IQ(xmlstream,'get') - roster.addElement(('jabber:iq:roster', 'query')) - roster.addCallback(self.rosterCb) - roster.send() - debug("server = %s",self.memory.getParamV("Server", "Connection")) - + def streamInitialized(self): + """Called when xmlstream is OK""" + SatXMPPClient.streamInitialized(self.xmppclient) + debug ("XML stream is initialized") + self.xmlstream = self.xmppclient.xmlstream + self.me = self.xmppclient.jid #in case of the ressource has changed + + self.roster.requestRoster() + + self.presence.available() + + #FIXME:tmp + self.xmlstream.addObserver("/iq[@type='set' or @type='get']", self.iqCb) + """ ###FIXME: tmp disco ### + #self.discoHandler = disco.discoHandler() self.memory.registerFeature("http://jabber.org/protocol/disco#info") self.disco(self.memory.getParamV("Server", "Connection"), self.serverDisco) - - #we now send our presence status - self.setPresence(status="Online") # add a callback for the messages - xmlstream.addObserver('/message', self.gotMessage) - xmlstream.addObserver('/presence', self.presenceCb) - xmlstream.addObserver("/iq[@type='set' or @type='get']", self.iqCb) - print "********** CONNECTED **********" - self.connected=True - self.keep_alife = task.LoopingCall(self.xmlstream.send, " ") #Needed to avoid disconnection (specially with openfire) - self.keep_alife.start(180) #reactor.callLater(2,self.sendFile,"goffi2@jabber.goffi.int/Psi", "/tmp/fakefile") - - def connectionLost(self, connector, unused_reason): - print "********** DISCONNECTED **********" - if self.keep_alife: - self.keep_alife.stop() - self.connected=False + """ def sendMessage(self,to,msg,type='chat'): @@ -186,86 +303,64 @@ self.memory.setParam(name, value, namespace) self.bridge.paramUpdate(name, value, namespace) - def setRoster(self, to): - """Add a contact to roster list""" - to_jid=jid.JID(to) - roster=client.IQ(self.xmlstream,'set') - query=roster.addElement(('jabber:iq:roster', 'query')) - item=query.addElement("item") - item.attributes["jid"]=to_jid.userhost() - roster.send() - #TODO: check IQ result - - def delRoster(self, to): - """Remove a contact from roster list""" - to_jid=jid.JID(to) - roster=client.IQ(self.xmlstream,'set') - query=roster.addElement(('jabber:iq:roster', 'query')) - item=query.addElement("item") - item.attributes["jid"]=to_jid.userhost() - item.attributes["subscription"]="remove" - roster.send() - #TODO: check IQ result - - def failed(self,xmlstream): debug("failed: %s", xmlstream.getErrorMessage()) debug("failed: %s", dir(xmlstream)) def isConnected(self): - return self.connected + try: + if self.xmppclient.isConnected(): + return True + except AttributeError: + #xmppclient not available + pass + return False ## jabber methods ## def disco (self, item, callback, node=None): """XEP-0030 Service discovery Feature.""" - disco=client.IQ(self.xmlstream,'get') + """disco=client.IQ(self.xmlstream,'get') disco["from"]=self.me.full() disco["to"]=item disco.addElement(('http://jabber.org/protocol/disco#info', 'query')) disco.addCallback(callback) - disco.send() + disco.send()""" def setPresence(self, to="", type="", show="", status="", priority=0): """Send our presence information""" - presence = domish.Element(('jabber:client', 'presence')) if not type in ["", "unavailable", "subscribed", "subscribe", "unsubscribe", "unsubscribed", "prob", "error"]: error("Type error !") #TODO: throw an error return - - if to: - presence.attributes["to"]=to - if type: - presence.attributes["type"]=type + to_jid=jid.JID(to) + #TODO: refactor subscription bridge API + if type=="": + self.presence.available(to_jid, show, status, priority) + elif type=="subscribe": + self.presence.subscribe(to_jid) + elif type=="subscribed": + self.presence.subscribed(to_jid) + elif type=="unsubscribe": + self.presence.unsubscribe(to_jid) + elif type=="unsubscribed": + self.presence.unsubscribed(to_jid) - for element in ["show", "status", "priority"]: - if locals()[element]: - presence.addElement(element).addContent(unicode(locals()[element])) - - self.xmlstream.send(presence) def addContact(self, to): """Add a contact in roster list""" to_jid=jid.JID(to) - self.setRoster(to_jid.userhost()) + self.roster.addItem(to_jid.userhost()) self.setPresence(to_jid.userhost(), "subscribe") def delContact(self, to): """Remove contact from roster list""" to_jid=jid.JID(to) - self.delRoster(to_jid.userhost()) + self.roster.removeItem(to_jid.userhost()) self.bridge.contactDeleted(to) - def gotMessage(self,message): - debug (u"got_message from: %s", message["from"]) - for e in message.elements(): - if e.name == "body": - self.bridge.newMessage(message["from"], e.children[0]) - self.memory.addToHistory(self.me, jid.JID(message["from"]), self.me, "chat", e.children[0]) - break ## callbacks ## @@ -286,52 +381,7 @@ self._iq_cb_map[uri](stanza) #TODO: manage errors stanza - def presenceCb(self, elem): - info ("presence update for [%s]", elem.getAttribute("from")) - debug("\n\nXML=\n%s\n\n", elem.toXml()) - presence={} - presence["jid"]=elem.getAttribute("from") - presence["type"]=elem.getAttribute("type") or "" - presence["show"]="" - presence["status"]="" - presence["priority"]=0 - - for item in elem.elements(): - if presence.has_key(item.name): - presence[item.name]=item.children[0] - ### we check if the status is not about subscription ### - #TODO: check that from jid is one we wants to subscribe (ie: check a recent subscription asking) - if jid.JID(presence["jid"]).userhost()!=self.me.userhost(): - if presence["type"]=="subscribed": - debug ("subscription answer") - elif presence["type"]=="unsubscribed": - debug ("unsubscription answer") - elif presence["type"]=="subscribe": - #FIXME: auto answer for subscribe request, must be checked ! - debug ("subscription request") - self.setPresence(to=presence["jid"], type="subscribed") - else: - #We keep presence information only if it is not for subscription - self.memory.addPresenceStatus(presence["jid"], presence["type"], presence["show"], - presence["status"], int(presence["priority"])) - - #now it's time to notify frontends - self.bridge.presenceUpdate(presence["jid"], presence["type"], presence["show"], - presence["status"], int(presence["priority"])) - - def rosterCb(self,roster): - for contact in roster.firstChildElement().elements(): - info ("new contact in roster list: %s", contact['jid']) - #and now the groups - groups=[] - for group in contact.elements(): - if group.name!="group": - error("Unexpected element !") - break - groups.append(str(group)) - self.memory.addContact(contact['jid'], contact.attributes, groups) - self.bridge.newContact(contact['jid'], contact.attributes, groups) def serverDisco(self, disco): """xep-0030 Discovery Protocol.""" @@ -390,8 +440,7 @@ application = service.Application('SàT') -sat = SAT() -service = sat.getService() +service = SAT() service.setServiceParent(application)