comparison src/plugins/plugin_xep_0059.py @ 1219:16484ebb695b

plugin XEP-0059: first draft, pubsub and jabber search do not exploit it yet
author souliane <souliane@mailoo.org>
date Mon, 22 Sep 2014 22:25:44 +0200
parents
children ea692d51a0ee
comparison
equal deleted inserted replaced
1218:3b1c5f723c4b 1219:16484ebb695b
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # SAT plugin for Result Set Management (XEP-0059)
5 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org)
6 # Copyright (C) 2013, 2014 Adrien Cossa (souliane@mailoo.org)
7
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU Affero General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU Affero General Public License for more details.
17
18 # You should have received a copy of the GNU Affero General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21 from sat.core.i18n import _
22 from sat.core.log import getLogger
23 log = getLogger(__name__)
24
25 from twisted.words.xish import domish
26 from wokkel import disco, iwokkel
27 try:
28 from twisted.words.protocols.xmlstream import XMPPHandler
29 except ImportError:
30 from wokkel.subprotocols import XMPPHandler
31 from zope.interface import implements
32
33
34 NS_RSM = 'http://jabber.org/protocol/rsm'
35
36 PLUGIN_INFO = {
37 "name": "Result Set Management",
38 "import_name": "XEP-0059",
39 "type": "XEP",
40 "protocols": ["XEP-0059"],
41 "main": "XEP_0059",
42 "handler": "no",
43 "description": _("""Implementation of Result Set Management""")
44 }
45
46
47 class XEP_0059(object):
48
49 def __init__(self, host):
50 log.info(_("Result Set Management plugin initialization"))
51 self.host = host
52
53 def requestPage(self, stanza, limit=10, index=None, after=None, before=None):
54 """Embed a RSM page request in the given stanza.
55
56 @param stanza (domish.Element): any stanza to which RSM applies
57 @param limit (int): the maximum number of items in the page
58 @param index (int): the starting index of the requested page
59 @param after (str, int): the element immediately preceding the page
60 @param before (str, int): the element immediately following the page
61 """
62 main_elt = None
63 try:
64 main_elt = domish.generateElementsNamed(stanza.elements(), name="query").next()
65 except StopIteration:
66 try:
67 main_elt = domish.generateElementsNamed(stanza.elements(), name="pubsub").next()
68 except StopIteration:
69 log.warning("Injection of a RSM element only applies to query or pubsub stanzas")
70 return
71 limit = str(int(limit))
72
73 # in case the service doesn't support RSM, do this at least
74 main_elt.items.attributes['max_items'] = limit
75
76 set_elt = main_elt.addElement('set', NS_RSM)
77 set_elt.addElement('max').addContent(limit)
78 if index:
79 assert(after is None and before is None)
80 set_elt.addElement('index').addContent(str(int(index)))
81 if after:
82 assert(before is None) # could not specify both at the same time
83 set_elt.addElement('after').addContent(str(after))
84 if before is not None:
85 if before == '': # request the last page, according to http://xmpp.org/extensions/xep-0059.html#last
86 set_elt.addElement('before')
87 else:
88 set_elt.addElement('before').addContent(str(before))
89
90 def countItems(self, stanza):
91 """Count the items without retrieving any of them.
92
93 @param stanza (domish.Element): any stanza to which RSM applies
94 """
95 self.requestPage(stanza, limit=0)
96
97 def extractMetadata(self, stanza):
98 """Extract the RSM metadata from the given stanza.
99
100 @param stanza (domish.Element, wokkel.pubsub.PubSubRequest):
101 any stanza to which RSM applies. When used by XEP-0060,
102 wokkel's PubSubRequest instance is also accepted.
103 @return: dict containing the page metadata
104 """
105 try:
106 main_elt = domish.generateElementsNamed(stanza.elements(), name="query").next()
107 except StopIteration:
108 try:
109 main_elt = domish.generateElementsNamed(stanza.elements(), name="pubsub").next()
110 except StopIteration:
111 log.warning("Extracting data from a RSM element only applies to query or pubsub stanzas")
112 return {}
113 try:
114 set_elt = domish.generateElementsQNamed(main_elt.elements(), name="set", uri=NS_RSM).next()
115 except StopIteration:
116 log.debug("There's no RSM element in the stanza")
117 return {}
118
119 data = {}
120 elts = set_elt.elements()
121 try:
122 elt = elts.next()
123 if elt.name == "first":
124 data["first"] = "".join(elt.children)
125 data["first_index"] = int(elt.getAttribute("index"))
126 elif elt.name == "last":
127 data["last"] = "".join(elt.children)
128 elif elt.name == "count":
129 data["count"] = int("".join(elt.children))
130 except StopIteration:
131 pass
132 if "count" not in data:
133 log.warning("There's no 'count' element in the RSM element!")
134 return data
135
136
137 class XEP_0059_handler(XMPPHandler):
138 implements(iwokkel.IDisco)
139
140 def __init__(self, plugin_parent, profile):
141 self.plugin_parent = plugin_parent
142 self.host = plugin_parent.host
143 self.profile = profile
144
145 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
146 return [disco.DiscoFeature(NS_RSM)]
147
148 def getDiscoItems(self, requestor, target, nodeIdentifier=''):
149 return []