plugins XEP-0234, file: moved file request dialog to file plugin

This commit is contained in:
Goffi 2015-11-11 18:19:47 +01:00
commit a022a36b5b
2 changed files with 112 additions and 98 deletions

View file

@ -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__)
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

View file

@ -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 @@ 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)