changeset 1574:babd97d80049

plugins XEP-0234, file: moved file request dialog to file plugin
author Goffi <goffi@goffi.org>
date Wed, 11 Nov 2015 18:19:47 +0100
parents 6338677f3a89
children 833bdb227b16
files src/plugins/plugin_misc_file.py src/plugins/plugin_xep_0234.py
diffstat 2 files changed, 111 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/plugin_misc_file.py	Wed Nov 11 14:56:05 2015 +0100
+++ b/src/plugins/plugin_misc_file.py	Wed Nov 11 18:19:47 2015 +0100
@@ -17,12 +17,13 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-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__)
+from sat.tools import xml_tools
+from twisted.internet import defer
 import os
-from twisted.internet import defer
 import uuid
 
 
@@ -37,6 +38,12 @@
 }
 
 
+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 @@
         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
--- a/src/plugins/plugin_xep_0234.py	Wed Nov 11 14:56:05 2015 +0100
+++ b/src/plugins/plugin_xep_0234.py	Wed Nov 11 18:19:47 2015 +0100
@@ -17,12 +17,11 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-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 @@
 
 
 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 @@
                          }],
                          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 @@
         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 @@
             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)