diff -r 7b9f484b0b44 wokkel/xmppim.py --- a/wokkel/xmppim.py Fri Feb 12 19:49:36 2010 +0100 +++ b/wokkel/xmppim.py Sat Feb 13 18:57:26 2010 +0100 @@ -12,6 +12,7 @@ All of it should eventually move to Twisted. """ +from twisted.words.protocols.jabber import error, xmlstream from twisted.words.protocols.jabber.jid import JID from twisted.words.xish import domish @@ -22,6 +23,9 @@ NS_XML = 'http://www.w3.org/XML/1998/namespace' NS_ROSTER = 'jabber:iq:roster' +XPATH_ROSTER_GET = "//iq[@type='get']/query[@xmlns='%s']" % NS_ROSTER +XPATH_ROSTER_SET = "//iq[@type='set']/query[@xmlns='%s']" % NS_ROSTER + class Presence(domish.Element): def __init__(self, to=None, type=None): domish.Element.__init__(self, (None, "presence")) @@ -636,6 +640,7 @@ + class RosterClientProtocol(XMPPHandler): """ Client side XMPP roster protocol. @@ -645,6 +650,7 @@ ROSTER_SET = "/iq[@type='set']/query[@xmlns='%s']" % NS_ROSTER self.xmlstream.addObserver(ROSTER_SET, self._onRosterSet) + def _parseRosterItem(self, element): jid = JID(element['jid']) item = RosterItem(jid) @@ -659,6 +665,7 @@ return item + def getRoster(self): """ Retrieve contact list. @@ -713,6 +720,7 @@ item = self._parseRosterItem(iq.query.item) self.onRosterSet(item) + def onRosterSet(self, item): """ Called when a roster push for a new or update item was received. @@ -721,6 +729,7 @@ @type item: L{RosterItem} """ + def onRosterRemove(self, entity): """ Called when a roster push for the removal of an item was received. @@ -729,6 +738,48 @@ @type entity: L{JID} """ + + +class RosterServerProtocol(XMPPHandler): + """ + XMPP subprotocol handler for the roster, server side. + """ + + def connectionInitialized(self): + self.xmlstream.addObserver(XPATH_ROSTER_GET, self._onRosterGet) + self.xmlstream.addObserver(XPATH_ROSTER_SET, self._onRosterSet) + + + def _toRosterReply(self, roster, iq): + response = xmlstream.toResponse(iq, 'result') + response.addElement((NS_ROSTER, 'query')) + + for item in roster: + response.query.addChild(item.toElement()) + + return response + + + def _onRosterGet(self, iq): + iq.handled = True + + d = self.getRoster(JID(iq["from"])) + d.addCallback(self._toRosterReply, iq) + d.addErrback(lambda _: error.ErrorStanza('internal-error').toResponse(iq)) + d.addBoth(self.send) + + + def _onRosterSet(self, iq): + iq.handled = True + response = error.StanzaError('bad-request').toResponse(iq) + self.send(response) + + + def getRoster(self, entity): + raise NotImplemented + + + class MessageProtocol(XMPPHandler): """ Generic XMPP subprotocol handler for incoming message stanzas.