diff --git a/onionshare/onionshare.py b/onionshare/onionshare.py
index f47a4c42..ca000c7a 100644
--- a/onionshare/onionshare.py
+++ b/onionshare/onionshare.py
@@ -39,10 +39,14 @@ class OnionShare(object):
self.port = tmpsock.getsockname()[1]
tmpsock.close()
- def start_hidden_service(self):
+ def start_hidden_service(self, gui=False):
if helpers.get_platform() == 'Tails':
# in Tails, start the hidden service in a root process
- p = subprocess.Popen(['/usr/bin/sudo', '--', '/usr/bin/onionshare', str(app.port)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+ if gui:
+ args = ['/usr/bin/gksudo', '-D', 'OnionShare', '--', '/usr/bin/onionshare']
+ else:
+ args = ['/usr/bin/sudo', '--', '/usr/bin/onionshare']
+ p = subprocess.Popen(args+[str(app.port)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
stdout = p.stdout.read(22) # .onion URLs are 22 chars long
if stdout:
diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py
index efa0d56e..35780c57 100644
--- a/onionshare_gui/onionshare_gui.py
+++ b/onionshare_gui/onionshare_gui.py
@@ -1,41 +1,33 @@
from __future__ import division
-import os, sys, subprocess, inspect, platform, argparse, threading, time, math
+import os, sys, subprocess, inspect, platform, argparse, threading, time, math, inspect, platform
from PyQt4 import QtCore, QtGui
-if platform.system() == 'Darwin':
- onionshare_gui_dir = os.path.dirname(__file__)
-else:
- onionshare_gui_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+def get_onionshare_gui_dir():
+ if platform.system() == 'Darwin':
+ onionshare_gui_dir = os.path.dirname(__file__)
+ else:
+ onionshare_gui_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+ return onionshare_gui_dir
try:
import onionshare
except ImportError:
- sys.path.append(os.path.abspath(onionshare_gui_dir+"/.."))
+ sys.path.append(os.path.abspath(__file__+"/.."))
import onionshare
-from onionshare import translated
-
-app = None
-window_icon = None
-onion_host = None
-port = None
-progress = None
-
-# request types
-REQUEST_LOAD = 0
-REQUEST_DOWNLOAD = 1
-REQUEST_PROGRESS = 2
-REQUEST_OTHER = 3
+from onionshare import strings, helpers, web
class Application(QtGui.QApplication):
def __init__(self):
- platform = onionshare.get_platform()
+ platform = helpers.get_platform()
if platform == 'Tails' or platform == 'Linux':
self.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
QtGui.QApplication.__init__(self, sys.argv)
class OnionShareGui(QtGui.QWidget):
- def __init__(self, filename, basename):
+ def __init__(self, app, filename, basename):
super(OnionShareGui, self).__init__()
+ self.app = app
+
# initialize ui
self.init_ui(filename, basename)
# check for requests every 1000ms
@@ -72,7 +64,7 @@ class OnionShareGui(QtGui.QWidget):
# logo
self.logoLabel = QtGui.QLabel(self.widget)
- self.logo = QtGui.QPixmap("{0}/static/logo.png".format(onionshare_gui_dir))
+ self.logo = QtGui.QPixmap("{0}/static/logo.png".format(get_onionshare_gui_dir()))
self.logoLabel.setPixmap(self.logo)
self.header.addWidget(self.logoLabel)
@@ -127,7 +119,7 @@ class OnionShareGui(QtGui.QWidget):
# close automatically checkbox
self.closeAutomatically = QtGui.QCheckBox(self.widget)
self.closeAutomatically.setCheckState(QtCore.Qt.Checked)
- if onionshare.get_stay_open():
+ if web.get_stay_open():
self.closeAutomatically.setCheckState(QtCore.Qt.Unchecked)
self.closeAutomatically.setStyleSheet("font-size: 12px")
@@ -145,41 +137,40 @@ class OnionShareGui(QtGui.QWidget):
self.footer.addWidget(self.copyURL)
self.wrapper.addLayout(self.footer)
- url = 'http://{0}/{1}'.format(onion_host, onionshare.slug)
+ url = 'http://{0}/{1}'.format(self.app.onion_host, web.slug)
- filehash, filesize = onionshare.file_crunching(filename)
- onionshare.set_file_info(filename, filehash, filesize)
- onionshare.filesize = filesize
+ filehash, filesize = helpers.file_crunching(filename)
+ web.set_file_info(filename, filehash, filesize)
# start onionshare service in new thread
- t = threading.Thread(target=onionshare.app.run, kwargs={'port': port})
+ t = threading.Thread(target=web.start, args=(self.app.port, self.app.stay_open))
t.daemon = True
t.start()
# show url to share
- loaded = QtGui.QLabel(translated("give_this_url") + "
" + url + "")
+ loaded = QtGui.QLabel(strings._("give_this_url") + "
" + url + "")
loaded.setStyleSheet("color: #000000; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
loaded.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.log.addWidget(loaded)
# translate
self.filenameLabel.setText(basename)
- self.checksumLabel.setText(translated("sha1_checksum") + ": " + filehash + "")
- self.filesizeLabel.setText(translated("filesize") + ": " + onionshare.human_readable_filesize(filesize) + "")
- self.closeAutomatically.setText(translated("close_on_finish"))
- self.copyURL.setText(translated("copy_url"))
+ self.checksumLabel.setText(strings._("sha1_checksum") + ": " + filehash + "")
+ self.filesizeLabel.setText(strings._("filesize") + ": " + helpers.human_readable_filesize(filesize) + "")
+ self.closeAutomatically.setText(strings._("close_on_finish"))
+ self.copyURL.setText(strings._("copy_url"))
# show dialog
self.show()
def update_log(self, event, msg):
global progress
- if event["type"] == REQUEST_LOAD:
+ if event["type"] == web.REQUEST_LOAD:
label = QtGui.QLabel(msg)
label.setStyleSheet("color: #009900; font-weight: bold; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
label.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.log.addWidget(label)
- elif event["type"] == REQUEST_DOWNLOAD:
+ elif event["type"] == web.REQUEST_DOWNLOAD:
download = QtGui.QLabel(msg)
download.setStyleSheet("color: #009900; font-weight: bold; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
download.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
@@ -188,7 +179,7 @@ class OnionShareGui(QtGui.QWidget):
progress.setStyleSheet("color: #0000cc; font-weight: bold; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
progress.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.log.addWidget(progress)
- elif event["type"] == REQUEST_PROGRESS:
+ elif event["type"] == web.REQUEST_PROGRESS:
progress.setText(msg)
elif event["path"] != '/favicon.ico':
other = QtGui.QLabel(msg)
@@ -203,22 +194,22 @@ class OnionShareGui(QtGui.QWidget):
done = False
while not done:
try:
- r = onionshare.q.get(False)
+ r = web.q.get(False)
events.append(r)
- except onionshare.Queue.Empty:
+ except web.Queue.Empty:
done = True
for event in events:
- if event["type"] == REQUEST_LOAD:
- self.update_log(event, translated("download_page_loaded"))
- elif event["type"] == REQUEST_DOWNLOAD:
- self.update_log(event, translated("download_started"))
- elif event["type"] == REQUEST_PROGRESS:
+ if event["type"] == web.REQUEST_LOAD:
+ self.update_log(event, strings._("download_page_loaded"))
+ elif event["type"] == web.REQUEST_DOWNLOAD:
+ self.update_log(event, strings._("download_started"))
+ elif event["type"] == web.REQUEST_PROGRESS:
# is the download complete?
- if event["data"]["bytes"] == onionshare.filesize:
- self.update_log(event, translated("download_finished"))
+ if event["data"]["bytes"] == web.filesize:
+ self.update_log(event, strings._("download_finished"))
# close on finish?
- if not onionshare.get_stay_open():
+ if not web.get_stay_open():
time.sleep(1)
def close_countdown(i):
if i > 0:
@@ -226,28 +217,27 @@ class OnionShareGui(QtGui.QWidget):
else:
time.sleep(1)
i -= 1
- closing.setText(translated("close_countdown").format(str(i)))
- print translated("close_countdown").format(str(i))
+ closing.setText(strings._("close_countdown").format(str(i)))
+ print strings._("close_countdown").format(str(i))
close_countdown(i)
closing = QtGui.QLabel(self.widget)
closing.setStyleSheet("font-weight: bold; font-style: italic; font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
- closing.setText(translated("close_countdown").format("3"))
+ closing.setText(strings._("close_countdown").format("3"))
closing.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.log.addWidget(closing)
close_countdown(3)
# still in progress
else:
- percent = math.floor((event["data"]["bytes"] / onionshare.filesize) * 100)
- self.update_log(event, " " + onionshare.human_readable_filesize(event["data"]["bytes"]) + ', ' + str(percent) +'%')
+ percent = math.floor((event["data"]["bytes"] / web.filesize) * 100)
+ self.update_log(event, " " + helpers.human_readable_filesize(event["data"]["bytes"]) + ', ' + str(percent) +'%')
elif event["path"] != '/favicon.ico':
- self.update_log(event, translated("other_page_loaded"))
+ self.update_log(event, strings._("other_page_loaded"))
def copy_to_clipboard(self):
- global onion_host
- url = 'http://{0}/{1}'.format(onion_host, onionshare.slug)
+ url = 'http://{0}/{1}'.format(self.app.onion_host, web.slug)
if platform.system() == 'Windows':
# Qt's QClipboard isn't working in Windows
@@ -263,10 +253,10 @@ class OnionShareGui(QtGui.QWidget):
ctypes.windll.user32.SetClipboardData(1, hcd)
ctypes.windll.user32.CloseClipboard()
else:
- clipboard = app.clipboard()
+ clipboard = qtapp.clipboard()
clipboard.setText(url)
- copied = QtGui.QLabel(translated("copied_url"))
+ copied = QtGui.QLabel(strings._("copied_url"))
copied.setStyleSheet("font-size: 14px; padding: 5px 10px; border-bottom: 1px solid #cccccc;")
copied.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.log.addWidget(copied)
@@ -274,13 +264,12 @@ class OnionShareGui(QtGui.QWidget):
def stay_open_changed(self, state):
if state > 0:
- onionshare.set_stay_open(False)
+ web.set_stay_open(False)
else:
- onionshare.set_stay_open(True)
+ web.set_stay_open(True)
return
def alert(msg, icon=QtGui.QMessageBox.NoIcon):
- global window_icon
dialog = QtGui.QMessageBox()
dialog.setWindowTitle("OnionShare")
dialog.setWindowIcon(window_icon)
@@ -288,10 +277,10 @@ def alert(msg, icon=QtGui.QMessageBox.NoIcon):
dialog.setIcon(icon)
dialog.exec_()
-def select_file(strings, filename=None):
+def select_file(filename=None):
# get filename, either from argument or file chooser dialog
if not filename:
- filename = QtGui.QFileDialog.getOpenFileName(caption=translated('choose_file'), options=QtGui.QFileDialog.ReadOnly)
+ filename = QtGui.QFileDialog.getOpenFileName(caption=strings._('choose_file'), options=QtGui.QFileDialog.ReadOnly)
if not filename:
return False, False
@@ -299,7 +288,7 @@ def select_file(strings, filename=None):
# validate filename
if not os.path.isfile(filename):
- alert(translated("not_a_file").format(filename), QtGui.QMessageBox.Warning)
+ alert(strings._("not_a_file").format(filename), QtGui.QMessageBox.Warning)
return False, False
filename = os.path.abspath(filename)
@@ -307,19 +296,18 @@ def select_file(strings, filename=None):
return filename, basename
def main():
- global port
- onionshare.strings = onionshare.load_strings()
+ strings.load_strings()
# start the Qt app
- global app
- app = Application()
+ global qtapp
+ qtapp = Application()
# parse arguments
parser = argparse.ArgumentParser()
- parser.add_argument('--local-only', action='store_true', dest='local_only', help=translated("help_local_only"))
- parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=translated("help_stay_open"))
- parser.add_argument('--debug', action='store_true', dest='debug', help=translated("help_debug"))
- parser.add_argument('filename', nargs='?', help=translated("help_filename"))
+ parser.add_argument('--local-only', action='store_true', dest='local_only', help=strings._("help_local_only"))
+ parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=strings._("help_stay_open"))
+ parser.add_argument('--debug', action='store_true', dest='debug', help=strings._("help_debug"))
+ parser.add_argument('filename', nargs='?', help=strings._("help_filename"))
args = parser.parse_args()
filename = args.filename
@@ -327,60 +315,38 @@ def main():
stay_open = bool(args.stay_open)
debug = bool(args.debug)
- onionshare.set_stay_open(stay_open)
-
- if debug:
- onionshare.debug_mode()
+ web.set_stay_open(stay_open)
# create the onionshare icon
- global window_icon, onionshare_gui_dir
- window_icon = QtGui.QIcon("{0}/static/logo.png".format(onionshare_gui_dir))
+ global window_icon
+ window_icon = QtGui.QIcon("{0}/static/logo.png".format(get_onionshare_gui_dir()))
- # try starting hidden service
- global onion_host
- port = onionshare.choose_port()
- local_host = "127.0.0.1:{0}".format(port)
-
- if onionshare.get_platform() == 'Tails':
- # if this is tails, start the root process
- root_p = subprocess.Popen(['/usr/bin/gksudo', '-D', 'OnionShare', '--', '/usr/bin/onionshare', str(port)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
- stdout = root_p.stdout.read(22) # .onion URLs are 22 chars long
-
- if stdout:
- onion_host = stdout
- else:
- if root_p.poll() == -1:
- alert(root_p.stderr.read())
- return
- else:
- alert(translated("error_tails_unknown_root"))
- return
- else:
- # if not tails, start hidden service normally
- if not local_only:
- try:
- onion_host = onionshare.start_hidden_service(port)
- except onionshare.NoTor as e:
- alert(e.args[0], QtGui.QMessageBox.Warning)
- return
- else:
- onion_host = local_host
+ # start the onionshare app
+ try:
+ app = onionshare.OnionShare(debug, local_only, stay_open)
+ app.start_hidden_service(gui=True)
+ except onionshare.NoTor as e:
+ alert(e.args[0], QtGui.QMessageBox.Warning)
+ sys.exit()
+ except onionshare.TailsError as e:
+ alert(e.args[0], QtGui.QMessageBox.Warning)
+ sys.exit()
# select file to share
- filename, basename = select_file(onionshare.strings, filename)
+ filename, basename = select_file(filename)
if not filename:
return
# clean up when app quits
def shutdown():
- onionshare.execute_cleanup_handlers()
- app.connect(app, QtCore.SIGNAL("aboutToQuit()"), shutdown)
+ app.cleanup()
+ qtapp.connect(qtapp, QtCore.SIGNAL("aboutToQuit()"), shutdown)
# launch the gui
- gui = OnionShareGui(filename, basename)
+ gui = OnionShareGui(app, filename, basename)
# all done
- sys.exit(app.exec_())
+ sys.exit(qtapp.exec_())
if __name__ == '__main__':
main()