diff --git a/sat/plugins/plugin_xep_0166.py b/sat/plugins/plugin_xep_0166.py
index c7a55a7e..e7dd5355 100644
--- a/sat/plugins/plugin_xep_0166.py
+++ b/sat/plugins/plugin_xep_0166.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
-
-# SAT plugin for Jingle (XEP-0166)
+# SàT plugin for Jingle (XEP-0166)
# Copyright (C) 2009-2020 Jérôme Poisson (goffi@goffi.org)
# This program is free software: you can redistribute it and/or modify
@@ -17,25 +16,27 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+
+import uuid
+import time
+from collections import namedtuple
+from zope.interface import implementer
+from twisted.words.protocols.jabber import jid
+from twisted.internet import defer
+from twisted.internet import reactor
+from twisted.words.protocols.jabber import error
+from twisted.words.protocols.jabber import xmlstream
+from twisted.python import failure
+from wokkel import disco, iwokkel
+from sat.core import exceptions
from sat.core.i18n import _, D_
from sat.core.constants import Const as C
from sat.core.log import getLogger
from sat.tools import xml_tools
+from sat.tools import utils
+
log = getLogger(__name__)
-from sat.core import exceptions
-from twisted.words.protocols.jabber import jid
-from twisted.internet import defer
-from twisted.internet import reactor
-from wokkel import disco, iwokkel
-from twisted.words.protocols.jabber import error
-from twisted.words.protocols.jabber import xmlstream
-from twisted.python import failure
-from collections import namedtuple
-import uuid
-import time
-
-from zope.interface import implementer
IQ_SET = '/iq[@type="set"]'
@@ -757,7 +758,7 @@ class XEP_0166(object):
elt = content_data.pop(elt_name) if delete else content_data[elt_name]
else:
elt = force_element
- d = defer.maybeDeferred(
+ d = utils.asDeferred(
method, client, action, session, content_name, elt
)
defers_list.append(d)
@@ -846,7 +847,7 @@ class XEP_0166(object):
application = content_data["application"]
app_session_accept_cb = application.handler.jingleHandler
- app_d = defer.maybeDeferred(
+ app_d = utils.asDeferred(
app_session_accept_cb,
client,
XEP_0166.A_SESSION_INITIATE,
@@ -860,7 +861,7 @@ class XEP_0166(object):
transport = content_data["transport"]
transport_session_accept_cb = transport.handler.jingleHandler
- transport_d = defer.maybeDeferred(
+ transport_d = utils.asDeferred(
transport_session_accept_cb,
client,
XEP_0166.A_SESSION_INITIATE,
diff --git a/sat/plugins/plugin_xep_0231.py b/sat/plugins/plugin_xep_0231.py
index ec55b502..981f6c08 100644
--- a/sat/plugins/plugin_xep_0231.py
+++ b/sat/plugins/plugin_xep_0231.py
@@ -17,23 +17,24 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from sat.core.i18n import _
-from sat.core.constants import Const as C
-from sat.core import exceptions
-from sat.core.log import getLogger
-
-log = getLogger(__name__)
-from sat.tools import xml_tools
-from wokkel import disco, iwokkel
+import base64
+import time
+from pathlib import Path
+from functools import partial
from zope.interface import implementer
from twisted.python import failure
from twisted.words.protocols.jabber import xmlstream
from twisted.words.protocols.jabber import jid
from twisted.words.protocols.jabber import error as jabber_error
from twisted.internet import defer
-from functools import partial
-import base64
-import time
+from wokkel import disco, iwokkel
+from sat.tools import xml_tools
+from sat.core.i18n import _
+from sat.core.constants import Const as C
+from sat.core import exceptions
+from sat.core.log import getLogger
+
+log = getLogger(__name__)
PLUGIN_INFO = {
@@ -90,7 +91,7 @@ class XEP_0231(object):
PLUGIN_INFO[C.PI_IMPORT_NAME], cid, data_elt.getAttribute("type"), max_age
) as f:
- file_path = f.name
+ file_path = Path(f.name)
f.write(base64.b64decode(str(data_elt)))
return file_path
diff --git a/sat/plugins/plugin_xep_0234.py b/sat/plugins/plugin_xep_0234.py
index 14287180..bc4c24c1 100644
--- a/sat/plugins/plugin_xep_0234.py
+++ b/sat/plugins/plugin_xep_0234.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# SAT plugin for Jingle File Transfer (XEP-0234)
+# SàT plugin for Jingle File Transfer (XEP-0234)
# Copyright (C) 2009-2020 Jérôme Poisson (goffi@goffi.org)
# This program is free software: you can redistribute it and/or modify
@@ -181,7 +181,7 @@ class XEP_0234(object):
file_data.update(kwargs)
return self.buildFileElement(client, **file_data)
- def parseFileElement(
+ async def parseFileElement(
self, client, file_elt, file_data=None, given=False, parent_elt=None,
keep_empty_range=False):
"""Parse a element and file dictionary accordingly
@@ -451,7 +451,9 @@ class XEP_0234(object):
return desc_elt
- def jingleRequestConfirmation(self, client, action, session, content_name, desc_elt):
+ async def jingleRequestConfirmation(
+ self, client, action, session, content_name, desc_elt
+ ):
"""This method request confirmation for a jingle session"""
content_data = session["contents"][content_name]
senders = content_data["senders"]
@@ -467,21 +469,20 @@ class XEP_0234(object):
if senders == self._j.ROLE_RESPONDER:
# we send the file
- return self._fileSendingRequestConf(
+ return await self._fileSendingRequestConf(
client, session, content_data, content_name, file_data, file_elt
)
else:
# we receive the file
- return self._fileReceivingRequestConf(
+ return await self._fileReceivingRequestConf(
client, session, content_data, content_name, file_data, file_elt
)
- @defer.inlineCallbacks
- def _fileSendingRequestConf(
+ async def _fileSendingRequestConf(
self, client, session, content_data, content_name, file_data, file_elt
):
"""parse file_elt, and handle file retrieving/permission checking"""
- self.parseFileElement(client, file_elt, file_data)
+ await self.parseFileElement(client, file_elt, file_data)
content_data["application_data"]["file_data"] = file_data
finished_d = content_data["finished_d"] = defer.Deferred()
@@ -496,22 +497,22 @@ class XEP_0234(object):
file_elt,
)
if not cont:
- confirmed = yield confirmed_d
+ confirmed = await confirmed_d
if confirmed:
args = [client, session, content_name, content_data]
finished_d.addCallbacks(
self._finishedCb, self._finishedEb, args, None, args
)
- defer.returnValue(confirmed)
+ return confirmed
log.warning(_("File continue is not implemented yet"))
- defer.returnValue(False)
+ return False
- def _fileReceivingRequestConf(
+ async def _fileReceivingRequestConf(
self, client, session, content_data, content_name, file_data, file_elt
):
"""parse file_elt, and handle user permission/file opening"""
- self.parseFileElement(client, file_elt, file_data, given=True)
+ await self.parseFileElement(client, file_elt, file_data, given=True)
try:
hash_algo, file_data["given_file_hash"] = self._hash.parseHashElt(file_elt)
except exceptions.NotFound:
@@ -540,21 +541,18 @@ class XEP_0234(object):
content_data["application_data"]["file_data"] = file_data
# now we actualy request permission to user
- def gotConfirmation(confirmed):
- if confirmed:
- args = [client, session, content_name, content_data]
- finished_d.addCallbacks(
- self._finishedCb, self._finishedEb, args, None, args
- )
- return confirmed
# deferred to track end of transfer
finished_d = content_data["finished_d"] = defer.Deferred()
- d = self._f.getDestDir(
+ confirmed = await self._f.getDestDir(
client, session["peer_jid"], content_data, file_data, stream_object=True
)
- d.addCallback(gotConfirmation)
- return d
+ if confirmed:
+ args = [client, session, content_name, content_data]
+ finished_d.addCallbacks(
+ self._finishedCb, self._finishedEb, args, None, args
+ )
+ return confirmed
@defer.inlineCallbacks
def jingleHandler(self, client, action, session, content_name, desc_elt):
diff --git a/sat/plugins/plugin_xep_0329.py b/sat/plugins/plugin_xep_0329.py
index 810fef1c..6971e0bb 100644
--- a/sat/plugins/plugin_xep_0329.py
+++ b/sat/plugins/plugin_xep_0329.py
@@ -44,7 +44,7 @@ PLUGIN_INFO = {
C.PI_TYPE: "XEP",
C.PI_MODES: C.PLUG_MODE_BOTH,
C.PI_PROTOCOLS: ["XEP-0329"],
- C.PI_DEPENDENCIES: ["XEP-0234", "XEP-0300", "XEP-0106"],
+ C.PI_DEPENDENCIES: ["XEP-0231", "XEP-0234", "XEP-0300", "XEP-0106"],
C.PI_MAIN: "XEP_0329",
C.PI_HANDLER: "yes",
C.PI_DESCRIPTION: _("""Implementation of File Information Sharing"""),
@@ -272,6 +272,7 @@ class XEP_0329(object):
log.info(_("File Information Sharing initialization"))
self.host = host
ShareNode.host = host
+ self._b = host.plugins["XEP-0231"]
self._h = host.plugins["XEP-0300"]
self._jf = host.plugins["XEP-0234"]
host.bridge.addMethod(
@@ -672,7 +673,7 @@ class XEP_0329(object):
client, iq_elt, self._compGetRootNodesCb, self._compGetFilesFromNodeCb
)
- def _parseResult(self, iq_elt, client):
+ async def _parseResult(self, client, peer_jid, iq_elt):
query_elt = next(iq_elt.elements(NS_FIS, "query"))
files = []
@@ -680,10 +681,24 @@ class XEP_0329(object):
if elt.name == "file":
# we have a file
try:
- file_data = self._jf.parseFileElement(client, elt)
+ file_data = await self._jf.parseFileElement(client, elt)
except exceptions.DataError:
continue
file_data["type"] = C.FILE_TYPE_FILE
+ try:
+ thumbs = file_data['extra'][C.KEY_THUMBNAILS]
+ except KeyError:
+ log.debug(f"No thumbnail found for {file_data}")
+ else:
+ for thumb in thumbs:
+ if 'url' not in thumb and "id" in thumb:
+ try:
+ file_path = await self._b.getFile(client, peer_jid, thumb['id'])
+ except Exception as e:
+ log.warning(f"Can't get thumbnail {thumb['id']!r} for {file_data}: {e}")
+ else:
+ thumb['filename'] = file_path.name
+
elif elt.name == "directory" and elt.uri == NS_FIS:
# we have a directory
@@ -1018,27 +1033,26 @@ class XEP_0329(object):
def _listFiles(self, target_jid, path, extra, profile):
client = self.host.getClient(profile)
target_jid = client.jid if not target_jid else jid.JID(target_jid)
- d = self.listFiles(client, target_jid, path or None)
+ d = defer.ensureDeferred(self.listFiles(client, target_jid, path or None))
d.addCallback(self._serializeData)
return d
- def listFiles(self, client, target_jid, path=None, extra=None):
+ async def listFiles(self, client, peer_jid, path=None, extra=None):
"""List file shared by an entity
- @param target_jid(jid.JID): jid of the sharing entity
+ @param peer_jid(jid.JID): jid of the sharing entity
@param path(unicode, None): path to the directory containing shared files
None to get root directories
@param extra(dict, None): extra data
@return list(dict): shared files
"""
iq_elt = client.IQ("get")
- iq_elt["to"] = target_jid.full()
+ iq_elt["to"] = peer_jid.full()
query_elt = iq_elt.addElement((NS_FIS, "query"))
if path:
query_elt["node"] = path
- d = iq_elt.send()
- d.addCallback(self._parseResult, client)
- return d
+ iq_result_elt = await iq_elt.send()
+ return await self._parseResult(client, peer_jid, iq_result_elt)
def _localSharesGet(self, profile):
client = self.host.getClient(profile)