Mercurial > libervia-backend
annotate src/plugins/plugin_xep_0313.py @ 1284:41ffe2c2dddc
plugin XEP-0313: update (still draft)
author | souliane <souliane@mailoo.org> |
---|---|
date | Fri, 09 Jan 2015 10:51:12 +0100 |
parents | 3a3e3014f9f8 |
children | ed2c718bfe03 |
rev | line source |
---|---|
1277 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # SAT plugin for Message Archive Management (XEP-0313) | |
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.constants import Const as C | |
22 from sat.core.i18n import _ | |
23 from sat.core.log import getLogger | |
24 log = getLogger(__name__) | |
25 | |
26 try: | |
27 from twisted.words.protocols.xmlstream import XMPPHandler | |
28 except ImportError: | |
29 from wokkel.subprotocols import XMPPHandler | |
30 from twisted.words.xish import domish | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
31 from twisted.words.protocols.jabber import jid |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
32 |
1277 | 33 from zope.interface import implements |
34 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
35 from wokkel import disco, data_form, mam |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
36 from wokkel.rsm import RSMRequest |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
37 from wokkel.generic import parseXml |
1277 | 38 |
39 | |
40 NS_MAM = 'urn:xmpp:mam:0' | |
41 NS_SF = 'urn:xmpp:forward:0' | |
42 NS_DD = 'urn:xmpp:delay' | |
43 NS_CLIENT = 'jabber:client' | |
44 | |
45 PLUGIN_INFO = { | |
46 "name": "Message Archive Management", | |
47 "import_name": "XEP-0313", | |
48 "type": "XEP", | |
49 "protocols": ["XEP-0313"], | |
50 "dependencies": ["XEP-0059", "XEP-0297", "XEP-0203"], | |
51 "recommendations": ["XEP-0334"], | |
52 "main": "XEP_0313", | |
53 "handler": "yes", | |
54 "description": _("""Implementation of Message Archive Management""") | |
55 } | |
56 | |
57 | |
58 class XEP_0313(object): | |
59 | |
60 def __init__(self, host): | |
61 log.info(_("Message Archive Management plugin initialization")) | |
62 self.host = host | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
63 self.clients = {} # bind profile name to SatMAMClient |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
64 host.bridge.addMethod("MAMqueryFields", ".plugin", in_sign='ss', out_sign='s', |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
65 method=self._queryFields, |
1277 | 66 async=True, |
67 doc={}) | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
68 host.bridge.addMethod("MAMqueryArchive", ".plugin", in_sign='ssa{ss}ss', out_sign='s', |
1277 | 69 method=self._queryArchive, |
70 async=True, | |
71 doc={}) | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
72 host.bridge.addMethod("MAMgetPrefs", ".plugin", in_sign='ss', out_sign='s', |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
73 method=self._getPrefs, |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
74 async=True, |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
75 doc={}) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
76 host.bridge.addMethod("MAMsetPrefs", ".plugin", in_sign='ssasass', out_sign='s', |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
77 method=self._setPrefs, |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
78 async=True, |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
79 doc={}) |
1277 | 80 host.trigger.add("MessageReceived", self.messageReceivedTrigger) |
81 | |
82 def getHandler(self, profile): | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
83 self.clients[profile] = SatMAMClient(self, profile) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
84 return self.clients[profile] |
1277 | 85 |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
86 def profileDisconnected(self, profile): |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
87 try: |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
88 del self.clients[profile] |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
89 except KeyError: |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
90 pass |
1277 | 91 |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
92 def _queryFields(self, service_s=None, profile_key=C.PROF_KEY_NONE): |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
93 service = jid.JID(service_s) if service_s else None |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
94 return self.queryFields(service, profile_key) |
1277 | 95 |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
96 def queryFields(self, service=None, profile_key=C.PROF_KEY_NONE): |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
97 """Ask the server about additional supported fields. |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
98 |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
99 @param service: entity offering the MAM service (None for user archives) |
1277 | 100 @param profile_key (unicode): %(doc_profile_key)s |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
101 @return: the server response as a Deferred domish.Element |
1277 | 102 """ |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
103 # http://xmpp.org/extensions/xep-0313.html#query-form |
1277 | 104 def eb(failure): |
105 # typically StanzaError with condition u'service-unavailable' | |
106 log.error(failure.getErrorMessage()) | |
107 return '' | |
108 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
109 profile = self.host.memory.getProfileName(profile_key) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
110 d = self.clients[profile].queryFields(service) |
1277 | 111 return d.addCallbacks(lambda elt: elt.toXml(), eb) |
112 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
113 def _queryArchive(self, service_s=None, form_xml=None, rsm_dict=None, node=None, profile_key=C.PROF_KEY_NONE): |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
114 service = jid.JID(service_s) if service_s else None |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
115 if form_xml: |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
116 form = data_form.Form.fromElement(parseXml(form_xml)) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
117 if form.formNamespace != NS_MAM: |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
118 log.error(_("Expected a MAM Data Form, got instead: %s") % form.formNamespace) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
119 form = None |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
120 else: |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
121 form = None |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
122 rsm = RSMRequest(**rsm_dict) if rsm_dict else None |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
123 return self.queryArchive(service, form, rsm, node, profile_key) |
1277 | 124 |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
125 def queryArchive(self, service=None, form=None, rsm=None, node=None, profile_key=C.PROF_KEY_NONE): |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
126 """Query a user, MUC or pubsub archive. |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
127 |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
128 @param service: entity offering the MAM service (None for user archives) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
129 @param form (Form): data form to filter the request |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
130 @param rsm (RSMRequest): RSM request instance |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
131 @param node (unicode): pubsub node to query, or None if inappropriate |
1277 | 132 @param profile_key (unicode): %(doc_profile_key)s |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
133 @return: a Deferred when the message has been sent |
1277 | 134 """ |
135 def eb(failure): | |
136 # typically StanzaError with condition u'service-unavailable' | |
137 log.error(failure.getErrorMessage()) | |
138 return '' | |
139 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
140 profile = self.host.memory.getProfileName(profile_key) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
141 d = self.clients[profile].queryArchive(service, form, rsm, node) |
1277 | 142 return d.addCallbacks(lambda elt: elt.toXml(), eb) |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
143 # TODO: add the handler for receiving the final message |
1277 | 144 |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
145 def _getPrefs(self, service_s=None, profile_key=C.PROF_KEY_NONE): |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
146 service = jid.JID(service_s) if service_s else None |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
147 return self.getPrefs(service, profile_key) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
148 |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
149 def getPrefs(self, service=None, profile_key=C.PROF_KEY_NONE): |
1277 | 150 """Retrieve the current user preferences. |
151 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
152 @param service: entity offering the MAM service (None for user archives) |
1277 | 153 @param profile_key (unicode): %(doc_profile_key)s |
154 @return: the server response as a Deferred domish.Element | |
155 """ | |
156 # http://xmpp.org/extensions/xep-0313.html#prefs | |
157 def eb(failure): | |
158 # typically StanzaError with condition u'service-unavailable' | |
159 log.error(failure.getErrorMessage()) | |
160 return '' | |
161 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
162 profile = self.host.memory.getProfileName(profile_key) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
163 d = self.clients[profile].queryPrefs(service) |
1277 | 164 return d.addCallbacks(lambda elt: elt.toXml(), eb) |
165 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
166 def _setPrefs(self, service_s=None, default='roster', always=None, never=None, profile_key=C.PROF_KEY_NONE): |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
167 service = jid.JID(service_s) if service_s else None |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
168 always_jid = [jid.JID(entity) for entity in always] |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
169 never_jid = [jid.JID(entity) for entity in never] |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
170 #TODO: why not build here a MAMPrefs object instead of passing the args separately? |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
171 return self.setPrefs(service, default, always_jid, never_jid, profile_key) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
172 |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
173 def setPrefs(self, service=None, default='roster', always=None, never=None, profile_key=C.PROF_KEY_NONE): |
1277 | 174 """Set news user preferences. |
175 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
176 @param service: entity offering the MAM service (None for user archives) |
1277 | 177 @param default (unicode): a value in ('always', 'never', 'roster') |
178 @param always (list): a list of JID instances | |
179 @param never (list): a list of JID instances | |
180 @param profile_key (unicode): %(doc_profile_key)s | |
181 @return: the server response as a Deferred domish.Element | |
182 """ | |
183 # http://xmpp.org/extensions/xep-0313.html#prefs | |
184 def eb(failure): | |
185 # typically StanzaError with condition u'service-unavailable' | |
186 log.error(failure.getErrorMessage()) | |
187 return '' | |
188 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
189 profile = self.host.memory.getProfileName(profile_key) |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
190 d = self.clients[profile].setPrefs(service, default, always, never) |
1277 | 191 return d.addCallbacks(lambda elt: elt.toXml(), eb) |
192 | |
193 def messageReceivedTrigger(self, message, post_treat, profile): | |
194 """Check if the message is a MAM result. If so, extract the original | |
195 message, stop processing the current message and process the original | |
196 message instead. | |
197 """ | |
198 try: | |
199 result = domish.generateElementsQNamed(message.elements(), "result", NS_MAM).next() | |
200 except StopIteration: | |
201 return True | |
202 try: | |
203 forwarded = domish.generateElementsQNamed(result.elements(), "forwarded", NS_SF).next() | |
204 except StopIteration: | |
205 log.error(_("MAM result misses its <forwarded/> mandatory element!")) | |
206 return False | |
207 try: | |
208 # TODO: delay is not here for nothing, get benefice of it! | |
209 delay = domish.generateElementsQNamed(forwarded.elements(), "delay", NS_DD).next() | |
210 msg = domish.generateElementsQNamed(forwarded.elements(), "message", NS_CLIENT).next() | |
211 except StopIteration: | |
212 log.error(_("<forwarded/> element misses a mandatory child!")) | |
213 return False | |
214 log.debug(_("MAM found a forwarded message")) | |
215 client = self.host.getClient(profile) | |
216 client.messageProt.onMessage(msg) | |
217 return False | |
218 | |
219 | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
220 class SatMAMClient(mam.MAMClient): |
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
221 implements(disco.IDisco) |
1277 | 222 |
223 def __init__(self, plugin_parent, profile): | |
224 self.plugin_parent = plugin_parent | |
225 self.host = plugin_parent.host | |
226 self.profile = profile | |
1284
41ffe2c2dddc
plugin XEP-0313: update (still draft)
souliane <souliane@mailoo.org>
parents:
1277
diff
changeset
|
227 mam.MAMClient.__init__(self) |
1277 | 228 |
229 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | |
230 return [disco.DiscoFeature(NS_MAM)] | |
231 | |
232 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | |
233 return [] |