summaryrefslogtreecommitdiff
path: root/caja-dropbox.in
diff options
context:
space:
mode:
Diffstat (limited to 'caja-dropbox.in')
-rwxr-xr-xcaja-dropbox.in230
1 files changed, 129 insertions, 101 deletions
diff --git a/caja-dropbox.in b/caja-dropbox.in
index 7b2c3b9..02f9519 100755
--- a/caja-dropbox.in
+++ b/caja-dropbox.in
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Copyright 2008 Evenflow, Inc.
+# Copyright (c) Dropbox, Inc.
#
# dropbox
# Dropbox frontend script
@@ -22,7 +22,6 @@
from __future__ import with_statement
import errno
-import fcntl
import locale
import optparse
import os
@@ -35,8 +34,10 @@ import sys
import tarfile
import tempfile
import threading
+import thread
import time
-import urllib
+import traceback
+import urllib2
try:
import gpgme
@@ -47,9 +48,14 @@ from contextlib import closing, contextmanager
from posixpath import curdir, sep, pardir, join, abspath, commonprefix
INFO = u"Dropbox is the easiest way to share and store your files online. Want to learn more? Head to"
-LINK = u"http://www.dropbox.com/"
+LINK = u"https://www.dropbox.com/"
WARNING = u"In order to use Dropbox, you must download the proprietary daemon."
GPG_WARNING = u"Note: python-gpgme is not installed, we will not be able to verify binary signatures."
+ERROR_CONNECTING = u"Trouble connecting to Dropbox servers. Maybe your internet connection is down, or you need to set your http_proxy environment variable."
+ERROR_SIGNATURE = u"Downloaded binary does not match Dropbox signature, aborting install."
+
+DOWNLOAD_LOCATION_FMT = "https://www.dropbox.com/download?plat=%s"
+SIGNATURE_LOCATION_FMT = "https://www.dropbox.com/download?plat=%s&signature=1"
DOWNLOADING = u"Downloading Dropbox... %d%%"
UNPACKING = u"Unpacking Dropbox... %d%%"
@@ -60,7 +66,7 @@ DESKTOP_FILE = u"@DESKTOP_FILE_DIR@/caja-dropbox.desktop"
enc = locale.getpreferredencoding()
-# Available from http://linux.dropbox.com/fedora/rpm-public-key.asc
+# Available from https://linux.dropbox.com/fedora/rpm-public-key.asc
DROPBOX_PUBLIC_KEY = """
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.0
@@ -196,76 +202,58 @@ def gpgme_context(keys):
del os.environ['GNUPGHOME']
shutil.rmtree(_gpghome, ignore_errors=True)
+class SignatureVerifyError(Exception):
+ pass
+
def verify_signature(key_file, sig_file, plain_file):
with gpgme_context([key_file]) as ctx:
sigs = ctx.verify(sig_file, plain_file, None)
return sigs[0].status == None
-def download_file_chunk(socket, buf, size):
+def download_file_chunk(url, buf):
+ opener = urllib2.build_opener()
+ opener.addheaders = [('User-Agent', "DropboxLinuxDownloader/@PACKAGE_VERSION@")]
+ sock = opener.open(url)
+
+ size = int(sock.info()['content-length'])
+ bufsize = max(size / 200, 4096)
progress = 0
- with closing(socket) as f:
+
+ with closing(sock) as f:
+ yield (0, True)
while True:
try:
- chunk = os.read(f.fileno(), 4096)
+ chunk = f.read(bufsize)
progress += len(chunk)
buf.write(chunk)
- yield (progress, True)
+ yield (float(progress)/size, True)
if progress == size:
break
except OSError, e:
if hasattr(e, 'errno') and e.errno == errno.EAGAIN:
# nothing left to read
- yield (progress, False)
+ yield (float(progress)/size, False)
else:
raise
-def download_uri_to_buffer(uri):
- try:
- socket = urllib.urlopen(uri)
- except IOError:
- FatalVisibleError("Trouble connecting to Dropbox servers. Maybe your internet connection is down, or you need to set your http_proxy environment variable.")
-
- fcntl.fcntl(socket, fcntl.F_SETFL, os.O_NONBLOCK)
- size = int(socket.info()['content-length'])
-
- buf = StringIO.StringIO()
- download_chunk = download_file_chunk(socket, buf, size)
-
- for _ in download_chunk:
- pass
-
- buf.seek(0)
- return buf
-
-# This sets a custom User-Agent
-class DropboxURLopener(urllib.FancyURLopener):
- version = "DropboxLinuxDownloader/@PACKAGE_VERSION@"
-urllib._urlopener = DropboxURLopener()
-
class DownloadState(object):
def __init__(self):
- try:
- self.socket = urllib.urlopen("http://www.dropbox.com/download?plat=%s" % plat())
- except IOError:
- FatalVisibleError("Trouble connecting to Dropbox servers. Maybe your internet connection is down, or you need to set your http_proxy environment variable")
-
- fcntl.fcntl(self.socket, fcntl.F_SETFL, os.O_NONBLOCK)
- self.size = int(self.socket.info()['content-length'])
-
self.local_file = StringIO.StringIO()
- self.download_chunk = download_file_chunk(self.socket, self.local_file, self.size)
def copy_data(self):
- return self.download_chunk
+ return download_file_chunk(DOWNLOAD_LOCATION_FMT % plat(), self.local_file)
def unpack(self):
# download signature
- signature = download_uri_to_buffer("http://www.dropbox.com/download?plat=%s&signature=1" % plat())
-
+ signature = StringIO.StringIO()
+ for _ in download_file_chunk(SIGNATURE_LOCATION_FMT % plat(), signature):
+ pass
+ signature.seek(0)
self.local_file.seek(0)
+
if gpgme:
if not verify_signature(StringIO.StringIO(DROPBOX_PUBLIC_KEY), signature, self.local_file):
- FatalVisibleError("Downloaded binary does not match Dropbox signature, aborting install.")
+ raise SignatureVerifyError()
self.local_file.seek(0)
archive = tarfile.open(fileobj=self.local_file, mode='r:gz')
@@ -296,6 +284,8 @@ if GUI_AVAILABLE:
import pango
import webbrowser
+ gtk.gdk.threads_init()
+
load_serialized_images()
global FatalVisibleError
@@ -310,9 +300,40 @@ if GUI_AVAILABLE:
gtk.main_quit()
sys.exit(-1)
- def gtk_flush_events():
- while gtk.events_pending():
- gtk.main_iteration()
+ class GeneratorTask(object):
+ def __init__(self, generator, loop_callback, on_done=None, on_exception=None):
+ self.generator = generator
+ self.loop_callback = loop_callback
+ self.on_done = on_done
+ self.on_exception = on_exception
+
+ def _run(self, *args, **kwargs):
+ self._stopped = False
+ try:
+ for ret in self.generator(*args, **kwargs):
+ if ret is None:
+ ret = ()
+ if not isinstance(ret, tuple):
+ ret = (ret,)
+ gobject.idle_add(self.loop_callback, *ret)
+
+ if self._stopped:
+ thread.exit()
+ except Exception, ex:
+ print ex
+ if self.on_exception is not None:
+ gobject.idle_add(self.on_exception, ex)
+ else:
+ if self.on_done is not None:
+ gobject.idle_add(self.on_done)
+
+ def start(self, *args, **kwargs):
+ t = threading.Thread(target=self._run, args=args, kwargs=kwargs)
+ t.setDaemon(True)
+ t.start()
+
+ def stop(self):
+ self._stopped = True
class DownloadDialog(gtk.Dialog):
def handle_delete_event(self, wid, ev, data=None):
@@ -322,8 +343,8 @@ if GUI_AVAILABLE:
reroll_autostart(not button.get_active())
def handle_cancel(self, button):
- if self.watch:
- gobject.source_remove(self.watch)
+ if self.task:
+ self.task.stop()
if self.download:
self.download.cancel()
gtk.main_quit()
@@ -333,51 +354,51 @@ if GUI_AVAILABLE:
# begin download
self.ok.hide()
self.download = DownloadState()
- self.one_chunk = self.download.copy_data()
- self.watch = gobject.io_add_watch(self.download.socket,
- gobject.IO_IN |
- gobject.IO_PRI |
- gobject.IO_ERR |
- gobject.IO_HUP,
- self.handle_data_waiting)
+
self.label.hide()
- self.dont_show_again_align.hide()
+ if self.dont_show_again_align is not None:
+ self.dont_show_again_align.hide()
self.progress.show()
- def update_progress(self, text, fraction):
- self.progress.set_text(text % int(fraction*100))
- self.progress.set_fraction(fraction)
- gtk_flush_events()
+ def download_progress(progress, status):
+ if not status:
+ self.task.stop()
+ self.update_progress(DOWNLOADING, progress)
- def handle_data_waiting(self, fd, condition):
- if condition == gobject.IO_HUP:
- FatalVisibleError("Connection to server unexpectedly closed.")
- elif condition == gobject.IO_ERR:
- FatalVisibleError("Unexpected error occurred with download.")
- try:
- while True:
- progress, status = self.one_chunk.next()
- if not status:
- break
- self.update_progress(DOWNLOADING, float(progress)/self.download.size)
- except StopIteration:
+ def finished():
self.update_progress(DOWNLOADING, 1.0)
self.unpack_dropbox()
- return False
- else:
- self.update_progress(DOWNLOADING, float(progress)/self.download.size)
- return True
+
+ def error(ex):
+ FatalVisibleError(ERROR_CONNECTING)
+
+ self.update_progress(DOWNLOADING, 0)
+ self.task = GeneratorTask(self.download.copy_data,
+ download_progress,
+ finished, error).start()
+
+ def update_progress(self, text, fraction):
+ self.progress.set_text(text % int(fraction*100))
+ self.progress.set_fraction(fraction)
def unpack_dropbox(self):
- one_member = self.download.unpack()
- try:
- while True:
- name, i, total = one_member.next()
- self.update_progress(UNPACKING, float(i)/total)
- except StopIteration:
+ def unpack_progress(name, i, total):
+ self.update_progress(UNPACKING, float(i)/total)
+
+ def finished():
self.update_progress(UNPACKING, 1.0)
gtk.main_quit()
+ def error(ex):
+ if isinstance(ex, SignatureVerifyError):
+ FatalVisibleError(ERROR_SIGNATURE)
+ else:
+ FatalVisibleError(ERROR_CONNECTING)
+
+ self.task = GeneratorTask(self.download.unpack,
+ unpack_progress,
+ finished, error).start()
+
def mouse_down(self, widget, event):
if self.hovering:
self.clicked_link = True
@@ -406,10 +427,10 @@ if GUI_AVAILABLE:
title = "Dropbox Installation")
self.download = None
- self.watch = None
self.hovering = False
self.clicked_link = False
self.user_cancelled = False
+ self.task = None
self.ok = ok = gtk.Button(stock=gtk.STOCK_OK)
ok.connect('clicked', self.handle_ok)
@@ -458,6 +479,8 @@ if GUI_AVAILABLE:
self.vbox.add(self.hbox)
+ self.dont_show_again_align = None
+
try:
if can_reroll_autostart():
dont_show_again = gtk.CheckButton("_Don't show this again")
@@ -477,7 +500,6 @@ if GUI_AVAILABLE:
self.set_resizable(False)
except:
- import traceback
traceback.print_exc()
self.ok.grab_focus()
@@ -526,24 +548,27 @@ else:
return
download = DownloadState()
- one_chunk = download.copy_data()
try:
- while True:
- progress = one_chunk.next()[0]
- setprogress(DOWNLOADING, float(progress)/download.size)
- except StopIteration:
+ for progress, status in download.copy_data():
+ if not status:
+ break
+ setprogress(DOWNLOADING, progress)
+ except Exception:
+ FatalVisibleError(ERROR_CONNECTING)
+ else:
setprogress(DOWNLOADING, 1.0)
console_print()
write(save)
- one_member = download.unpack()
-
try:
- while True:
- name, i, total = one_member.next()
+ for name, i, total in download.unpack():
setprogress(UNPACKING, float(i)/total)
- except StopIteration:
+ except SignatureVerifyError:
+ FatalVisibleError(ERROR_SIGNATURE)
+ except Exception:
+ FatalVisibleError(ERROR_CONNECTING)
+ else:
setprogress(UNPACKING, 1.0)
console_print()
@@ -788,9 +813,8 @@ def columnize(list, display_list=None, display_width=None):
original_texts = texts[:]
for col in range(len(texts)):
texts[col] = texts[col].ljust(colwidths[col])
- line = u"%s" % " ".join(texts)
- for i, text in enumerate(original_texts):
- line = line.replace(text, display_texts[i])
+ texts[col] = texts[col].replace(original_texts[col], display_texts[col])
+ line = u" ".join(texts)
lines.append(line)
for line in lines:
console_print(line)
@@ -932,6 +956,10 @@ options:
else:
if len(args) == 0:
args = [name for name in sorted(os.listdir(u"."), key=methodcaller('lower')) if type(name) == unicode]
+ if len(args) == 0:
+ # Bail early if there's nothing to list to avoid crashing on indent below
+ console_print(u"<empty>")
+ return
indent = max(len(st)+1 for st in args)
for file in args:
@@ -1228,7 +1256,7 @@ options:
try:
download()
except:
- pass
+ traceback.print_exc()
else:
if GUI_AVAILABLE:
start_dropbox()