wokkel integration (not finished yet)

This commit is contained in:
Goffi 2009-10-30 17:38:27 +01:00
commit 4c7d7563d3
3 changed files with 189 additions and 141 deletions

View file

@ -25,7 +25,6 @@ from sat_bridge_frontend.DBus import DBusBridgeFrontend
from quick_frontend.quick_contact_management import QuickContactManagement
class QuickApp():
"""This class contain the main methods needed for the frontend"""
@ -126,8 +125,8 @@ class QuickApp():
self.contactList.replace(jid, show=show, status=status, name=name, group=group)
if type=="unavailable" and jid.short in self.onlineContact:
self.onlineContact.remove(jid.short)
if type=="unavailable" and jid in self.onlineContact:
self.onlineContact.remove(jid)
self.CM.remove(jid)
self.contactList.remove(jid)

323
sat.tac
View file

@ -24,12 +24,14 @@ from twisted.application import internet, service
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 @@ logging.basicConfig(level=logging.DEBUG,
###
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 @@ class SAT:
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 @@ class SAT:
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 @@ class SAT:
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
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)
if to:
presence.attributes["to"]=to
if type:
presence.attributes["type"]=type
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 @@ class SAT:
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 @@ class SAT:
application = service.Application('SàT')
sat = SAT()
service = sat.getService()
service = SAT()
service.setServiceParent(application)

View file

@ -121,7 +121,7 @@ class Memory:
def addContact(self, JID, attributes, groups):
debug("Memory addContact: %s",JID)
assert(isinstance(attributes,dict))
assert(isinstance(groups,list))
assert(isinstance(groups,set))
self.contact[JID]=[attributes, groups]
def addPresenceStatus(self, jid, type, show, status, priority):