]>
Commit | Line | Data |
---|---|---|
55fa2408 ER |
1 | From bc155a50edc5fa3023e2fceebf432403e903ce02 Mon Sep 17 00:00:00 2001 |
2 | From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> | |
3 | Date: Sun, 6 Apr 2014 13:47:59 +0300 | |
4 | Subject: [PATCH] merge download changes from nautilus-dropbox-1.6.1/dropbox.in | |
5 | ||
6 | http://linux.dropbox.com/packages/nautilus-dropbox-1.6.1.tar.bz2 | |
7 | --- | |
8 | caja-dropbox.in | 229 +++++++++++++++++++++++++++++++------------------------- | |
9 | 1 file changed, 128 insertions(+), 101 deletions(-) | |
10 | ||
11 | diff --git a/caja-dropbox.in b/caja-dropbox.in | |
12 | index abf7e82..8b063a4 100755 | |
13 | --- a/caja-dropbox.in | |
14 | +++ b/caja-dropbox.in | |
15 | @@ -1,6 +1,6 @@ | |
16 | #!/usr/bin/python | |
17 | # | |
18 | -# Copyright 2008 Evenflow, Inc. | |
19 | +# Copyright (c) Dropbox, Inc. | |
20 | # | |
21 | # dropbox | |
22 | # Dropbox frontend script | |
23 | @@ -22,7 +22,6 @@ | |
24 | from __future__ import with_statement | |
25 | ||
26 | import errno | |
27 | -import fcntl | |
28 | import locale | |
29 | import optparse | |
30 | import os | |
31 | @@ -35,8 +34,10 @@ import sys | |
32 | import tarfile | |
33 | import tempfile | |
34 | import threading | |
35 | +import thread | |
36 | import time | |
37 | -import urllib | |
38 | +import traceback | |
39 | +import urllib2 | |
40 | ||
41 | try: | |
42 | import gpgme | |
43 | @@ -47,9 +48,14 @@ from contextlib import closing, contextmanager | |
44 | from posixpath import curdir, sep, pardir, join, abspath, commonprefix | |
45 | ||
46 | INFO = u"Dropbox is the easiest way to share and store your files online. Want to learn more? Head to" | |
47 | -LINK = u"http://www.dropbox.com/" | |
48 | +LINK = u"https://www.dropbox.com/" | |
49 | WARNING = u"In order to use Dropbox, you must download the proprietary daemon." | |
50 | GPG_WARNING = u"Note: python-gpgme is not installed, we will not be able to verify binary signatures." | |
51 | +ERROR_CONNECTING = u"Trouble connecting to Dropbox servers. Maybe your internet connection is down, or you need to set your http_proxy environment variable." | |
52 | +ERROR_SIGNATURE = u"Downloaded binary does not match Dropbox signature, aborting install." | |
53 | + | |
54 | +DOWNLOAD_LOCATION_FMT = "https://www.dropbox.com/download?plat=%s" | |
55 | +SIGNATURE_LOCATION_FMT = "https://www.dropbox.com/download?plat=%s&signature=1" | |
56 | ||
57 | DOWNLOADING = u"Downloading Dropbox... %d%%" | |
58 | UNPACKING = u"Unpacking Dropbox... %d%%" | |
59 | @@ -60,7 +66,7 @@ DESKTOP_FILE = u"@DESKTOP_FILE_DIR@/dropbox.desktop" | |
60 | ||
61 | enc = locale.getpreferredencoding() | |
62 | ||
63 | -# Available from http://linux.dropbox.com/fedora/rpm-public-key.asc | |
64 | +# Available from https://linux.dropbox.com/fedora/rpm-public-key.asc | |
65 | DROPBOX_PUBLIC_KEY = """ | |
66 | -----BEGIN PGP PUBLIC KEY BLOCK----- | |
67 | Version: SKS 1.1.0 | |
68 | @@ -196,76 +202,58 @@ def gpgme_context(keys): | |
69 | del os.environ['GNUPGHOME'] | |
70 | shutil.rmtree(_gpghome, ignore_errors=True) | |
71 | ||
72 | +class SignatureVerifyError(Exception): | |
73 | + pass | |
74 | + | |
75 | def verify_signature(key_file, sig_file, plain_file): | |
76 | with gpgme_context([key_file]) as ctx: | |
77 | sigs = ctx.verify(sig_file, plain_file, None) | |
78 | return sigs[0].status == None | |
79 | ||
80 | -def download_file_chunk(socket, buf, size): | |
81 | +def download_file_chunk(url, buf): | |
82 | + opener = urllib2.build_opener() | |
83 | + opener.addheaders = [('User-Agent', "DropboxLinuxDownloader/@PACKAGE_VERSION@")] | |
84 | + sock = opener.open(url) | |
85 | + | |
86 | + size = int(sock.info()['content-length']) | |
87 | + bufsize = max(size / 200, 4096) | |
88 | progress = 0 | |
89 | - with closing(socket) as f: | |
90 | + | |
91 | + with closing(sock) as f: | |
92 | + yield (0, True) | |
93 | while True: | |
94 | try: | |
95 | - chunk = os.read(f.fileno(), 4096) | |
96 | + chunk = f.read(bufsize) | |
97 | progress += len(chunk) | |
98 | buf.write(chunk) | |
99 | - yield (progress, True) | |
100 | + yield (float(progress)/size, True) | |
101 | if progress == size: | |
102 | break | |
103 | except OSError, e: | |
104 | if hasattr(e, 'errno') and e.errno == errno.EAGAIN: | |
105 | # nothing left to read | |
106 | - yield (progress, False) | |
107 | + yield (float(progress)/size, False) | |
108 | else: | |
109 | raise | |
110 | ||
111 | -def download_uri_to_buffer(uri): | |
112 | - try: | |
113 | - socket = urllib.urlopen(uri) | |
114 | - except IOError: | |
115 | - FatalVisibleError("Trouble connecting to Dropbox servers. Maybe your internet connection is down, or you need to set your http_proxy environment variable.") | |
116 | - | |
117 | - fcntl.fcntl(socket, fcntl.F_SETFL, os.O_NONBLOCK) | |
118 | - size = int(socket.info()['content-length']) | |
119 | - | |
120 | - buf = StringIO.StringIO() | |
121 | - download_chunk = download_file_chunk(socket, buf, size) | |
122 | - | |
123 | - for _ in download_chunk: | |
124 | - pass | |
125 | - | |
126 | - buf.seek(0) | |
127 | - return buf | |
128 | - | |
129 | -# This sets a custom User-Agent | |
130 | -class DropboxURLopener(urllib.FancyURLopener): | |
131 | - version = "DropboxLinuxDownloader/@PACKAGE_VERSION@" | |
132 | -urllib._urlopener = DropboxURLopener() | |
133 | - | |
134 | class DownloadState(object): | |
135 | def __init__(self): | |
136 | - try: | |
137 | - self.socket = urllib.urlopen("http://www.dropbox.com/download?plat=%s" % plat()) | |
138 | - except IOError: | |
139 | - FatalVisibleError("Trouble connecting to Dropbox servers. Maybe your internet connection is down, or you need to set your http_proxy environment variable") | |
140 | - | |
141 | - fcntl.fcntl(self.socket, fcntl.F_SETFL, os.O_NONBLOCK) | |
142 | - self.size = int(self.socket.info()['content-length']) | |
143 | - | |
144 | self.local_file = StringIO.StringIO() | |
145 | - self.download_chunk = download_file_chunk(self.socket, self.local_file, self.size) | |
146 | ||
147 | def copy_data(self): | |
148 | - return self.download_chunk | |
149 | + return download_file_chunk(DOWNLOAD_LOCATION_FMT % plat(), self.local_file) | |
150 | ||
151 | def unpack(self): | |
152 | # download signature | |
153 | - signature = download_uri_to_buffer("http://www.dropbox.com/download?plat=%s&signature=1" % plat()) | |
154 | - | |
155 | + signature = StringIO.StringIO() | |
156 | + for _ in download_file_chunk(SIGNATURE_LOCATION_FMT % plat(), signature): | |
157 | + pass | |
158 | + signature.seek(0) | |
159 | self.local_file.seek(0) | |
160 | + | |
161 | if gpgme: | |
162 | if not verify_signature(StringIO.StringIO(DROPBOX_PUBLIC_KEY), signature, self.local_file): | |
163 | - FatalVisibleError("Downloaded binary does not match Dropbox signature, aborting install.") | |
164 | + raise SignatureVerifyError() | |
165 | ||
166 | self.local_file.seek(0) | |
167 | archive = tarfile.open(fileobj=self.local_file, mode='r:gz') | |
168 | @@ -296,6 +284,8 @@ if GUI_AVAILABLE: | |
169 | import pango | |
170 | import webbrowser | |
171 | ||
172 | + gtk.gdk.threads_init() | |
173 | + | |
174 | load_serialized_images() | |
175 | ||
176 | global FatalVisibleError | |
177 | @@ -310,9 +300,40 @@ if GUI_AVAILABLE: | |
178 | gtk.main_quit() | |
179 | sys.exit(-1) | |
180 | ||
181 | - def gtk_flush_events(): | |
182 | - while gtk.events_pending(): | |
183 | - gtk.main_iteration() | |
184 | + class GeneratorTask(object): | |
185 | + def __init__(self, generator, loop_callback, on_done=None, on_exception=None): | |
186 | + self.generator = generator | |
187 | + self.loop_callback = loop_callback | |
188 | + self.on_done = on_done | |
189 | + self.on_exception = on_exception | |
190 | + | |
191 | + def _run(self, *args, **kwargs): | |
192 | + self._stopped = False | |
193 | + try: | |
194 | + for ret in self.generator(*args, **kwargs): | |
195 | + if ret is None: | |
196 | + ret = () | |
197 | + if not isinstance(ret, tuple): | |
198 | + ret = (ret,) | |
199 | + gobject.idle_add(self.loop_callback, *ret) | |
200 | + | |
201 | + if self._stopped: | |
202 | + thread.exit() | |
203 | + except Exception, ex: | |
204 | + print ex | |
205 | + if self.on_exception is not None: | |
206 | + gobject.idle_add(self.on_exception, ex) | |
207 | + else: | |
208 | + if self.on_done is not None: | |
209 | + gobject.idle_add(self.on_done) | |
210 | + | |
211 | + def start(self, *args, **kwargs): | |
212 | + t = threading.Thread(target=self._run, args=args, kwargs=kwargs) | |
213 | + t.setDaemon(True) | |
214 | + t.start() | |
215 | + | |
216 | + def stop(self): | |
217 | + self._stopped = True | |
218 | ||
219 | class DownloadDialog(gtk.Dialog): | |
220 | def handle_delete_event(self, wid, ev, data=None): | |
221 | @@ -322,8 +343,8 @@ if GUI_AVAILABLE: | |
222 | reroll_autostart(not button.get_active()) | |
223 | ||
224 | def handle_cancel(self, button): | |
225 | - if self.watch: | |
226 | - gobject.source_remove(self.watch) | |
227 | + if self.task: | |
228 | + self.task.stop() | |
229 | if self.download: | |
230 | self.download.cancel() | |
231 | gtk.main_quit() | |
232 | @@ -333,51 +354,51 @@ if GUI_AVAILABLE: | |
233 | # begin download | |
234 | self.ok.hide() | |
235 | self.download = DownloadState() | |
236 | - self.one_chunk = self.download.copy_data() | |
237 | - self.watch = gobject.io_add_watch(self.download.socket, | |
238 | - gobject.IO_IN | | |
239 | - gobject.IO_PRI | | |
240 | - gobject.IO_ERR | | |
241 | - gobject.IO_HUP, | |
242 | - self.handle_data_waiting) | |
243 | + | |
244 | self.label.hide() | |
245 | - self.dont_show_again_align.hide() | |
246 | + if self.dont_show_again_align is not None: | |
247 | + self.dont_show_again_align.hide() | |
248 | self.progress.show() | |
249 | ||
250 | - def update_progress(self, text, fraction): | |
251 | - self.progress.set_text(text % int(fraction*100)) | |
252 | - self.progress.set_fraction(fraction) | |
253 | - gtk_flush_events() | |
254 | + def download_progress(progress, status): | |
255 | + if not status: | |
256 | + self.task.stop() | |
257 | + self.update_progress(DOWNLOADING, progress) | |
258 | ||
259 | - def handle_data_waiting(self, fd, condition): | |
260 | - if condition == gobject.IO_HUP: | |
261 | - FatalVisibleError("Connection to server unexpectedly closed.") | |
262 | - elif condition == gobject.IO_ERR: | |
263 | - FatalVisibleError("Unexpected error occurred with download.") | |
264 | - try: | |
265 | - while True: | |
266 | - progress, status = self.one_chunk.next() | |
267 | - if not status: | |
268 | - break | |
269 | - self.update_progress(DOWNLOADING, float(progress)/self.download.size) | |
270 | - except StopIteration: | |
271 | + def finished(): | |
272 | self.update_progress(DOWNLOADING, 1.0) | |
273 | self.unpack_dropbox() | |
274 | - return False | |
275 | - else: | |
276 | - self.update_progress(DOWNLOADING, float(progress)/self.download.size) | |
277 | - return True | |
278 | + | |
279 | + def error(ex): | |
280 | + FatalVisibleError(ERROR_CONNECTING) | |
281 | + | |
282 | + self.update_progress(DOWNLOADING, 0) | |
283 | + self.task = GeneratorTask(self.download.copy_data, | |
284 | + download_progress, | |
285 | + finished, error).start() | |
286 | + | |
287 | + def update_progress(self, text, fraction): | |
288 | + self.progress.set_text(text % int(fraction*100)) | |
289 | + self.progress.set_fraction(fraction) | |
290 | ||
291 | def unpack_dropbox(self): | |
292 | - one_member = self.download.unpack() | |
293 | - try: | |
294 | - while True: | |
295 | - name, i, total = one_member.next() | |
296 | - self.update_progress(UNPACKING, float(i)/total) | |
297 | - except StopIteration: | |
298 | + def unpack_progress(name, i, total): | |
299 | + self.update_progress(UNPACKING, float(i)/total) | |
300 | + | |
301 | + def finished(): | |
302 | self.update_progress(UNPACKING, 1.0) | |
303 | gtk.main_quit() | |
304 | ||
305 | + def error(ex): | |
306 | + if isinstance(ex, SignatureVerifyError): | |
307 | + FatalVisibleError(ERROR_SIGNATURE) | |
308 | + else: | |
309 | + FatalVisibleError(ERROR_CONNECTING) | |
310 | + | |
311 | + self.task = GeneratorTask(self.download.unpack, | |
312 | + unpack_progress, | |
313 | + finished, error).start() | |
314 | + | |
315 | def mouse_down(self, widget, event): | |
316 | if self.hovering: | |
317 | self.clicked_link = True | |
318 | @@ -406,7 +427,6 @@ if GUI_AVAILABLE: | |
319 | title = "Dropbox Installation") | |
320 | ||
321 | self.download = None | |
322 | - self.watch = None | |
323 | self.hovering = False | |
324 | self.clicked_link = False | |
325 | self.user_cancelled = False | |
326 | @@ -458,6 +478,8 @@ if GUI_AVAILABLE: | |
327 | ||
328 | self.vbox.add(self.hbox) | |
329 | ||
330 | + self.dont_show_again_align = None | |
331 | + | |
332 | try: | |
333 | if can_reroll_autostart(): | |
334 | dont_show_again = gtk.CheckButton("_Don't show this again") | |
335 | @@ -477,7 +499,6 @@ if GUI_AVAILABLE: | |
336 | ||
337 | self.set_resizable(False) | |
338 | except: | |
339 | - import traceback | |
340 | traceback.print_exc() | |
341 | ||
342 | self.ok.grab_focus() | |
343 | @@ -526,24 +547,27 @@ else: | |
344 | return | |
345 | ||
346 | download = DownloadState() | |
347 | - one_chunk = download.copy_data() | |
348 | ||
349 | try: | |
350 | - while True: | |
351 | - progress = one_chunk.next()[0] | |
352 | - setprogress(DOWNLOADING, float(progress)/download.size) | |
353 | - except StopIteration: | |
354 | + for progress, status in download.copy_data(): | |
355 | + if not status: | |
356 | + break | |
357 | + setprogress(DOWNLOADING, progress) | |
358 | + except Exception: | |
359 | + FatalVisibleError(ERROR_CONNECTING) | |
360 | + else: | |
361 | setprogress(DOWNLOADING, 1.0) | |
362 | console_print() | |
363 | write(save) | |
364 | ||
365 | - one_member = download.unpack() | |
366 | - | |
367 | try: | |
368 | - while True: | |
369 | - name, i, total = one_member.next() | |
370 | + for name, i, total in download.unpack(): | |
371 | setprogress(UNPACKING, float(i)/total) | |
372 | - except StopIteration: | |
373 | + except SignatureVerifyError: | |
374 | + FatalVisibleError(ERROR_SIGNATURE) | |
375 | + except Exception: | |
376 | + FatalVisibleError(ERROR_CONNECTING) | |
377 | + else: | |
378 | setprogress(UNPACKING, 1.0) | |
379 | ||
380 | console_print() | |
381 | @@ -788,9 +812,8 @@ def columnize(list, display_list=None, display_width=None): | |
382 | original_texts = texts[:] | |
383 | for col in range(len(texts)): | |
384 | texts[col] = texts[col].ljust(colwidths[col]) | |
385 | - line = u"%s" % " ".join(texts) | |
386 | - for i, text in enumerate(original_texts): | |
387 | - line = line.replace(text, display_texts[i]) | |
388 | + texts[col] = texts[col].replace(original_texts[col], display_texts[col]) | |
389 | + line = u" ".join(texts) | |
390 | lines.append(line) | |
391 | for line in lines: | |
392 | console_print(line) | |
393 | @@ -932,6 +955,10 @@ options: | |
394 | else: | |
395 | if len(args) == 0: | |
396 | args = [name for name in sorted(os.listdir(u"."), key=methodcaller('lower')) if type(name) == unicode] | |
397 | + if len(args) == 0: | |
398 | + # Bail early if there's nothing to list to avoid crashing on indent below | |
399 | + console_print(u"<empty>") | |
400 | + return | |
401 | indent = max(len(st)+1 for st in args) | |
402 | for file in args: | |
403 | ||
404 | @@ -1228,7 +1255,7 @@ options: | |
405 | try: | |
406 | download() | |
407 | except: | |
408 | - pass | |
409 | + traceback.print_exc() | |
410 | else: | |
411 | if GUI_AVAILABLE: | |
412 | start_dropbox() | |
413 | -- | |
414 | 1.9.1 | |
415 |