diff --git a/src/plugins/plugin_misc_file.py b/src/plugins/plugin_misc_file.py
index 28d40f8f..4d036b7b 100644
--- a/src/plugins/plugin_misc_file.py
+++ b/src/plugins/plugin_misc_file.py
@@ -17,12 +17,13 @@
# 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.i18n import _, D_
from sat.core.constants import Const as C
from sat.core.log import getLogger
log = getLogger(__name__)
-import os
+from sat.tools import xml_tools
from twisted.internet import defer
+import os
import uuid
@@ -37,6 +38,12 @@ This plugin manage the various ways of sending a file, and choose the best one."
}
+CONFIRM = D_(u'{peer} wants to send the file "{name}" to you:\n{desc}\n\nThe file has a size of {size_human}\n\nDo you accept ?')
+CONFIRM_TITLE = D_(u'Confirm file transfer')
+CONFIRM_OVERWRITE = D_(u'File {} already exists, are you sure you want to overwrite ?')
+CONFIRM_OVERWRITE_TITLE = D_(u'File exists')
+
+
class SatFile(object):
"""A file-like object to have high level files manipulation"""
# TODO: manage "with" statement
@@ -94,4 +101,85 @@ class FilePlugin(object):
log.info(_("plugin File initialization"))
self.host = host
+ # Dialogs with user
+ # the overwrite check is done here
+ def _openFileWrite(self, file_path, transfer_data, file_data, profile):
+ assert 'file_obj' not in transfer_data
+ transfer_data['file_obj'] = SatFile(
+ self.host,
+ file_path,
+ 'w',
+ size=file_data['size'],
+ profile=profile,
+ )
+
+ def _gotConfirmation(self, data, peer_jid, transfer_data, file_data, profile):
+ """Called when the permission and dest path have been received
+
+ @param peer_jid(jid.JID): jid of the file sender
+ @param transfer_data(dict): same as for [self.getDestDir]
+ @param file_data(dict): same as for [self.getDestDir]
+ @param profile: %(doc_profile)s
+ return (bool): True if copy is wanted and OK
+ False if user wants to cancel
+ if file exists ask confirmation and call again self._getDestDir if needed
+ """
+ if data.get('cancelled', False):
+ return False
+ path = data['path']
+ file_data['file_path'] = file_path = os.path.join(path, file_data['name'])
+ log.debug(u'destination file path set to {}'.format(file_path))
+
+ # we manage case where file already exists
+ if os.path.exists(file_path):
+ def check_overwrite(overwrite):
+ if overwrite:
+ self._openFileWrite(file_path, transfer_data, file_data, profile)
+ return True
+ else:
+ return self.getDestDir(peer_jid, transfer_data, file_data, profile)
+
+ exists_d = xml_tools.deferConfirm(
+ self.host,
+ _(CONFIRM_OVERWRITE).format(file_path),
+ _(CONFIRM_OVERWRITE_TITLE),
+ profile=profile)
+ exists_d.addCallback(check_overwrite)
+ return exists_d
+
+ self._openFileWrite(file_path, transfer_data, file_data, profile)
+ return True
+
+ def getDestDir(self, peer_jid, transfer_data, file_data, profile):
+ """Request confirmation and destination dir to user
+
+ Overwrite confirmation is managed.
+ if transfer is confirmed, 'file_obj' is added to transfer_data
+ @param peer_jid(jid.JID): jid of the file sender
+ @param filename(unicode): name of the file
+ @param transfer_data(dict): data of the transfer session,
+ it will be only used to store the file_obj.
+ "file_obj" key *MUST NOT* exist before using getDestDir
+ @param file_data(dict): information about the file to be transfered
+ It MUST contain the following keys:
+ - peer_jid (jid.JID): other peer jid
+ - name (unicode): name of the file to trasnsfer
+ the name must not be empty or contain a "/" character
+ - size (int): size of the file
+ It may content the key used in CONFIRM constant
+ It *MUST NOT* contain the "peer" key
+ "file_path" will be added to this dict once destination selected
+ @param profile: %(doc_profile)s
+ return (defer.Deferred): True if transfer is accepted
+ """
+ filename = file_data['name']
+ assert filename and not '/' in filename
+ d = xml_tools.deferDialog(self.host,
+ _(CONFIRM).format(peer=peer_jid.full(), **file_data),
+ _(CONFIRM_TITLE),
+ type_=C.XMLUI_DIALOG_FILE,
+ options={C.XMLUI_DATA_FILETYPE: C.XMLUI_DATA_FILETYPE_DIR},
+ profile=profile)
+ d.addCallback(self._gotConfirmation, peer_jid, transfer_data, file_data, profile)
+ return d
diff --git a/src/plugins/plugin_xep_0234.py b/src/plugins/plugin_xep_0234.py
index 3777cf13..eaba7101 100644
--- a/src/plugins/plugin_xep_0234.py
+++ b/src/plugins/plugin_xep_0234.py
@@ -17,12 +17,11 @@
# 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 _, D_
+from sat.core.i18n import _
from sat.core.constants import Const as C
from sat.core.log import getLogger
log = getLogger(__name__)
from sat.core import exceptions
-from sat.tools import xml_tools
from wokkel import disco, iwokkel
from zope.interface import implements
from sat.tools import utils
@@ -35,10 +34,6 @@ from twisted.internet import defer
NS_JINGLE_FT = 'urn:xmpp:jingle:apps:file-transfer:4'
-CONFIRM = D_(u'{entity} wants to send the file "{name}" to you:\n{desc}\n\nThe file has a size of {size_human}\n\nDo you accept ?')
-CONFIRM_TITLE = D_(u'Confirm file transfer')
-CONFIRM_OVERWRITE = D_(u'File {} already exists, are you sure you want to overwrite ?')
-CONFIRM_OVERWRITE_TITLE = D_(u'File exists')
PLUGIN_INFO = {
"name": "Jingle File Transfer",
@@ -79,84 +74,6 @@ class XEP_0234(object):
}],
profile=profile)
-
- # Dialogs with user
- # the overwrite check is done here
-
- def _getDestDir(self, session, content_name, content_data, profile):
- """Request confirmation and destination dir to user
-
- if transfer is confirmed, session is filled
- @param session(dict): jingle session data
- @param content_name(unicode): name of the jingle content
- @param content_data(dict): content informations
- @param profile: %(doc_profile)s
- return (defer.Deferred): True if transfer is accepted
- """
- application_data = content_data['application_data']
- file_data = application_data['file_data']
- d = xml_tools.deferDialog(self.host,
- _(CONFIRM).format(entity=session['peer_jid'].full(), **file_data),
- _(CONFIRM_TITLE),
- type_=C.XMLUI_DIALOG_FILE,
- options={C.XMLUI_DATA_FILETYPE: C.XMLUI_DATA_FILETYPE_DIR},
- profile=profile)
- d.addCallback(self._gotConfirmation, session, content_name, content_data, application_data, profile)
- return d
-
- def _openFileWrite(self, session, content_name, content_data, file_path, file_data, profile):
- assert 'file_obj' not in content_data
- file_obj = content_data['file_obj'] = self._f.File(
- self.host,
- file_path,
- 'w',
- size=file_data['size'],
- profile=profile,
- )
- finished_d = content_data['finished_d'] = defer.Deferred()
- args = [file_obj, session, content_name, content_data, profile]
- finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args)
-
- def _gotConfirmation(self, data, session, content_name, content_data, application_data, profile):
- """Called when the permission and dest path have been received
-
- @param data(dict): xmlui data received from file dialog
- @param session(dict): jingle session data
- @param content_name(unicode): name of the jingle content
- @param content_data(dict): content session_data
- @param content_data(dict): application session data
- @param profile: %(doc_profile)s
- return (bool): True if copy is wanted and OK
- False if user wants to cancel
- if fill exists ask confirmation and call again self._getDestDir if needed
- """
- if data.get('cancelled', False):
- return False
- file_data = application_data['file_data']
- path = data['path']
- file_data['file_path'] = file_path = os.path.join(path, file_data['name'])
- log.debug(u'destination file path set to {}'.format(file_path))
-
- # we manage case where file already exists
- if os.path.exists(file_path):
- def check_overwrite(overwrite):
- if overwrite:
- self._openFileWrite(session, content_name, content_data, file_path, file_data, profile)
- return True
- else:
- return self._getDestDir(session, content_name, content_data, profile)
-
- exists_d = xml_tools.deferConfirm(
- self.host,
- _(CONFIRM_OVERWRITE).format(file_path),
- _(CONFIRM_OVERWRITE_TITLE),
- profile=profile)
- exists_d.addCallback(check_overwrite)
- return exists_d
-
- self._openFileWrite(session, content_name, content_data, file_path, file_data, profile)
- return True
-
# jingle callbacks
def jingleSessionInit(self, session, content_name, filepath, name=None, file_desc=None, profile=C.PROF_KEY_NONE):
@@ -214,7 +131,16 @@ class XEP_0234(object):
content_data['application_data']['file_data'] = file_data
# now we actualy request permission to user
- return self._getDestDir(session, content_name, content_data, profile)
+ def gotConfirmation(confirmed):
+ if confirmed:
+ finished_d = content_data['finished_d'] = defer.Deferred()
+ args = [session, content_name, content_data, profile]
+ finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args)
+ return confirmed
+
+ d = self._f.getDestDir(session['peer_jid'], content_data, file_data, profile)
+ d.addCallback(gotConfirmation)
+ return d
def jingleHandler(self, action, session, content_name, desc_elt, profile):
@@ -234,29 +160,29 @@ class XEP_0234(object):
assert not 'file_obj' in content_data
file_path = application_data['file_path']
size = application_data['file_data']['size']
- file_obj = content_data['file_obj'] = self._f.File(self.host,
- file_path,
- size=size,
- profile=profile
- )
+ content_data['file_obj'] = self._f.File(self.host,
+ file_path,
+ size=size,
+ profile=profile
+ )
finished_d = content_data['finished_d'] = defer.Deferred()
- args = [file_obj, session, content_name, content_data, profile]
+ args = [session, content_name, content_data, profile]
finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args)
else:
log.warning(u"FIXME: unmanaged action {}".format(action))
return desc_elt
- def _finishedCb(self, dummy, file_obj, session, content_name, content_data, profile):
+ def _finishedCb(self, dummy, session, content_name, content_data, profile):
log.debug(u"File transfer completed successfuly")
if content_data['senders'] != session['role']:
# we terminate the session only if we are the received,
# as recommanded in XEP-0234 ยง2 (after example 6)
self._j.contentTerminate(session, content_name, profile=profile)
- file_obj.close()
+ content_data['file_obj'].close()
- def _finishedEb(self, failure, file_obj, session, content_name, content_data, profile):
+ def _finishedEb(self, failure, session, content_name, content_data, profile):
log.warning(u"Error while streaming through s5b: {}".format(failure))
- file_obj.close()
+ content_data['file_obj'].close()
self._j.contentTerminate(session, content_name, reason=self._j.REASON_FAILED_TRANSPORT, profile=profile)