# HG changeset patch # User Goffi # Date 1296752785 -3600 # Node ID 68cd30d982a5fdc9e3b584be88803b2b9c119e51 # Parent 6a0c6d8e119db534189cd7df884d4966e1cef8d7 core: added plugins for PubSub et PEP (first drafts) - plugin for XEP 0060, 0163 and 0107, based on Wokkel's pubsub - XEP 0115 plugin has been fixed, so generateHash can be called when features have changed (can be usefull to filter PEP) diff -r 6a0c6d8e119d -r 68cd30d982a5 src/plugins/plugin_xep_0060.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/plugin_xep_0060.py Thu Feb 03 18:06:25 2011 +0100 @@ -0,0 +1,94 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +SAT plugin for Publish-Subscribe (xep-0060) +Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +from logging import debug, info, error +from twisted.internet import protocol +from twisted.words.protocols.jabber import client, jid +from twisted.words.protocols.jabber import error as jab_error +import twisted.internet.error + +from wokkel import disco, iwokkel, pubsub + +from zope.interface import implements + +PLUGIN_INFO = { +"name": "Publish-Subscribe", +"import_name": "XEP_0060", +"type": "XEP", +"protocols": ["XEP-0060"], +"dependencies": [], +"main": "XEP_0060", +"handler": "yes", +"description": _("""Implementation of PubSub Protocol""") +} + +class XEP_0060(): + + def __init__(self, host): + info(_("PubSub plugin initialization")) + self.host = host + self.managedNodes=[] + self.clients={} + + def getHandler(self, profile): + self.clients[profile] = SatPubSubClient(self.host, self) + return self.clients[profile] + + def addManagedNode(self, node_name, callback): + """Add a handler for a namespace + @param namespace: NS of the handler (will appear in disco info) + @param callback: method to call when the handler is found + @param profile: profile which manage this handler""" + self.managedNodes.append((node_name, callback)) + + +class SatPubSubClient(pubsub.PubSubClient): + implements(disco.IDisco) + + def __init__(self, host, parent_plugin): + self.host=host + self.parent_plugin = parent_plugin + pubsub.PubSubClient.__init__(self) + + def connectionInitialized(self): + pubsub.PubSubClient.connectionInitialized(self) + + def itemsReceived(self, event): + for node in self.parent_plugin.managedNodes: + if event.nodeIdentifier == node[0]: + return node[1](event, self.parent.profile) + + def deleteReceived(self, event): + import pdb + pdb.set_trace() + + def purgeReceived(self, event): + import pdb + pdb.set_trace() + + def getDiscoInfo(self, requestor, target, nodeIdentifier=''): + _disco_info = [] + self.host.trigger.point("PubSub Disco Info", _disco_info, self.parent.profile) + return _disco_info + + def getDiscoItems(self, requestor, target, nodeIdentifier=''): + return [] + diff -r 6a0c6d8e119d -r 68cd30d982a5 src/plugins/plugin_xep_0115.py --- a/src/plugins/plugin_xep_0115.py Thu Feb 03 01:27:57 2011 +0100 +++ b/src/plugins/plugin_xep_0115.py Thu Feb 03 18:06:25 2011 +0100 @@ -96,17 +96,20 @@ """modify SatPresenceProtocol to add capabilities data""" client=self.host.getClient(profile) presenceInst = client.presence + c_elt = domish.Element((NS_ENTITY_CAPABILITY,'c')) + c_elt['hash']='sha-1' + c_elt['node']='http://wiki.goffi.org/wiki/Salut_%C3%A0_Toi' + c_elt['ver']=XEP_0115.cap_hash + presenceInst._c_elt = c_elt + if "_legacy_send" in dir(presenceInst): + debug('capabilities already added to presence instance') + return def hacked_send(self, obj): obj.addChild(self._c_elt) self._legacy_send(obj) new_send = types.MethodType(hacked_send, presenceInst, presenceInst.__class__) presenceInst._legacy_send = presenceInst.send presenceInst.send = new_send - c_elt = domish.Element((NS_ENTITY_CAPABILITY,'c')) - c_elt['hash']='sha-1' - c_elt['node']='http://wiki.goffi.org/wiki/Salut_%C3%A0_Toi' - c_elt['ver']=XEP_0115.cap_hash - presenceInst._c_elt = c_elt def generateHash(self, profile_key="@DEFAULT@"): diff -r 6a0c6d8e119d -r 68cd30d982a5 src/plugins/plugin_xep_0163.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/plugin_xep_0163.py Thu Feb 03 18:06:25 2011 +0100 @@ -0,0 +1,82 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +SAT plugin for Personal Eventing Protocol (xep-0163) +Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +from logging import debug, info, error +from twisted.internet import protocol +from twisted.words.protocols.jabber import client, jid +from twisted.words.protocols.jabber import error as jab_error +import twisted.internet.error + +from wokkel import disco +from wokkel.formats import Mood + +NS_USER_MOOD = 'http://jabber.org/protocol/mood' + +PLUGIN_INFO = { +"name": "Personal Eventing Protocol Plugin", +"import_name": "XEP_0163", +"type": "XEP", +"protocols": ["XEP-0163", "XEP-0107"], +"dependencies": ["XEP-0060"], +"main": "XEP_0163", +"handler": "no", +"description": _("""Implementation of Personal Eventing Protocol""") +} + +class XEP_0163(): + + def __init__(self, host): + info(_("PEP plugin initialization")) + self.host = host + self.pep_events=set() + host.trigger.add("PubSub Disco Info", self.disoInfoTrigger) + host.bridge.addSignal("personalEvent", ".communication", signature='ssa{ss}s') #args: from (jid), type(MOOD, TUNE, etc), data, profile + self.addPEPEvent("MOOD", NS_USER_MOOD, self.userMoodCB) + + def disoInfoTrigger(self, disco_info, profile): + """Add info from managed PEP + @param disco_info: list of disco feature as returned by PubSub, + will be filled with PEP features + @param profile: profile we are handling""" + disco_info.extend(map(disco.DiscoFeature, self.pep_events)) + return True + + def addPEPEvent(self, event_type, name, callback): + """Add a Personal Eventing Protocol event manager + @param event_type: type of the event (always uppercase), can be MOOD, TUNE, etc + @param name: namespace of the node (e.g. http://jabber.org/protocol/mood for User Mood) + @param callback: method to call when this event occur""" + self.pep_events.add(name) + self.pep_events.add(name+"+notify") + self.host.plugins["XEP_0060"].addManagedNode(name, callback) + + def userMoodCB(self, itemsEvent, profile): + try: + mood_elem = filter(lambda x:x.name == "mood", itemsEvent.items[0].children)[0] + except KeyError: + error(_("Can't find mood element in mood event")) + return + _mood = Mood.fromXml(mood_elem) + if not _mood: + error(_("Error while parsing mood element")) + return + self.host.bridge.personalEvent(itemsEvent.sender.full(), "MOOD", {"mood":_mood.value or "", "text":_mood.text or ""}, profile) +