Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0231.py @ 3028:ab2696e34d29
Python 3 port:
/!\ this is a huge commit
/!\ starting from this commit, SàT is needs Python 3.6+
/!\ SàT maybe be instable or some feature may not work anymore, this will improve with time
This patch port backend, bridge and frontends to Python 3.
Roughly this has been done this way:
- 2to3 tools has been applied (with python 3.7)
- all references to python2 have been replaced with python3 (notably shebangs)
- fixed files not handled by 2to3 (notably the shell script)
- several manual fixes
- fixed issues reported by Python 3 that where not handled in Python 2
- replaced "async" with "async_" when needed (it's a reserved word from Python 3.7)
- replaced zope's "implements" with @implementer decorator
- temporary hack to handle data pickled in database, as str or bytes may be returned,
to be checked later
- fixed hash comparison for password
- removed some code which is not needed anymore with Python 3
- deactivated some code which needs to be checked (notably certificate validation)
- tested with jp, fixed reported issues until some basic commands worked
- ported Primitivus (after porting dependencies like urwid satext)
- more manual fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 19:08:41 +0200 |
parents | 003b8b4b56a7 |
children | 9d0df638c8b4 |
comparison
equal
deleted
inserted
replaced
3027:ff5bcb12ae60 | 3028:ab2696e34d29 |
---|---|
1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python3 |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 | 3 |
4 # SAT plugin for Bit of Binary handling (XEP-0231) | 4 # SAT plugin for Bit of Binary handling (XEP-0231) |
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) | 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) |
6 | 6 |
23 from sat.core.log import getLogger | 23 from sat.core.log import getLogger |
24 | 24 |
25 log = getLogger(__name__) | 25 log = getLogger(__name__) |
26 from sat.tools import xml_tools | 26 from sat.tools import xml_tools |
27 from wokkel import disco, iwokkel | 27 from wokkel import disco, iwokkel |
28 from zope.interface import implements | 28 from zope.interface import implementer |
29 from twisted.python import failure | 29 from twisted.python import failure |
30 from twisted.words.protocols.jabber import xmlstream | 30 from twisted.words.protocols.jabber import xmlstream |
31 from twisted.words.protocols.jabber import jid | 31 from twisted.words.protocols.jabber import jid |
32 from twisted.words.protocols.jabber import error as jabber_error | 32 from twisted.words.protocols.jabber import error as jabber_error |
33 from twisted.internet import defer | 33 from twisted.internet import defer |
47 C.PI_DESCRIPTION: _( | 47 C.PI_DESCRIPTION: _( |
48 """Implementation of bits of binary (used for small images/files)""" | 48 """Implementation of bits of binary (used for small images/files)""" |
49 ), | 49 ), |
50 } | 50 } |
51 | 51 |
52 NS_BOB = u"urn:xmpp:bob" | 52 NS_BOB = "urn:xmpp:bob" |
53 IQ_BOB_REQUEST = C.IQ_GET + '/data[@xmlns="' + NS_BOB + '"]' | 53 IQ_BOB_REQUEST = C.IQ_GET + '/data[@xmlns="' + NS_BOB + '"]' |
54 | 54 |
55 | 55 |
56 class XEP_0231(object): | 56 class XEP_0231(object): |
57 def __init__(self, host): | 57 def __init__(self, host): |
58 log.info(_(u"plugin Bits of Binary initialization")) | 58 log.info(_("plugin Bits of Binary initialization")) |
59 self.host = host | 59 self.host = host |
60 host.registerNamespace("bob", NS_BOB) | 60 host.registerNamespace("bob", NS_BOB) |
61 host.trigger.add("xhtml_post_treat", self.XHTMLTrigger) | 61 host.trigger.add("xhtml_post_treat", self.XHTMLTrigger) |
62 host.bridge.addMethod( | 62 host.bridge.addMethod( |
63 "bobGetFile", | 63 "bobGetFile", |
64 ".plugin", | 64 ".plugin", |
65 in_sign="sss", | 65 in_sign="sss", |
66 out_sign="s", | 66 out_sign="s", |
67 method=self._getFile, | 67 method=self._getFile, |
68 async=True, | 68 async_=True, |
69 ) | 69 ) |
70 | 70 |
71 def dumpData(self, cache, data_elt, cid): | 71 def dumpData(self, cache, data_elt, cid): |
72 """save file encoded in data_elt to cache | 72 """save file encoded in data_elt to cache |
73 | 73 |
81 try: | 81 try: |
82 max_age = int(data_elt["max-age"]) | 82 max_age = int(data_elt["max-age"]) |
83 if max_age < 0: | 83 if max_age < 0: |
84 raise ValueError | 84 raise ValueError |
85 except (KeyError, ValueError): | 85 except (KeyError, ValueError): |
86 log.warning(u"invalid max-age found") | 86 log.warning("invalid max-age found") |
87 max_age = None | 87 max_age = None |
88 | 88 |
89 with cache.cacheData( | 89 with cache.cacheData( |
90 PLUGIN_INFO[C.PI_IMPORT_NAME], cid, data_elt.getAttribute("type"), max_age | 90 PLUGIN_INFO[C.PI_IMPORT_NAME], cid, data_elt.getAttribute("type"), max_age |
91 ) as f: | 91 ) as f: |
97 | 97 |
98 def getHandler(self, client): | 98 def getHandler(self, client): |
99 return XEP_0231_handler(self) | 99 return XEP_0231_handler(self) |
100 | 100 |
101 def _requestCb(self, iq_elt, cache, cid): | 101 def _requestCb(self, iq_elt, cache, cid): |
102 for data_elt in iq_elt.elements(NS_BOB, u"data"): | 102 for data_elt in iq_elt.elements(NS_BOB, "data"): |
103 if data_elt.getAttribute("cid") == cid: | 103 if data_elt.getAttribute("cid") == cid: |
104 file_path = self.dumpData(cache, data_elt, cid) | 104 file_path = self.dumpData(cache, data_elt, cid) |
105 return file_path | 105 return file_path |
106 | 106 |
107 log.warning( | 107 log.warning( |
108 u"invalid data stanza received, requested cid was not found:\n{iq_elt}\nrequested cid: {cid}".format( | 108 "invalid data stanza received, requested cid was not found:\n{iq_elt}\nrequested cid: {cid}".format( |
109 iq_elt=iq_elt, cid=cid | 109 iq_elt=iq_elt, cid=cid |
110 ) | 110 ) |
111 ) | 111 ) |
112 raise failure.Failure(exceptions.DataError("missing data")) | 112 raise failure.Failure(exceptions.DataError("missing data")) |
113 | 113 |
114 def _requestEb(self, failure_): | 114 def _requestEb(self, failure_): |
115 """Log the error and continue errback chain""" | 115 """Log the error and continue errback chain""" |
116 log.warning(u"Can't get requested data:\n{reason}".format(reason=failure_)) | 116 log.warning("Can't get requested data:\n{reason}".format(reason=failure_)) |
117 return failure_ | 117 return failure_ |
118 | 118 |
119 def requestData(self, client, to_jid, cid, cache=None): | 119 def requestData(self, client, to_jid, cid, cache=None): |
120 """Request data if we don't have it in cache | 120 """Request data if we don't have it in cache |
121 | 121 |
135 d.addCallback(self._requestCb, cache, cid) | 135 d.addCallback(self._requestCb, cache, cid) |
136 d.addErrback(self._requestEb) | 136 d.addErrback(self._requestEb) |
137 return d | 137 return d |
138 | 138 |
139 def _setImgEltSrc(self, path, img_elt): | 139 def _setImgEltSrc(self, path, img_elt): |
140 img_elt[u"src"] = u"file://{}".format(path) | 140 img_elt["src"] = "file://{}".format(path) |
141 | 141 |
142 def XHTMLTrigger(self, client, message_elt, body_elt, lang, treat_d): | 142 def XHTMLTrigger(self, client, message_elt, body_elt, lang, treat_d): |
143 for img_elt in xml_tools.findAll(body_elt, C.NS_XHTML, u"img"): | 143 for img_elt in xml_tools.findAll(body_elt, C.NS_XHTML, "img"): |
144 source = img_elt.getAttribute(u"src", "") | 144 source = img_elt.getAttribute("src", "") |
145 if source.startswith(u"cid:"): | 145 if source.startswith("cid:"): |
146 cid = source[4:] | 146 cid = source[4:] |
147 file_path = client.cache.getFilePath(cid) | 147 file_path = client.cache.getFilePath(cid) |
148 if file_path is not None: | 148 if file_path is not None: |
149 # image is in cache, we change the url | 149 # image is in cache, we change the url |
150 img_elt[u"src"] = u"file://{}".format(file_path) | 150 img_elt["src"] = "file://{}".format(file_path) |
151 continue | 151 continue |
152 else: | 152 else: |
153 # image is not in cache, is it given locally? | 153 # image is not in cache, is it given locally? |
154 for data_elt in message_elt.elements(NS_BOB, u"data"): | 154 for data_elt in message_elt.elements(NS_BOB, "data"): |
155 if data_elt.getAttribute("cid") == cid: | 155 if data_elt.getAttribute("cid") == cid: |
156 file_path = self.dumpData(client.cache, data_elt, cid) | 156 file_path = self.dumpData(client.cache, data_elt, cid) |
157 img_elt[u"src"] = u"file://{}".format(file_path) | 157 img_elt["src"] = "file://{}".format(file_path) |
158 break | 158 break |
159 else: | 159 else: |
160 # cid not found locally, we need to request it | 160 # cid not found locally, we need to request it |
161 # so we use the deferred | 161 # so we use the deferred |
162 d = self.requestData(client, jid.JID(message_elt["from"]), cid) | 162 d = self.requestData(client, jid.JID(message_elt["from"]), cid) |
170 # An access check should be implemented though. | 170 # An access check should be implemented though. |
171 | 171 |
172 iq_elt.handled = True | 172 iq_elt.handled = True |
173 data_elt = next(iq_elt.elements(NS_BOB, "data")) | 173 data_elt = next(iq_elt.elements(NS_BOB, "data")) |
174 try: | 174 try: |
175 cid = data_elt[u"cid"] | 175 cid = data_elt["cid"] |
176 except KeyError: | 176 except KeyError: |
177 error_elt = jabber_error.StanzaError("not-acceptable").toResponse(iq_elt) | 177 error_elt = jabber_error.StanzaError("not-acceptable").toResponse(iq_elt) |
178 client.send(error_elt) | 178 client.send(error_elt) |
179 return | 179 return |
180 | 180 |
187 with open(metadata["path"]) as f: | 187 with open(metadata["path"]) as f: |
188 data = f.read() | 188 data = f.read() |
189 | 189 |
190 result_elt = xmlstream.toResponse(iq_elt, "result") | 190 result_elt = xmlstream.toResponse(iq_elt, "result") |
191 data_elt = result_elt.addElement((NS_BOB, "data"), content=data.encode("base64")) | 191 data_elt = result_elt.addElement((NS_BOB, "data"), content=data.encode("base64")) |
192 data_elt[u"cid"] = cid | 192 data_elt["cid"] = cid |
193 data_elt[u"type"] = metadata[u"mime_type"] | 193 data_elt["type"] = metadata["mime_type"] |
194 data_elt[u"max-age"] = unicode(int(max(0, metadata["eol"] - time.time()))) | 194 data_elt["max-age"] = str(int(max(0, metadata["eol"] - time.time()))) |
195 client.send(result_elt) | 195 client.send(result_elt) |
196 | 196 |
197 def _getFile(self, peer_jid_s, cid, profile): | 197 def _getFile(self, peer_jid_s, cid, profile): |
198 peer_jid = jid.JID(peer_jid_s) | 198 peer_jid = jid.JID(peer_jid_s) |
199 assert cid | 199 assert cid |
215 # file is in cache | 215 # file is in cache |
216 return defer.succeed(file_path) | 216 return defer.succeed(file_path) |
217 else: | 217 else: |
218 # file not in cache, is it given locally? | 218 # file not in cache, is it given locally? |
219 if parent_elt is not None: | 219 if parent_elt is not None: |
220 for data_elt in parent_elt.elements(NS_BOB, u"data"): | 220 for data_elt in parent_elt.elements(NS_BOB, "data"): |
221 if data_elt.getAttribute("cid") == cid: | 221 if data_elt.getAttribute("cid") == cid: |
222 return defer.succeed(self.dumpData(client.cache, data_elt, cid)) | 222 return defer.succeed(self.dumpData(client.cache, data_elt, cid)) |
223 | 223 |
224 # cid not found locally, we need to request it | 224 # cid not found locally, we need to request it |
225 # so we use the deferred | 225 # so we use the deferred |
226 return self.requestData(client, peer_jid, cid) | 226 return self.requestData(client, peer_jid, cid) |
227 | 227 |
228 | 228 |
229 @implementer(iwokkel.IDisco) | |
229 class XEP_0231_handler(xmlstream.XMPPHandler): | 230 class XEP_0231_handler(xmlstream.XMPPHandler): |
230 implements(iwokkel.IDisco) | |
231 | 231 |
232 def __init__(self, plugin_parent): | 232 def __init__(self, plugin_parent): |
233 self.plugin_parent = plugin_parent | 233 self.plugin_parent = plugin_parent |
234 self.host = plugin_parent.host | 234 self.host = plugin_parent.host |
235 | 235 |