XEP-0065,XEP-0096,XEP-0166,XEP-0235,XEP-0300: file transfer improvments:

huge patch sorry :)

many things are improved by this patch, notably:
- updated to last protocol changes (urn:xmpp:jingle:apps:file-transfer:5 and urn:xmpp:hashes:2)
- XEP-0234: file request implementation
- XEP-0234: methods to parse and generate <file> element (can be used by other plugins easily)
- XEP-0234: range data is now in a namedtuple
- path and namespace can be specified when sending/requesting a file (not standard, but needed for file sharing)
- better error/termination handling
- trigger points to handle file requests by other plugins
- preparation to use file plugins with components
This commit is contained in:
Goffi 2018-02-28 18:28:39 +01:00
commit 2e5991575f

View file

@ -34,6 +34,7 @@ PLUGIN_INFO = {
C.PI_NAME: "File Tansfer",
C.PI_IMPORT_NAME: "FILE",
C.PI_TYPE: C.PLUG_TYPE_MISC,
C.PI_MODES: C.PLUG_MODE_BOTH,
C.PI_MAIN: "FilePlugin",
C.PI_HANDLER: "no",
C.PI_DESCRIPTION: _("""File Tansfer Management:
@ -58,16 +59,16 @@ class FilePlugin(object):
def __init__(self, host):
log.info(_("plugin File initialization"))
self.host = host
host.bridge.addMethod("fileSend", ".plugin", in_sign='sssss', out_sign='a{ss}', method=self._fileSend, async=True)
host.bridge.addMethod("fileSend", ".plugin", in_sign='ssssa{ss}s', out_sign='a{ss}', method=self._fileSend, async=True)
self._file_callbacks = []
host.importMenu((D_("Action"), D_("send file")), self._fileSendMenu, security_limit=10, help_string=D_("Send a file"), type_=C.MENU_SINGLE)
def _fileSend(self, peer_jid_s, filepath, name="", file_desc="", profile=C.PROF_KEY_NONE):
def _fileSend(self, peer_jid_s, filepath, name="", file_desc="", extra=None, profile=C.PROF_KEY_NONE):
client = self.host.getClient(profile)
return self.fileSend(client, jid.JID(peer_jid_s), filepath, name or None, file_desc or None)
return self.fileSend(client, jid.JID(peer_jid_s), filepath, name or None, file_desc or None, extra)
@defer.inlineCallbacks
def fileSend(self, client, peer_jid, filepath, filename=None, file_desc=None):
def fileSend(self, client, peer_jid, filepath, filename=None, file_desc=None, extra=None):
"""Send a file using best available method
@param peer_jid(jid.JID): jid of the destinee
@ -85,7 +86,7 @@ class FilePlugin(object):
has_feature = yield self.host.hasFeature(client, namespace, peer_jid)
if has_feature:
log.info(u"{name} method will be used to send the file".format(name=method_name))
progress_id = yield callback(client, peer_jid, filepath, filename, file_desc)
progress_id = yield callback(client, peer_jid, filepath, filename, file_desc, extra)
defer.returnValue({'progress': progress_id})
msg = u"Can't find any method to send file to {jid}".format(jid=peer_jid.full())
log.warning(msg)
@ -143,7 +144,9 @@ class FilePlugin(object):
# Dialogs with user
# the overwrite check is done here
def _openFileWrite(self, client, file_path, transfer_data, file_data, stream_object):
def openFileWrite(self, client, file_path, transfer_data, file_data, stream_object):
"""create SatFile or FileStremaObject for the requested file and fill suitable data
"""
if stream_object:
assert 'stream_object' not in transfer_data
transfer_data['stream_object'] = stream.FileStreamObject(
@ -188,7 +191,7 @@ class FilePlugin(object):
if os.path.exists(file_path):
def check_overwrite(overwrite):
if overwrite:
self._openFileWrite(client, file_path, transfer_data, file_data, stream_object)
self.openFileWrite(client, file_path, transfer_data, file_data, stream_object)
return True
else:
return self.getDestDir(client, peer_jid, transfer_data, file_data)
@ -206,7 +209,7 @@ class FilePlugin(object):
exists_d.addCallback(check_overwrite)
return exists_d
self._openFileWrite(client, file_path, transfer_data, file_data, stream_object)
self.openFileWrite(client, file_path, transfer_data, file_data, stream_object)
return True
def getDestDir(self, client, peer_jid, transfer_data, file_data, stream_object=False):
@ -236,6 +239,9 @@ class FilePlugin(object):
a stream.FileStreamObject will be used
return (defer.Deferred): True if transfer is accepted
"""
cont,ret_value = self.host.trigger.returnPoint("FILE_getDestDir", client, peer_jid, transfer_data, file_data, stream_object)
if not cont:
return ret_value
filename = file_data['name']
assert filename and not '/' in filename
assert PROGRESS_ID_KEY in file_data