Mercurial > libervia-backend
comparison src/plugins/plugin_xep_0234.py @ 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 | c668081eba1c |
children | 833bdb227b16 |
comparison
equal
deleted
inserted
replaced
1573:6338677f3a89 | 1574:babd97d80049 |
---|---|
15 # GNU Affero General Public License for more details. | 15 # GNU Affero General Public License for more details. |
16 | 16 |
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _, D_ | 20 from sat.core.i18n import _ |
21 from sat.core.constants import Const as C | 21 from sat.core.constants import Const as C |
22 from sat.core.log import getLogger | 22 from sat.core.log import getLogger |
23 log = getLogger(__name__) | 23 log = getLogger(__name__) |
24 from sat.core import exceptions | 24 from sat.core import exceptions |
25 from sat.tools import xml_tools | |
26 from wokkel import disco, iwokkel | 25 from wokkel import disco, iwokkel |
27 from zope.interface import implements | 26 from zope.interface import implements |
28 from sat.tools import utils | 27 from sat.tools import utils |
29 import os.path | 28 import os.path |
30 from twisted.words.xish import domish | 29 from twisted.words.xish import domish |
33 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | 32 from twisted.words.protocols.jabber.xmlstream import XMPPHandler |
34 from twisted.internet import defer | 33 from twisted.internet import defer |
35 | 34 |
36 | 35 |
37 NS_JINGLE_FT = 'urn:xmpp:jingle:apps:file-transfer:4' | 36 NS_JINGLE_FT = 'urn:xmpp:jingle:apps:file-transfer:4' |
38 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 ?') | |
39 CONFIRM_TITLE = D_(u'Confirm file transfer') | |
40 CONFIRM_OVERWRITE = D_(u'File {} already exists, are you sure you want to overwrite ?') | |
41 CONFIRM_OVERWRITE_TITLE = D_(u'File exists') | |
42 | 37 |
43 PLUGIN_INFO = { | 38 PLUGIN_INFO = { |
44 "name": "Jingle File Transfer", | 39 "name": "Jingle File Transfer", |
45 "import_name": "XEP-0234", | 40 "import_name": "XEP-0234", |
46 "type": "XEP", | 41 "type": "XEP", |
76 'app_kwargs': {'filepath': filepath, | 71 'app_kwargs': {'filepath': filepath, |
77 'name': name, | 72 'name': name, |
78 'file_desc': file_desc}, | 73 'file_desc': file_desc}, |
79 }], | 74 }], |
80 profile=profile) | 75 profile=profile) |
81 | |
82 | |
83 # Dialogs with user | |
84 # the overwrite check is done here | |
85 | |
86 def _getDestDir(self, session, content_name, content_data, profile): | |
87 """Request confirmation and destination dir to user | |
88 | |
89 if transfer is confirmed, session is filled | |
90 @param session(dict): jingle session data | |
91 @param content_name(unicode): name of the jingle content | |
92 @param content_data(dict): content informations | |
93 @param profile: %(doc_profile)s | |
94 return (defer.Deferred): True if transfer is accepted | |
95 """ | |
96 application_data = content_data['application_data'] | |
97 file_data = application_data['file_data'] | |
98 d = xml_tools.deferDialog(self.host, | |
99 _(CONFIRM).format(entity=session['peer_jid'].full(), **file_data), | |
100 _(CONFIRM_TITLE), | |
101 type_=C.XMLUI_DIALOG_FILE, | |
102 options={C.XMLUI_DATA_FILETYPE: C.XMLUI_DATA_FILETYPE_DIR}, | |
103 profile=profile) | |
104 d.addCallback(self._gotConfirmation, session, content_name, content_data, application_data, profile) | |
105 return d | |
106 | |
107 def _openFileWrite(self, session, content_name, content_data, file_path, file_data, profile): | |
108 assert 'file_obj' not in content_data | |
109 file_obj = content_data['file_obj'] = self._f.File( | |
110 self.host, | |
111 file_path, | |
112 'w', | |
113 size=file_data['size'], | |
114 profile=profile, | |
115 ) | |
116 finished_d = content_data['finished_d'] = defer.Deferred() | |
117 args = [file_obj, session, content_name, content_data, profile] | |
118 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) | |
119 | |
120 def _gotConfirmation(self, data, session, content_name, content_data, application_data, profile): | |
121 """Called when the permission and dest path have been received | |
122 | |
123 @param data(dict): xmlui data received from file dialog | |
124 @param session(dict): jingle session data | |
125 @param content_name(unicode): name of the jingle content | |
126 @param content_data(dict): content session_data | |
127 @param content_data(dict): application session data | |
128 @param profile: %(doc_profile)s | |
129 return (bool): True if copy is wanted and OK | |
130 False if user wants to cancel | |
131 if fill exists ask confirmation and call again self._getDestDir if needed | |
132 """ | |
133 if data.get('cancelled', False): | |
134 return False | |
135 file_data = application_data['file_data'] | |
136 path = data['path'] | |
137 file_data['file_path'] = file_path = os.path.join(path, file_data['name']) | |
138 log.debug(u'destination file path set to {}'.format(file_path)) | |
139 | |
140 # we manage case where file already exists | |
141 if os.path.exists(file_path): | |
142 def check_overwrite(overwrite): | |
143 if overwrite: | |
144 self._openFileWrite(session, content_name, content_data, file_path, file_data, profile) | |
145 return True | |
146 else: | |
147 return self._getDestDir(session, content_name, content_data, profile) | |
148 | |
149 exists_d = xml_tools.deferConfirm( | |
150 self.host, | |
151 _(CONFIRM_OVERWRITE).format(file_path), | |
152 _(CONFIRM_OVERWRITE_TITLE), | |
153 profile=profile) | |
154 exists_d.addCallback(check_overwrite) | |
155 return exists_d | |
156 | |
157 self._openFileWrite(session, content_name, content_data, file_path, file_data, profile) | |
158 return True | |
159 | 76 |
160 # jingle callbacks | 77 # jingle callbacks |
161 | 78 |
162 def jingleSessionInit(self, session, content_name, filepath, name=None, file_desc=None, profile=C.PROF_KEY_NONE): | 79 def jingleSessionInit(self, session, content_name, filepath, name=None, file_desc=None, profile=C.PROF_KEY_NONE): |
163 content_data = session['contents'][content_name] | 80 content_data = session['contents'][content_name] |
212 # TODO: parse hash using plugin XEP-0300 | 129 # TODO: parse hash using plugin XEP-0300 |
213 | 130 |
214 content_data['application_data']['file_data'] = file_data | 131 content_data['application_data']['file_data'] = file_data |
215 | 132 |
216 # now we actualy request permission to user | 133 # now we actualy request permission to user |
217 return self._getDestDir(session, content_name, content_data, profile) | 134 def gotConfirmation(confirmed): |
135 if confirmed: | |
136 finished_d = content_data['finished_d'] = defer.Deferred() | |
137 args = [session, content_name, content_data, profile] | |
138 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) | |
139 return confirmed | |
140 | |
141 d = self._f.getDestDir(session['peer_jid'], content_data, file_data, profile) | |
142 d.addCallback(gotConfirmation) | |
143 return d | |
218 | 144 |
219 | 145 |
220 def jingleHandler(self, action, session, content_name, desc_elt, profile): | 146 def jingleHandler(self, action, session, content_name, desc_elt, profile): |
221 content_data = session['contents'][content_name] | 147 content_data = session['contents'][content_name] |
222 application_data = content_data['application_data'] | 148 application_data = content_data['application_data'] |
232 file_elt.addElement('range') | 158 file_elt.addElement('range') |
233 elif action == self._j.A_SESSION_ACCEPT: | 159 elif action == self._j.A_SESSION_ACCEPT: |
234 assert not 'file_obj' in content_data | 160 assert not 'file_obj' in content_data |
235 file_path = application_data['file_path'] | 161 file_path = application_data['file_path'] |
236 size = application_data['file_data']['size'] | 162 size = application_data['file_data']['size'] |
237 file_obj = content_data['file_obj'] = self._f.File(self.host, | 163 content_data['file_obj'] = self._f.File(self.host, |
238 file_path, | 164 file_path, |
239 size=size, | 165 size=size, |
240 profile=profile | 166 profile=profile |
241 ) | 167 ) |
242 finished_d = content_data['finished_d'] = defer.Deferred() | 168 finished_d = content_data['finished_d'] = defer.Deferred() |
243 args = [file_obj, session, content_name, content_data, profile] | 169 args = [session, content_name, content_data, profile] |
244 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) | 170 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) |
245 else: | 171 else: |
246 log.warning(u"FIXME: unmanaged action {}".format(action)) | 172 log.warning(u"FIXME: unmanaged action {}".format(action)) |
247 return desc_elt | 173 return desc_elt |
248 | 174 |
249 def _finishedCb(self, dummy, file_obj, session, content_name, content_data, profile): | 175 def _finishedCb(self, dummy, session, content_name, content_data, profile): |
250 log.debug(u"File transfer completed successfuly") | 176 log.debug(u"File transfer completed successfuly") |
251 if content_data['senders'] != session['role']: | 177 if content_data['senders'] != session['role']: |
252 # we terminate the session only if we are the received, | 178 # we terminate the session only if we are the received, |
253 # as recommanded in XEP-0234 §2 (after example 6) | 179 # as recommanded in XEP-0234 §2 (after example 6) |
254 self._j.contentTerminate(session, content_name, profile=profile) | 180 self._j.contentTerminate(session, content_name, profile=profile) |
255 file_obj.close() | 181 content_data['file_obj'].close() |
256 | 182 |
257 def _finishedEb(self, failure, file_obj, session, content_name, content_data, profile): | 183 def _finishedEb(self, failure, session, content_name, content_data, profile): |
258 log.warning(u"Error while streaming through s5b: {}".format(failure)) | 184 log.warning(u"Error while streaming through s5b: {}".format(failure)) |
259 file_obj.close() | 185 content_data['file_obj'].close() |
260 self._j.contentTerminate(session, content_name, reason=self._j.REASON_FAILED_TRANSPORT, profile=profile) | 186 self._j.contentTerminate(session, content_name, reason=self._j.REASON_FAILED_TRANSPORT, profile=profile) |
261 | 187 |
262 | 188 |
263 class XEP_0234_handler(XMPPHandler): | 189 class XEP_0234_handler(XMPPHandler): |
264 implements(iwokkel.IDisco) | 190 implements(iwokkel.IDisco) |