Mercurial > libervia-backend
comparison sat_frontends/jp/cmd_file.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | c0401a72cbb4 |
children | 003b8b4b56a7 |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
27 from sat_frontends.jp.constants import Const as C | 27 from sat_frontends.jp.constants import Const as C |
28 from sat_frontends.jp import common | 28 from sat_frontends.jp import common |
29 from sat_frontends.tools import jid | 29 from sat_frontends.tools import jid |
30 from sat.tools.common.ansi import ANSI as A | 30 from sat.tools.common.ansi import ANSI as A |
31 import tempfile | 31 import tempfile |
32 import xml.etree.ElementTree as ET # FIXME: used temporarily to manage XMLUI | 32 import xml.etree.ElementTree as ET # FIXME: used temporarily to manage XMLUI |
33 from functools import partial | 33 from functools import partial |
34 import json | 34 import json |
35 | 35 |
36 __commands__ = ["File"] | 36 __commands__ = ["File"] |
37 | 37 |
38 | 38 |
39 class Send(base.CommandBase): | 39 class Send(base.CommandBase): |
40 def __init__(self, host): | 40 def __init__(self, host): |
41 super(Send, self).__init__(host, 'send', use_progress=True, use_verbose=True, help=_('send a file to a contact')) | 41 super(Send, self).__init__( |
42 self.need_loop=True | 42 host, |
43 "send", | |
44 use_progress=True, | |
45 use_verbose=True, | |
46 help=_("send a file to a contact"), | |
47 ) | |
48 self.need_loop = True | |
43 | 49 |
44 def add_parser_options(self): | 50 def add_parser_options(self): |
45 self.parser.add_argument("files", type=str, nargs='+', metavar='file', help=_(u"a list of file")) | 51 self.parser.add_argument( |
46 self.parser.add_argument("jid", type=base.unicode_decoder, help=_(u"the destination jid")) | 52 "files", type=str, nargs="+", metavar="file", help=_(u"a list of file") |
47 self.parser.add_argument("-b", "--bz2", action="store_true", help=_(u"make a bzip2 tarball")) | 53 ) |
48 self.parser.add_argument("-d", "--path", type=base.unicode_decoder, help=(u"path to the directory where the file must be stored")) | 54 self.parser.add_argument( |
49 self.parser.add_argument("-N", "--namespace", type=base.unicode_decoder, help=(u"namespace of the file")) | 55 "jid", type=base.unicode_decoder, help=_(u"the destination jid") |
50 self.parser.add_argument("-n", "--name", type=base.unicode_decoder, default=u'', help=(u"name to use (DEFAULT: use source file name)")) | 56 ) |
57 self.parser.add_argument( | |
58 "-b", "--bz2", action="store_true", help=_(u"make a bzip2 tarball") | |
59 ) | |
60 self.parser.add_argument( | |
61 "-d", | |
62 "--path", | |
63 type=base.unicode_decoder, | |
64 help=(u"path to the directory where the file must be stored"), | |
65 ) | |
66 self.parser.add_argument( | |
67 "-N", | |
68 "--namespace", | |
69 type=base.unicode_decoder, | |
70 help=(u"namespace of the file"), | |
71 ) | |
72 self.parser.add_argument( | |
73 "-n", | |
74 "--name", | |
75 type=base.unicode_decoder, | |
76 default=u"", | |
77 help=(u"name to use (DEFAULT: use source file name)"), | |
78 ) | |
51 | 79 |
52 def start(self): | 80 def start(self): |
53 """Send files to jabber contact""" | 81 """Send files to jabber contact""" |
54 self.send_files() | 82 self.send_files() |
55 | 83 |
56 def onProgressStarted(self, metadata): | 84 def onProgressStarted(self, metadata): |
57 self.disp(_(u'File copy started'),2) | 85 self.disp(_(u"File copy started"), 2) |
58 | 86 |
59 def onProgressFinished(self, metadata): | 87 def onProgressFinished(self, metadata): |
60 self.disp(_(u'File sent successfully'),2) | 88 self.disp(_(u"File sent successfully"), 2) |
61 | 89 |
62 def onProgressError(self, error_msg): | 90 def onProgressError(self, error_msg): |
63 if error_msg == C.PROGRESS_ERROR_DECLINED: | 91 if error_msg == C.PROGRESS_ERROR_DECLINED: |
64 self.disp(_(u'The file has been refused by your contact')) | 92 self.disp(_(u"The file has been refused by your contact")) |
65 else: | 93 else: |
66 self.disp(_(u'Error while sending file: {}').format(error_msg),error=True) | 94 self.disp(_(u"Error while sending file: {}").format(error_msg), error=True) |
67 | 95 |
68 def gotId(self, data, file_): | 96 def gotId(self, data, file_): |
69 """Called when a progress id has been received | 97 """Called when a progress id has been received |
70 | 98 |
71 @param pid(unicode): progress id | 99 @param pid(unicode): progress id |
72 @param file_(str): file path | 100 @param file_(str): file path |
73 """ | 101 """ |
74 #FIXME: this show progress only for last progress_id | 102 # FIXME: this show progress only for last progress_id |
75 self.disp(_(u"File request sent to {jid}".format(jid=self.full_dest_jid)), 1) | 103 self.disp(_(u"File request sent to {jid}".format(jid=self.full_dest_jid)), 1) |
76 try: | 104 try: |
77 self.progress_id = data['progress'] | 105 self.progress_id = data["progress"] |
78 except KeyError: | 106 except KeyError: |
79 # TODO: if 'xmlui' key is present, manage xmlui message display | 107 # TODO: if 'xmlui' key is present, manage xmlui message display |
80 self.disp(_(u"Can't send file to {jid}".format(jid=self.full_dest_jid)), error=True) | 108 self.disp( |
109 _(u"Can't send file to {jid}".format(jid=self.full_dest_jid)), error=True | |
110 ) | |
81 self.host.quit(2) | 111 self.host.quit(2) |
82 | 112 |
83 def error(self, failure): | 113 def error(self, failure): |
84 self.disp(_("Error while trying to send a file: {reason}").format(reason=failure), error=True) | 114 self.disp( |
115 _("Error while trying to send a file: {reason}").format(reason=failure), | |
116 error=True, | |
117 ) | |
85 self.host.quit(1) | 118 self.host.quit(1) |
86 | 119 |
87 def send_files(self): | 120 def send_files(self): |
88 for file_ in self.args.files: | 121 for file_ in self.args.files: |
89 if not os.path.exists(file_): | 122 if not os.path.exists(file_): |
90 self.disp(_(u"file [{}] doesn't exist !").format(file_), error=True) | 123 self.disp(_(u"file [{}] doesn't exist !").format(file_), error=True) |
91 self.host.quit(1) | 124 self.host.quit(1) |
92 if not self.args.bz2 and os.path.isdir(file_): | 125 if not self.args.bz2 and os.path.isdir(file_): |
93 self.disp(_(u"[{}] is a dir ! Please send files inside or use compression").format(file_)) | 126 self.disp( |
127 _( | |
128 u"[{}] is a dir ! Please send files inside or use compression" | |
129 ).format(file_) | |
130 ) | |
94 self.host.quit(1) | 131 self.host.quit(1) |
95 | 132 |
96 self.full_dest_jid = self.host.get_full_jid(self.args.jid) | 133 self.full_dest_jid = self.host.get_full_jid(self.args.jid) |
97 extra = {} | 134 extra = {} |
98 if self.args.path: | 135 if self.args.path: |
99 extra[u'path'] = self.args.path | 136 extra[u"path"] = self.args.path |
100 if self.args.namespace: | 137 if self.args.namespace: |
101 extra[u'namespace'] = self.args.namespace | 138 extra[u"namespace"] = self.args.namespace |
102 | 139 |
103 if self.args.bz2: | 140 if self.args.bz2: |
104 with tempfile.NamedTemporaryFile('wb', delete=False) as buf: | 141 with tempfile.NamedTemporaryFile("wb", delete=False) as buf: |
105 self.host.addOnQuitCallback(os.unlink, buf.name) | 142 self.host.addOnQuitCallback(os.unlink, buf.name) |
106 self.disp(_(u"bz2 is an experimental option, use with caution")) | 143 self.disp(_(u"bz2 is an experimental option, use with caution")) |
107 #FIXME: check free space | 144 # FIXME: check free space |
108 self.disp(_(u"Starting compression, please wait...")) | 145 self.disp(_(u"Starting compression, please wait...")) |
109 sys.stdout.flush() | 146 sys.stdout.flush() |
110 bz2 = tarfile.open(mode="w:bz2", fileobj=buf) | 147 bz2 = tarfile.open(mode="w:bz2", fileobj=buf) |
111 archive_name = u'{}.tar.bz2'.format(os.path.basename(self.args.files[0]) or u'compressed_files') | 148 archive_name = u"{}.tar.bz2".format( |
149 os.path.basename(self.args.files[0]) or u"compressed_files" | |
150 ) | |
112 for file_ in self.args.files: | 151 for file_ in self.args.files: |
113 self.disp(_(u"Adding {}").format(file_), 1) | 152 self.disp(_(u"Adding {}").format(file_), 1) |
114 bz2.add(file_) | 153 bz2.add(file_) |
115 bz2.close() | 154 bz2.close() |
116 self.disp(_(u"Done !"), 1) | 155 self.disp(_(u"Done !"), 1) |
117 | 156 |
118 self.host.bridge.fileSend(self.full_dest_jid, buf.name, self.args.name or archive_name, '', extra, self.profile, | 157 self.host.bridge.fileSend( |
119 callback=lambda pid, file_=buf.name: self.gotId(pid, file_), errback=self.error) | 158 self.full_dest_jid, |
159 buf.name, | |
160 self.args.name or archive_name, | |
161 "", | |
162 extra, | |
163 self.profile, | |
164 callback=lambda pid, file_=buf.name: self.gotId(pid, file_), | |
165 errback=self.error, | |
166 ) | |
120 else: | 167 else: |
121 for file_ in self.args.files: | 168 for file_ in self.args.files: |
122 path = os.path.abspath(file_) | 169 path = os.path.abspath(file_) |
123 self.host.bridge.fileSend(self.full_dest_jid, path, self.args.name, '', extra, self.profile, | 170 self.host.bridge.fileSend( |
124 callback=lambda pid, file_=file_: self.gotId(pid, file_), errback=self.error) | 171 self.full_dest_jid, |
172 path, | |
173 self.args.name, | |
174 "", | |
175 extra, | |
176 self.profile, | |
177 callback=lambda pid, file_=file_: self.gotId(pid, file_), | |
178 errback=self.error, | |
179 ) | |
125 | 180 |
126 | 181 |
127 class Request(base.CommandBase): | 182 class Request(base.CommandBase): |
128 | |
129 def __init__(self, host): | 183 def __init__(self, host): |
130 super(Request, self).__init__(host, 'request', use_progress=True, use_verbose=True, help=_('request a file from a contact')) | 184 super(Request, self).__init__( |
131 self.need_loop=True | 185 host, |
186 "request", | |
187 use_progress=True, | |
188 use_verbose=True, | |
189 help=_("request a file from a contact"), | |
190 ) | |
191 self.need_loop = True | |
132 | 192 |
133 @property | 193 @property |
134 def filename(self): | 194 def filename(self): |
135 return self.args.name or self.args.hash or u"output" | 195 return self.args.name or self.args.hash or u"output" |
136 | 196 |
137 def add_parser_options(self): | 197 def add_parser_options(self): |
138 self.parser.add_argument("jid", type=base.unicode_decoder, help=_(u"the destination jid")) | 198 self.parser.add_argument( |
139 self.parser.add_argument("-D", "--dest", type=base.unicode_decoder, help=_(u"destination path where the file will be saved (default: [current_dir]/[name|hash])")) | 199 "jid", type=base.unicode_decoder, help=_(u"the destination jid") |
140 self.parser.add_argument("-n", "--name", type=base.unicode_decoder, default=u'', help=_(u"name of the file")) | 200 ) |
141 self.parser.add_argument("-H", "--hash", type=base.unicode_decoder, default=u'', help=_(u"hash of the file")) | 201 self.parser.add_argument( |
142 self.parser.add_argument("-a", "--hash-algo", type=base.unicode_decoder, default=u'sha-256', help=_(u"hash algorithm use for --hash (default: sha-256)")) | 202 "-D", |
143 self.parser.add_argument("-d", "--path", type=base.unicode_decoder, help=(u"path to the directory containing the file")) | 203 "--dest", |
144 self.parser.add_argument("-N", "--namespace", type=base.unicode_decoder, help=(u"namespace of the file")) | 204 type=base.unicode_decoder, |
145 self.parser.add_argument("-f", "--force", action='store_true', help=_(u"overwrite existing file without confirmation")) | 205 help=_( |
206 u"destination path where the file will be saved (default: [current_dir]/[name|hash])" | |
207 ), | |
208 ) | |
209 self.parser.add_argument( | |
210 "-n", | |
211 "--name", | |
212 type=base.unicode_decoder, | |
213 default=u"", | |
214 help=_(u"name of the file"), | |
215 ) | |
216 self.parser.add_argument( | |
217 "-H", | |
218 "--hash", | |
219 type=base.unicode_decoder, | |
220 default=u"", | |
221 help=_(u"hash of the file"), | |
222 ) | |
223 self.parser.add_argument( | |
224 "-a", | |
225 "--hash-algo", | |
226 type=base.unicode_decoder, | |
227 default=u"sha-256", | |
228 help=_(u"hash algorithm use for --hash (default: sha-256)"), | |
229 ) | |
230 self.parser.add_argument( | |
231 "-d", | |
232 "--path", | |
233 type=base.unicode_decoder, | |
234 help=(u"path to the directory containing the file"), | |
235 ) | |
236 self.parser.add_argument( | |
237 "-N", | |
238 "--namespace", | |
239 type=base.unicode_decoder, | |
240 help=(u"namespace of the file"), | |
241 ) | |
242 self.parser.add_argument( | |
243 "-f", | |
244 "--force", | |
245 action="store_true", | |
246 help=_(u"overwrite existing file without confirmation"), | |
247 ) | |
146 | 248 |
147 def onProgressStarted(self, metadata): | 249 def onProgressStarted(self, metadata): |
148 self.disp(_(u'File copy started'),2) | 250 self.disp(_(u"File copy started"), 2) |
149 | 251 |
150 def onProgressFinished(self, metadata): | 252 def onProgressFinished(self, metadata): |
151 self.disp(_(u'File received successfully'),2) | 253 self.disp(_(u"File received successfully"), 2) |
152 | 254 |
153 def onProgressError(self, error_msg): | 255 def onProgressError(self, error_msg): |
154 if error_msg == C.PROGRESS_ERROR_DECLINED: | 256 if error_msg == C.PROGRESS_ERROR_DECLINED: |
155 self.disp(_(u'The file request has been refused')) | 257 self.disp(_(u"The file request has been refused")) |
156 else: | 258 else: |
157 self.disp(_(u'Error while requesting file: {}').format(error_msg), error=True) | 259 self.disp(_(u"Error while requesting file: {}").format(error_msg), error=True) |
158 | 260 |
159 def gotId(self, progress_id): | 261 def gotId(self, progress_id): |
160 """Called when a progress id has been received | 262 """Called when a progress id has been received |
161 | 263 |
162 @param progress_id(unicode): progress id | 264 @param progress_id(unicode): progress id |
163 """ | 265 """ |
164 self.progress_id = progress_id | 266 self.progress_id = progress_id |
165 | 267 |
166 def error(self, failure): | 268 def error(self, failure): |
167 self.disp(_("Error while trying to send a file: {reason}").format(reason=failure), error=True) | 269 self.disp( |
270 _("Error while trying to send a file: {reason}").format(reason=failure), | |
271 error=True, | |
272 ) | |
168 self.host.quit(1) | 273 self.host.quit(1) |
169 | 274 |
170 def start(self): | 275 def start(self): |
171 if not self.args.name and not self.args.hash: | 276 if not self.args.name and not self.args.hash: |
172 self.parser.error(_(u'at least one of --name or --hash must be provided')) | 277 self.parser.error(_(u"at least one of --name or --hash must be provided")) |
173 # extra = dict(self.args.extra) | 278 # extra = dict(self.args.extra) |
174 if self.args.dest: | 279 if self.args.dest: |
175 path = os.path.abspath(os.path.expanduser(self.args.dest)) | 280 path = os.path.abspath(os.path.expanduser(self.args.dest)) |
176 if os.path.isdir(path): | 281 if os.path.isdir(path): |
177 path = os.path.join(path, self.filename) | 282 path = os.path.join(path, self.filename) |
178 else: | 283 else: |
179 path = os.path.abspath(self.filename) | 284 path = os.path.abspath(self.filename) |
180 | 285 |
181 if os.path.exists(path) and not self.args.force: | 286 if os.path.exists(path) and not self.args.force: |
182 message = _(u'File {path} already exists! Do you want to overwrite?').format(path=path) | 287 message = _(u"File {path} already exists! Do you want to overwrite?").format( |
183 confirm = raw_input(u"{} (y/N) ".format(message).encode('utf-8')) | 288 path=path |
289 ) | |
290 confirm = raw_input(u"{} (y/N) ".format(message).encode("utf-8")) | |
184 if confirm not in (u"y", u"Y"): | 291 if confirm not in (u"y", u"Y"): |
185 self.disp(_(u"file request cancelled")) | 292 self.disp(_(u"file request cancelled")) |
186 self.host.quit(2) | 293 self.host.quit(2) |
187 | 294 |
188 self.full_dest_jid = self.host.get_full_jid(self.args.jid) | 295 self.full_dest_jid = self.host.get_full_jid(self.args.jid) |
189 extra = {} | 296 extra = {} |
190 if self.args.path: | 297 if self.args.path: |
191 extra[u'path'] = self.args.path | 298 extra[u"path"] = self.args.path |
192 if self.args.namespace: | 299 if self.args.namespace: |
193 extra[u'namespace'] = self.args.namespace | 300 extra[u"namespace"] = self.args.namespace |
194 self.host.bridge.fileJingleRequest(self.full_dest_jid, | 301 self.host.bridge.fileJingleRequest( |
195 path, | 302 self.full_dest_jid, |
196 self.args.name, | 303 path, |
197 self.args.hash, | 304 self.args.name, |
198 self.args.hash_algo if self.args.hash else u'', | 305 self.args.hash, |
199 extra, | 306 self.args.hash_algo if self.args.hash else u"", |
200 self.profile, | 307 extra, |
201 callback=self.gotId, | 308 self.profile, |
202 errback=partial(self.errback, | 309 callback=self.gotId, |
203 msg=_(u"can't request file: {}"), | 310 errback=partial( |
204 exit_code=C.EXIT_BRIDGE_ERRBACK)) | 311 self.errback, |
312 msg=_(u"can't request file: {}"), | |
313 exit_code=C.EXIT_BRIDGE_ERRBACK, | |
314 ), | |
315 ) | |
205 | 316 |
206 | 317 |
207 class Receive(base.CommandAnswering): | 318 class Receive(base.CommandAnswering): |
208 | |
209 def __init__(self, host): | 319 def __init__(self, host): |
210 super(Receive, self).__init__(host, 'receive', use_progress=True, use_verbose=True, help=_('wait for a file to be sent by a contact')) | 320 super(Receive, self).__init__( |
211 self._overwrite_refused = False # True when one overwrite as already been refused | 321 host, |
212 self.action_callbacks = {C.META_TYPE_FILE: self.onFileAction, | 322 "receive", |
213 C.META_TYPE_OVERWRITE: self.onOverwriteAction} | 323 use_progress=True, |
324 use_verbose=True, | |
325 help=_("wait for a file to be sent by a contact"), | |
326 ) | |
327 self._overwrite_refused = False # True when one overwrite as already been refused | |
328 self.action_callbacks = { | |
329 C.META_TYPE_FILE: self.onFileAction, | |
330 C.META_TYPE_OVERWRITE: self.onOverwriteAction, | |
331 } | |
214 | 332 |
215 def onProgressStarted(self, metadata): | 333 def onProgressStarted(self, metadata): |
216 self.disp(_(u'File copy started'),2) | 334 self.disp(_(u"File copy started"), 2) |
217 | 335 |
218 def onProgressFinished(self, metadata): | 336 def onProgressFinished(self, metadata): |
219 self.disp(_(u'File received successfully'),2) | 337 self.disp(_(u"File received successfully"), 2) |
220 if metadata.get('hash_verified', False): | 338 if metadata.get("hash_verified", False): |
221 try: | 339 try: |
222 self.disp(_(u'hash checked: {algo}:{checksum}').format( | 340 self.disp( |
223 algo=metadata['hash_algo'], | 341 _(u"hash checked: {algo}:{checksum}").format( |
224 checksum=metadata['hash']), | 342 algo=metadata["hash_algo"], checksum=metadata["hash"] |
225 1) | 343 ), |
344 1, | |
345 ) | |
226 except KeyError: | 346 except KeyError: |
227 self.disp(_(u'hash is checked but hash value is missing', 1), error=True) | 347 self.disp(_(u"hash is checked but hash value is missing", 1), error=True) |
228 else: | 348 else: |
229 self.disp(_(u"hash can't be verified"), 1) | 349 self.disp(_(u"hash can't be verified"), 1) |
230 | 350 |
231 def onProgressError(self, error_msg): | 351 def onProgressError(self, error_msg): |
232 self.disp(_(u'Error while receiving file: {}').format(error_msg),error=True) | 352 self.disp(_(u"Error while receiving file: {}").format(error_msg), error=True) |
233 | 353 |
234 def getXmluiId(self, action_data): | 354 def getXmluiId(self, action_data): |
235 # FIXME: we temporarily use ElementTree, but a real XMLUI managing module | 355 # FIXME: we temporarily use ElementTree, but a real XMLUI managing module |
236 # should be available in the futur | 356 # should be available in the futur |
237 # TODO: XMLUI module | 357 # TODO: XMLUI module |
238 try: | 358 try: |
239 xml_ui = action_data['xmlui'] | 359 xml_ui = action_data["xmlui"] |
240 except KeyError: | 360 except KeyError: |
241 self.disp(_(u"Action has no XMLUI"), 1) | 361 self.disp(_(u"Action has no XMLUI"), 1) |
242 else: | 362 else: |
243 ui = ET.fromstring(xml_ui.encode('utf-8')) | 363 ui = ET.fromstring(xml_ui.encode("utf-8")) |
244 xmlui_id = ui.get('submit') | 364 xmlui_id = ui.get("submit") |
245 if not xmlui_id: | 365 if not xmlui_id: |
246 self.disp(_(u"Invalid XMLUI received"), error=True) | 366 self.disp(_(u"Invalid XMLUI received"), error=True) |
247 return xmlui_id | 367 return xmlui_id |
248 | 368 |
249 def onFileAction(self, action_data, action_id, security_limit, profile): | 369 def onFileAction(self, action_data, action_id, security_limit, profile): |
250 xmlui_id = self.getXmluiId(action_data) | 370 xmlui_id = self.getXmluiId(action_data) |
251 if xmlui_id is None: | 371 if xmlui_id is None: |
252 return self.host.quitFromSignal(1) | 372 return self.host.quitFromSignal(1) |
253 try: | 373 try: |
254 from_jid = jid.JID(action_data['meta_from_jid']) | 374 from_jid = jid.JID(action_data["meta_from_jid"]) |
255 except KeyError: | 375 except KeyError: |
256 self.disp(_(u"Ignoring action without from_jid data"), 1) | 376 self.disp(_(u"Ignoring action without from_jid data"), 1) |
257 return | 377 return |
258 try: | 378 try: |
259 progress_id = action_data['meta_progress_id'] | 379 progress_id = action_data["meta_progress_id"] |
260 except KeyError: | 380 except KeyError: |
261 self.disp(_(u"ignoring action without progress id"), 1) | 381 self.disp(_(u"ignoring action without progress id"), 1) |
262 return | 382 return |
263 | 383 |
264 if not self.bare_jids or from_jid.bare in self.bare_jids: | 384 if not self.bare_jids or from_jid.bare in self.bare_jids: |
265 if self._overwrite_refused: | 385 if self._overwrite_refused: |
266 self.disp(_(u"File refused because overwrite is needed"), error=True) | 386 self.disp(_(u"File refused because overwrite is needed"), error=True) |
267 self.host.bridge.launchAction(xmlui_id, {'cancelled': C.BOOL_TRUE}, profile_key=profile) | 387 self.host.bridge.launchAction( |
388 xmlui_id, {"cancelled": C.BOOL_TRUE}, profile_key=profile | |
389 ) | |
268 return self.host.quitFromSignal(2) | 390 return self.host.quitFromSignal(2) |
269 self.progress_id = progress_id | 391 self.progress_id = progress_id |
270 xmlui_data = {'path': self.path} | 392 xmlui_data = {"path": self.path} |
271 self.host.bridge.launchAction(xmlui_id, xmlui_data, profile_key=profile) | 393 self.host.bridge.launchAction(xmlui_id, xmlui_data, profile_key=profile) |
272 | 394 |
273 def onOverwriteAction(self, action_data, action_id, security_limit, profile): | 395 def onOverwriteAction(self, action_data, action_id, security_limit, profile): |
274 xmlui_id = self.getXmluiId(action_data) | 396 xmlui_id = self.getXmluiId(action_data) |
275 if xmlui_id is None: | 397 if xmlui_id is None: |
276 return self.host.quitFromSignal(1) | 398 return self.host.quitFromSignal(1) |
277 try: | 399 try: |
278 progress_id = action_data['meta_progress_id'] | 400 progress_id = action_data["meta_progress_id"] |
279 except KeyError: | 401 except KeyError: |
280 self.disp(_(u"ignoring action without progress id"), 1) | 402 self.disp(_(u"ignoring action without progress id"), 1) |
281 return | 403 return |
282 self.disp(_(u"Overwriting needed"), 1) | 404 self.disp(_(u"Overwriting needed"), 1) |
283 | 405 |
286 self.disp(_(u"Overwrite accepted"), 2) | 408 self.disp(_(u"Overwrite accepted"), 2) |
287 else: | 409 else: |
288 self.disp(_(u"Refused to overwrite"), 2) | 410 self.disp(_(u"Refused to overwrite"), 2) |
289 self._overwrite_refused = True | 411 self._overwrite_refused = True |
290 | 412 |
291 xmlui_data = {'answer': C.boolConst(self.args.force)} | 413 xmlui_data = {"answer": C.boolConst(self.args.force)} |
292 self.host.bridge.launchAction(xmlui_id, xmlui_data, profile_key=profile) | 414 self.host.bridge.launchAction(xmlui_id, xmlui_data, profile_key=profile) |
293 | 415 |
294 def add_parser_options(self): | 416 def add_parser_options(self): |
295 self.parser.add_argument("jids", type=base.unicode_decoder, nargs="*", help=_(u'jids accepted (accept everything if none is specified)')) | 417 self.parser.add_argument( |
296 self.parser.add_argument("-m", "--multiple", action="store_true", help=_(u"accept multiple files (you'll have to stop manually)")) | 418 "jids", |
297 self.parser.add_argument("-f", "--force", action="store_true", help=_(u"force overwritting of existing files (/!\\ name is choosed by sender)")) | 419 type=base.unicode_decoder, |
298 self.parser.add_argument("--path", default='.', metavar='DIR', help=_(u"destination path (default: working directory)")) | 420 nargs="*", |
421 help=_(u"jids accepted (accept everything if none is specified)"), | |
422 ) | |
423 self.parser.add_argument( | |
424 "-m", | |
425 "--multiple", | |
426 action="store_true", | |
427 help=_(u"accept multiple files (you'll have to stop manually)"), | |
428 ) | |
429 self.parser.add_argument( | |
430 "-f", | |
431 "--force", | |
432 action="store_true", | |
433 help=_( | |
434 u"force overwritting of existing files (/!\\ name is choosed by sender)" | |
435 ), | |
436 ) | |
437 self.parser.add_argument( | |
438 "--path", | |
439 default=".", | |
440 metavar="DIR", | |
441 help=_(u"destination path (default: working directory)"), | |
442 ) | |
299 | 443 |
300 def start(self): | 444 def start(self): |
301 self.bare_jids = [jid.JID(jid_).bare for jid_ in self.args.jids] | 445 self.bare_jids = [jid.JID(jid_).bare for jid_ in self.args.jids] |
302 self.path = os.path.abspath(self.args.path) | 446 self.path = os.path.abspath(self.args.path) |
303 if not os.path.isdir(self.path): | 447 if not os.path.isdir(self.path): |
304 self.disp(_(u"Given path is not a directory !", error=True)) | 448 self.disp(_(u"Given path is not a directory !", error=True)) |
305 self.host.quit(2) | 449 self.host.quit(2) |
306 if self.args.multiple: | 450 if self.args.multiple: |
307 self.host.quit_on_progress_end = False | 451 self.host.quit_on_progress_end = False |
308 self.disp(_(u"waiting for incoming file request"),2) | 452 self.disp(_(u"waiting for incoming file request"), 2) |
309 | 453 |
310 | 454 |
311 class Upload(base.CommandBase): | 455 class Upload(base.CommandBase): |
312 | |
313 def __init__(self, host): | 456 def __init__(self, host): |
314 super(Upload, self).__init__(host, 'upload', use_progress=True, use_verbose=True, help=_('upload a file')) | 457 super(Upload, self).__init__( |
315 self.need_loop=True | 458 host, "upload", use_progress=True, use_verbose=True, help=_("upload a file") |
459 ) | |
460 self.need_loop = True | |
316 | 461 |
317 def add_parser_options(self): | 462 def add_parser_options(self): |
318 self.parser.add_argument("file", type=str, help=_("file to upload")) | 463 self.parser.add_argument("file", type=str, help=_("file to upload")) |
319 self.parser.add_argument("jid", type=base.unicode_decoder, nargs='?', help=_("jid of upload component (nothing to autodetect)")) | 464 self.parser.add_argument( |
320 self.parser.add_argument("--ignore-tls-errors", action="store_true", help=_("ignore invalide TLS certificate")) | 465 "jid", |
466 type=base.unicode_decoder, | |
467 nargs="?", | |
468 help=_("jid of upload component (nothing to autodetect)"), | |
469 ) | |
470 self.parser.add_argument( | |
471 "--ignore-tls-errors", | |
472 action="store_true", | |
473 help=_("ignore invalide TLS certificate"), | |
474 ) | |
321 | 475 |
322 def onProgressStarted(self, metadata): | 476 def onProgressStarted(self, metadata): |
323 self.disp(_(u'File upload started'),2) | 477 self.disp(_(u"File upload started"), 2) |
324 | 478 |
325 def onProgressFinished(self, metadata): | 479 def onProgressFinished(self, metadata): |
326 self.disp(_(u'File uploaded successfully'),2) | 480 self.disp(_(u"File uploaded successfully"), 2) |
327 try: | 481 try: |
328 url = metadata['url'] | 482 url = metadata["url"] |
329 except KeyError: | 483 except KeyError: |
330 self.disp(u'download URL not found in metadata') | 484 self.disp(u"download URL not found in metadata") |
331 else: | 485 else: |
332 self.disp(_(u'URL to retrieve the file:'),1) | 486 self.disp(_(u"URL to retrieve the file:"), 1) |
333 # XXX: url is display alone on a line to make parsing easier | 487 # XXX: url is display alone on a line to make parsing easier |
334 self.disp(url) | 488 self.disp(url) |
335 | 489 |
336 def onProgressError(self, error_msg): | 490 def onProgressError(self, error_msg): |
337 self.disp(_(u'Error while uploading file: {}').format(error_msg),error=True) | 491 self.disp(_(u"Error while uploading file: {}").format(error_msg), error=True) |
338 | 492 |
339 def gotId(self, data, file_): | 493 def gotId(self, data, file_): |
340 """Called when a progress id has been received | 494 """Called when a progress id has been received |
341 | 495 |
342 @param pid(unicode): progress id | 496 @param pid(unicode): progress id |
343 @param file_(str): file path | 497 @param file_(str): file path |
344 """ | 498 """ |
345 try: | 499 try: |
346 self.progress_id = data['progress'] | 500 self.progress_id = data["progress"] |
347 except KeyError: | 501 except KeyError: |
348 # TODO: if 'xmlui' key is present, manage xmlui message display | 502 # TODO: if 'xmlui' key is present, manage xmlui message display |
349 self.disp(_(u"Can't upload file"), error=True) | 503 self.disp(_(u"Can't upload file"), error=True) |
350 self.host.quit(2) | 504 self.host.quit(2) |
351 | 505 |
352 def error(self, failure): | 506 def error(self, failure): |
353 self.disp(_("Error while trying to upload a file: {reason}").format(reason=failure), error=True) | 507 self.disp( |
508 _("Error while trying to upload a file: {reason}").format(reason=failure), | |
509 error=True, | |
510 ) | |
354 self.host.quit(1) | 511 self.host.quit(1) |
355 | 512 |
356 def start(self): | 513 def start(self): |
357 file_ = self.args.file | 514 file_ = self.args.file |
358 if not os.path.exists(file_): | 515 if not os.path.exists(file_): |
360 self.host.quit(1) | 517 self.host.quit(1) |
361 if os.path.isdir(file_): | 518 if os.path.isdir(file_): |
362 self.disp(_(u"[{}] is a dir! Can't upload a dir").format(file_)) | 519 self.disp(_(u"[{}] is a dir! Can't upload a dir").format(file_)) |
363 self.host.quit(1) | 520 self.host.quit(1) |
364 | 521 |
365 self.full_dest_jid = self.host.get_full_jid(self.args.jid) if self.args.jid is not None else '' | 522 self.full_dest_jid = ( |
523 self.host.get_full_jid(self.args.jid) if self.args.jid is not None else "" | |
524 ) | |
366 options = {} | 525 options = {} |
367 if self.args.ignore_tls_errors: | 526 if self.args.ignore_tls_errors: |
368 options['ignore_tls_errors'] = C.BOOL_TRUE | 527 options["ignore_tls_errors"] = C.BOOL_TRUE |
369 | 528 |
370 path = os.path.abspath(file_) | 529 path = os.path.abspath(file_) |
371 self.host.bridge.fileUpload(path, '', self.full_dest_jid, options, self.profile, callback=lambda pid, file_=file_: self.gotId(pid, file_), errback=self.error) | 530 self.host.bridge.fileUpload( |
531 path, | |
532 "", | |
533 self.full_dest_jid, | |
534 options, | |
535 self.profile, | |
536 callback=lambda pid, file_=file_: self.gotId(pid, file_), | |
537 errback=self.error, | |
538 ) | |
372 | 539 |
373 | 540 |
374 class ShareList(base.CommandBase): | 541 class ShareList(base.CommandBase): |
375 | |
376 def __init__(self, host): | 542 def __init__(self, host): |
377 extra_outputs = {'default': self.default_output} | 543 extra_outputs = {"default": self.default_output} |
378 super(ShareList, self).__init__(host, 'list', use_output=C.OUTPUT_LIST_DICT, extra_outputs=extra_outputs, help=_(u'retrieve files shared by an entity'), use_verbose=True) | 544 super(ShareList, self).__init__( |
379 self.need_loop=True | 545 host, |
546 "list", | |
547 use_output=C.OUTPUT_LIST_DICT, | |
548 extra_outputs=extra_outputs, | |
549 help=_(u"retrieve files shared by an entity"), | |
550 use_verbose=True, | |
551 ) | |
552 self.need_loop = True | |
380 | 553 |
381 def add_parser_options(self): | 554 def add_parser_options(self): |
382 self.parser.add_argument("-d", "--path", default=u'', help=_(u"path to the directory containing the files")) | 555 self.parser.add_argument( |
383 self.parser.add_argument("jid", type=base.unicode_decoder, nargs='?', default='', help=_("jid of sharing entity (nothing to check our own jid)")) | 556 "-d", |
557 "--path", | |
558 default=u"", | |
559 help=_(u"path to the directory containing the files"), | |
560 ) | |
561 self.parser.add_argument( | |
562 "jid", | |
563 type=base.unicode_decoder, | |
564 nargs="?", | |
565 default="", | |
566 help=_("jid of sharing entity (nothing to check our own jid)"), | |
567 ) | |
384 | 568 |
385 def file_gen(self, files_data): | 569 def file_gen(self, files_data): |
386 for file_data in files_data: | 570 for file_data in files_data: |
387 yield file_data[u'name'] | 571 yield file_data[u"name"] |
388 yield file_data.get(u'size', '') | 572 yield file_data.get(u"size", "") |
389 yield file_data.get(u'hash','') | 573 yield file_data.get(u"hash", "") |
390 | 574 |
391 def _name_filter(self, name, row): | 575 def _name_filter(self, name, row): |
392 if row.type == C.FILE_TYPE_DIRECTORY: | 576 if row.type == C.FILE_TYPE_DIRECTORY: |
393 return A.color(C.A_DIRECTORY, name) | 577 return A.color(C.A_DIRECTORY, name) |
394 elif row.type == C.FILE_TYPE_FILE: | 578 elif row.type == C.FILE_TYPE_FILE: |
395 return A.color(C.A_FILE, name) | 579 return A.color(C.A_FILE, name) |
396 else: | 580 else: |
397 self.disp(_(u'unknown file type: {type}').format(type=row.type), error=True) | 581 self.disp(_(u"unknown file type: {type}").format(type=row.type), error=True) |
398 return name | 582 return name |
399 | 583 |
400 def _size_filter(self, size, row): | 584 def _size_filter(self, size, row): |
401 if not size: | 585 if not size: |
402 return u'' | 586 return u"" |
403 size = int(size) | 587 size = int(size) |
404 # cf. https://stackoverflow.com/a/1094933 (thanks) | 588 # cf. https://stackoverflow.com/a/1094933 (thanks) |
405 suffix = u'o' | 589 suffix = u"o" |
406 for unit in [u'', u'Ki', u'Mi', u'Gi', u'Ti', u'Pi', u'Ei', u'Zi']: | 590 for unit in [u"", u"Ki", u"Mi", u"Gi", u"Ti", u"Pi", u"Ei", u"Zi"]: |
407 if abs(size) < 1024.0: | 591 if abs(size) < 1024.0: |
408 return A.color(A.BOLD, u"{:.2f}".format(size), unit, suffix) | 592 return A.color(A.BOLD, u"{:.2f}".format(size), unit, suffix) |
409 size /= 1024.0 | 593 size /= 1024.0 |
410 | 594 |
411 return A.color(A.BOLD, u"{:.2f}".format(size), u'Yi', suffix) | 595 return A.color(A.BOLD, u"{:.2f}".format(size), u"Yi", suffix) |
412 | 596 |
413 def default_output(self, files_data): | 597 def default_output(self, files_data): |
414 """display files a way similar to ls""" | 598 """display files a way similar to ls""" |
415 files_data.sort(key=lambda d: d['name'].lower()) | 599 files_data.sort(key=lambda d: d["name"].lower()) |
416 show_header = False | 600 show_header = False |
417 if self.verbosity == 0: | 601 if self.verbosity == 0: |
418 headers = (u'name', u'type') | 602 headers = (u"name", u"type") |
419 elif self.verbosity == 1: | 603 elif self.verbosity == 1: |
420 headers = (u'name', u'type', u'size') | 604 headers = (u"name", u"type", u"size") |
421 elif self.verbosity > 1: | 605 elif self.verbosity > 1: |
422 show_header = True | 606 show_header = True |
423 headers = (u'name', u'type', u'size', u'hash') | 607 headers = (u"name", u"type", u"size", u"hash") |
424 table = common.Table.fromDict(self.host, | 608 table = common.Table.fromDict( |
425 files_data, | 609 self.host, |
426 headers, | 610 files_data, |
427 filters={u'name': self._name_filter, | 611 headers, |
428 u'size': self._size_filter}, | 612 filters={u"name": self._name_filter, u"size": self._size_filter}, |
429 defaults={u'size': u'', | 613 defaults={u"size": u"", u"hash": u""}, |
430 u'hash': u''}, | 614 ) |
431 ) | 615 table.display_blank(show_header=show_header, hide_cols=["type"]) |
432 table.display_blank(show_header=show_header, hide_cols=['type']) | |
433 | 616 |
434 def _FISListCb(self, files_data): | 617 def _FISListCb(self, files_data): |
435 self.output(files_data) | 618 self.output(files_data) |
436 self.host.quit() | 619 self.host.quit() |
437 | 620 |
440 self.args.jid, | 623 self.args.jid, |
441 self.args.path, | 624 self.args.path, |
442 {}, | 625 {}, |
443 self.profile, | 626 self.profile, |
444 callback=self._FISListCb, | 627 callback=self._FISListCb, |
445 errback=partial(self.errback, | 628 errback=partial( |
446 msg=_(u"can't retrieve shared files: {}"), | 629 self.errback, |
447 exit_code=C.EXIT_BRIDGE_ERRBACK)) | 630 msg=_(u"can't retrieve shared files: {}"), |
631 exit_code=C.EXIT_BRIDGE_ERRBACK, | |
632 ), | |
633 ) | |
448 | 634 |
449 | 635 |
450 class SharePath(base.CommandBase): | 636 class SharePath(base.CommandBase): |
451 | |
452 def __init__(self, host): | 637 def __init__(self, host): |
453 super(SharePath, self).__init__(host, 'path', help=_(u'share a file or directory'), use_verbose=True) | 638 super(SharePath, self).__init__( |
454 self.need_loop=True | 639 host, "path", help=_(u"share a file or directory"), use_verbose=True |
640 ) | |
641 self.need_loop = True | |
455 | 642 |
456 def add_parser_options(self): | 643 def add_parser_options(self): |
457 self.parser.add_argument("-n", "--name", type=base.unicode_decoder, default=u'', help=_(u"virtual name to use (default: use directory/file name)")) | 644 self.parser.add_argument( |
645 "-n", | |
646 "--name", | |
647 type=base.unicode_decoder, | |
648 default=u"", | |
649 help=_(u"virtual name to use (default: use directory/file name)"), | |
650 ) | |
458 perm_group = self.parser.add_mutually_exclusive_group() | 651 perm_group = self.parser.add_mutually_exclusive_group() |
459 perm_group.add_argument("-j", "--jid", type=base.unicode_decoder, action='append', dest="jids", default=[], help=_(u"jid of contacts allowed to retrieve the files")) | 652 perm_group.add_argument( |
460 perm_group.add_argument("--public", action='store_true', help=_(u"share publicly the file(s) (/!\\ *everybody* will be able to access them)")) | 653 "-j", |
461 self.parser.add_argument("path", type=base.unicode_decoder, help=_(u"path to a file or directory to share")) | 654 "--jid", |
462 | 655 type=base.unicode_decoder, |
656 action="append", | |
657 dest="jids", | |
658 default=[], | |
659 help=_(u"jid of contacts allowed to retrieve the files"), | |
660 ) | |
661 perm_group.add_argument( | |
662 "--public", | |
663 action="store_true", | |
664 help=_( | |
665 u"share publicly the file(s) (/!\\ *everybody* will be able to access them)" | |
666 ), | |
667 ) | |
668 self.parser.add_argument( | |
669 "path", | |
670 type=base.unicode_decoder, | |
671 help=_(u"path to a file or directory to share"), | |
672 ) | |
463 | 673 |
464 def _FISSharePathCb(self, name): | 674 def _FISSharePathCb(self, name): |
465 self.disp(_(u'{path} shared under the name "{name}"').format( | 675 self.disp( |
466 path = self.path, | 676 _(u'{path} shared under the name "{name}"').format(path=self.path, name=name) |
467 name = name)) | 677 ) |
468 self.host.quit() | 678 self.host.quit() |
469 | 679 |
470 def start(self): | 680 def start(self): |
471 self.path = os.path.abspath(self.args.path) | 681 self.path = os.path.abspath(self.args.path) |
472 if self.args.public: | 682 if self.args.public: |
473 access = {u'read': {u'type': u'public'}} | 683 access = {u"read": {u"type": u"public"}} |
474 else: | 684 else: |
475 jids = self.args.jids | 685 jids = self.args.jids |
476 if jids: | 686 if jids: |
477 access = {u'read': {u'type': 'whitelist', | 687 access = {u"read": {u"type": "whitelist", u"jids": jids}} |
478 u'jids': jids}} | |
479 else: | 688 else: |
480 access = {} | 689 access = {} |
481 self.host.bridge.FISSharePath( | 690 self.host.bridge.FISSharePath( |
482 self.args.name, | 691 self.args.name, |
483 self.path, | 692 self.path, |
484 json.dumps(access, ensure_ascii=False), | 693 json.dumps(access, ensure_ascii=False), |
485 self.profile, | 694 self.profile, |
486 callback=self._FISSharePathCb, | 695 callback=self._FISSharePathCb, |
487 errback=partial(self.errback, | 696 errback=partial( |
488 msg=_(u"can't share path: {}"), | 697 self.errback, |
489 exit_code=C.EXIT_BRIDGE_ERRBACK)) | 698 msg=_(u"can't share path: {}"), |
699 exit_code=C.EXIT_BRIDGE_ERRBACK, | |
700 ), | |
701 ) | |
490 | 702 |
491 | 703 |
492 class Share(base.CommandBase): | 704 class Share(base.CommandBase): |
493 subcommands = (ShareList, SharePath) | 705 subcommands = (ShareList, SharePath) |
494 | 706 |
495 def __init__(self, host): | 707 def __init__(self, host): |
496 super(Share, self).__init__(host, 'share', use_profile=False, help=_(u'files sharing management')) | 708 super(Share, self).__init__( |
709 host, "share", use_profile=False, help=_(u"files sharing management") | |
710 ) | |
497 | 711 |
498 | 712 |
499 class File(base.CommandBase): | 713 class File(base.CommandBase): |
500 subcommands = (Send, Request, Receive, Upload, Share) | 714 subcommands = (Send, Request, Receive, Upload, Share) |
501 | 715 |
502 def __init__(self, host): | 716 def __init__(self, host): |
503 super(File, self).__init__(host, 'file', use_profile=False, help=_(u'files sending/receiving/management')) | 717 super(File, self).__init__( |
718 host, "file", use_profile=False, help=_(u"files sending/receiving/management") | |
719 ) |