Format all code using black

This commit is contained in:
Micah Lee 2019-10-12 21:01:25 -07:00
parent 8010b279e7
commit 88e151d414
87 changed files with 4293 additions and 2374 deletions

View file

@ -32,22 +32,26 @@ from onionshare.onionshare import OnionShare
from .onionshare_gui import OnionShareGui
class Application(QtWidgets.QApplication):
"""
This is Qt's QApplication class. It has been overridden to support threads
and the quick keyboard shortcut.
"""
def __init__(self, common):
if common.platform == 'Linux' or common.platform == 'BSD':
if common.platform == "Linux" or common.platform == "BSD":
self.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
QtWidgets.QApplication.__init__(self, sys.argv)
self.installEventFilter(self)
def eventFilter(self, obj, event):
if (event.type() == QtCore.QEvent.KeyPress and
event.key() == QtCore.Qt.Key_Q and
event.modifiers() == QtCore.Qt.ControlModifier):
self.quit()
if (
event.type() == QtCore.QEvent.KeyPress
and event.key() == QtCore.Qt.Key_Q
and event.modifiers() == QtCore.Qt.ControlModifier
):
self.quit()
return False
@ -70,11 +74,34 @@ def main():
qtapp = Application(common)
# Parse arguments
parser = argparse.ArgumentParser(formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=48))
parser.add_argument('--local-only', action='store_true', dest='local_only', help="Don't use Tor (only for development)")
parser.add_argument('-v', '--verbose', action='store_true', dest='verbose', help="Log OnionShare errors to stdout, and web errors to disk")
parser.add_argument('--filenames', metavar='filenames', nargs='+', help="List of files or folders to share")
parser.add_argument('--config', metavar='config', default=False, help="Custom JSON config file location (optional)")
parser = argparse.ArgumentParser(
formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=48)
)
parser.add_argument(
"--local-only",
action="store_true",
dest="local_only",
help="Don't use Tor (only for development)",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
dest="verbose",
help="Log OnionShare errors to stdout, and web errors to disk",
)
parser.add_argument(
"--filenames",
metavar="filenames",
nargs="+",
help="List of files or folders to share",
)
parser.add_argument(
"--config",
metavar="config",
default=False,
help="Custom JSON config file location (optional)",
)
args = parser.parse_args()
filenames = args.filenames
@ -118,10 +145,12 @@ def main():
def shutdown():
onion.cleanup()
app.cleanup()
qtapp.aboutToQuit.connect(shutdown)
# All done
sys.exit(qtapp.exec_())
if __name__ == '__main__':
if __name__ == "__main__":
main()

View file

@ -29,10 +29,12 @@ from ..threads import OnionThread
from ..threads import AutoStartTimer
from ..widgets import Alert
class Mode(QtWidgets.QWidget):
"""
The class that all modes inherit from
"""
start_server_finished = QtCore.pyqtSignal()
stop_server_finished = QtCore.pyqtSignal()
starting_server_step2 = QtCore.pyqtSignal()
@ -41,7 +43,17 @@ class Mode(QtWidgets.QWidget):
starting_server_early = QtCore.pyqtSignal()
set_server_active = QtCore.pyqtSignal(bool)
def __init__(self, common, qtapp, app, status_bar, server_status_label, system_tray, filenames=None, local_only=False):
def __init__(
self,
common,
qtapp,
app,
status_bar,
server_status_label,
system_tray,
filenames=None,
local_only=False,
):
super(Mode, self).__init__()
self.common = common
self.qtapp = qtapp
@ -65,7 +77,9 @@ class Mode(QtWidgets.QWidget):
self.startup_thread = None
# Server status
self.server_status = ServerStatus(self.common, self.qtapp, self.app, None, self.local_only)
self.server_status = ServerStatus(
self.common, self.qtapp, self.app, None, self.local_only
)
self.server_status.server_started.connect(self.start_server)
self.server_status.server_stopped.connect(self.stop_server)
self.server_status.server_canceled.connect(self.cancel_server)
@ -98,16 +112,26 @@ class Mode(QtWidgets.QWidget):
"""
Returns a human-friendly time delta from given seconds.
"""
days = secs//86400
hours = (secs - days*86400)//3600
minutes = (secs - days*86400 - hours*3600)//60
seconds = secs - days*86400 - hours*3600 - minutes*60
days = secs // 86400
hours = (secs - days * 86400) // 3600
minutes = (secs - days * 86400 - hours * 3600) // 60
seconds = secs - days * 86400 - hours * 3600 - minutes * 60
if not seconds:
seconds = '0'
result = ("{0}{1}, ".format(days, strings._('days_first_letter')) if days else "") + \
("{0}{1}, ".format(hours, strings._('hours_first_letter')) if hours else "") + \
("{0}{1}, ".format(minutes, strings._('minutes_first_letter')) if minutes else "") + \
"{0}{1}".format(seconds, strings._('seconds_first_letter'))
seconds = "0"
result = (
("{0}{1}, ".format(days, strings._("days_first_letter")) if days else "")
+ (
"{0}{1}, ".format(hours, strings._("hours_first_letter"))
if hours
else ""
)
+ (
"{0}{1}, ".format(minutes, strings._("minutes_first_letter"))
if minutes
else ""
)
+ "{0}{1}".format(seconds, strings._("seconds_first_letter"))
)
return result
@ -120,25 +144,45 @@ class Mode(QtWidgets.QWidget):
if self.server_status.autostart_timer_datetime:
now = QtCore.QDateTime.currentDateTime()
if self.server_status.local_only:
seconds_remaining = now.secsTo(self.server_status.autostart_timer_widget.dateTime())
seconds_remaining = now.secsTo(
self.server_status.autostart_timer_widget.dateTime()
)
else:
seconds_remaining = now.secsTo(self.server_status.autostart_timer_datetime.replace(second=0, microsecond=0))
seconds_remaining = now.secsTo(
self.server_status.autostart_timer_datetime.replace(
second=0, microsecond=0
)
)
# Update the server button
if seconds_remaining > 0:
self.server_status.server_button.setText(strings._('gui_waiting_to_start').format(self.human_friendly_time(seconds_remaining)))
self.server_status.server_button.setText(
strings._("gui_waiting_to_start").format(
self.human_friendly_time(seconds_remaining)
)
)
else:
self.server_status.server_button.setText(strings._('gui_please_wait'))
self.server_status.server_button.setText(
strings._("gui_please_wait")
)
# If the auto-stop timer has stopped, stop the server
if self.server_status.status == ServerStatus.STATUS_STARTED:
if self.app.autostop_timer_thread and self.common.settings.get('autostop_timer'):
if self.app.autostop_timer_thread and self.common.settings.get(
"autostop_timer"
):
if self.autostop_timer_datetime_delta > 0:
now = QtCore.QDateTime.currentDateTime()
seconds_remaining = now.secsTo(self.server_status.autostop_timer_datetime)
seconds_remaining = now.secsTo(
self.server_status.autostop_timer_datetime
)
# Update the server button
server_button_text = self.get_stop_server_autostop_timer_text()
self.server_status.server_button.setText(server_button_text.format(self.human_friendly_time(seconds_remaining)))
self.server_status.server_button.setText(
server_button_text.format(
self.human_friendly_time(seconds_remaining)
)
)
self.status_bar.clearMessage()
if not self.app.autostop_timer_thread.is_alive():
@ -168,16 +212,16 @@ class Mode(QtWidgets.QWidget):
Start the onionshare server. This uses multiple threads to start the Tor onion
server and the web app.
"""
self.common.log('Mode', 'start_server')
self.common.log("Mode", "start_server")
self.start_server_custom()
self.set_server_active.emit(True)
self.app.set_stealth(self.common.settings.get('use_stealth'))
self.app.set_stealth(self.common.settings.get("use_stealth"))
# Clear the status bar
self.status_bar.clearMessage()
self.server_status_label.setText('')
self.server_status_label.setText("")
# Ensure we always get a new random port each time we might launch an OnionThread
self.app.port = None
@ -192,7 +236,7 @@ class Mode(QtWidgets.QWidget):
# If scheduling a share, delay starting the real share
if self.server_status.autostart_timer_datetime:
self.common.log('Mode', 'start_server', 'Starting auto-start timer')
self.common.log("Mode", "start_server", "Starting auto-start timer")
self.startup_thread = AutoStartTimer(self)
# Once the timer has finished, start the real share, with a WebThread
self.startup_thread.success.connect(self.start_scheduled_service)
@ -201,7 +245,7 @@ class Mode(QtWidgets.QWidget):
self.startup_thread.start()
def start_onion_thread(self, obtain_onion_early=False):
self.common.log('Mode', 'start_server', 'Starting an onion thread')
self.common.log("Mode", "start_server", "Starting an onion thread")
self.obtain_onion_early = obtain_onion_early
self.onion_thread = OnionThread(self)
self.onion_thread.success.connect(self.starting_server_step2.emit)
@ -213,7 +257,7 @@ class Mode(QtWidgets.QWidget):
# We start a new OnionThread with the saved scheduled key from settings
self.common.settings.load()
self.obtain_onion_early = obtain_onion_early
self.common.log('Mode', 'start_server', 'Starting a scheduled onion thread')
self.common.log("Mode", "start_server", "Starting a scheduled onion thread")
self.onion_thread = OnionThread(self)
self.onion_thread.success.connect(self.starting_server_step2.emit)
self.onion_thread.error.connect(self.starting_server_error.emit)
@ -237,7 +281,7 @@ class Mode(QtWidgets.QWidget):
"""
Step 2 in starting the onionshare server.
"""
self.common.log('Mode', 'start_server_step2')
self.common.log("Mode", "start_server_step2")
self.start_server_step2_custom()
@ -257,22 +301,28 @@ class Mode(QtWidgets.QWidget):
"""
Step 3 in starting the onionshare server.
"""
self.common.log('Mode', 'start_server_step3')
self.common.log("Mode", "start_server_step3")
self.start_server_step3_custom()
if self.common.settings.get('autostop_timer'):
if self.common.settings.get("autostop_timer"):
# Convert the date value to seconds between now and then
now = QtCore.QDateTime.currentDateTime()
self.autostop_timer_datetime_delta = now.secsTo(self.server_status.autostop_timer_datetime)
self.autostop_timer_datetime_delta = now.secsTo(
self.server_status.autostop_timer_datetime
)
# Start the auto-stop timer
if self.autostop_timer_datetime_delta > 0:
self.app.autostop_timer_thread = AutoStopTimer(self.common, self.autostop_timer_datetime_delta)
self.app.autostop_timer_thread = AutoStopTimer(
self.common, self.autostop_timer_datetime_delta
)
self.app.autostop_timer_thread.start()
# The auto-stop timer has actually already passed since the user clicked Start. Probably the Onion service took too long to start.
else:
self.stop_server()
self.start_server_error(strings._('gui_server_started_after_autostop_timer'))
self.start_server_error(
strings._("gui_server_started_after_autostop_timer")
)
def start_server_step3_custom(self):
"""
@ -284,7 +334,7 @@ class Mode(QtWidgets.QWidget):
"""
If there's an error when trying to start the onion service
"""
self.common.log('Mode', 'start_server_error')
self.common.log("Mode", "start_server_error")
Alert(self.common, error, QtWidgets.QMessageBox.Warning)
self.set_server_active.emit(False)
@ -305,16 +355,16 @@ class Mode(QtWidgets.QWidget):
"""
self.cancel_server_custom()
if self.startup_thread:
self.common.log('Mode', 'cancel_server: quitting startup thread')
self.common.log("Mode", "cancel_server: quitting startup thread")
self.startup_thread.canceled = True
self.app.onion.scheduled_key = None
self.app.onion.scheduled_auth_cookie = None
self.startup_thread.quit()
if self.onion_thread:
self.common.log('Mode', 'cancel_server: quitting onion thread')
self.common.log("Mode", "cancel_server: quitting onion thread")
self.onion_thread.quit()
if self.web_thread:
self.common.log('Mode', 'cancel_server: quitting web thread')
self.common.log("Mode", "cancel_server: quitting web thread")
self.web_thread.quit()
self.stop_server()
@ -328,7 +378,7 @@ class Mode(QtWidgets.QWidget):
"""
Stop the onionshare server.
"""
self.common.log('Mode', 'stop_server')
self.common.log("Mode", "stop_server")
if self.server_status.status != ServerStatus.STATUS_STOPPED:
try:
@ -382,7 +432,9 @@ class Mode(QtWidgets.QWidget):
Handle REQUEST_RATE_LIMIT event.
"""
self.stop_server()
Alert(self.common, strings._('error_rate_limit'), QtWidgets.QMessageBox.Critical)
Alert(
self.common, strings._("error_rate_limit"), QtWidgets.QMessageBox.Critical
)
def handle_request_progress(self, event):
"""

View file

@ -24,11 +24,13 @@ from onionshare import strings
from ..widgets import Alert, AddFileDialog
class DropHereLabel(QtWidgets.QLabel):
"""
When there are no files or folders in the FileList yet, display the
'drop files here' message and graphic.
"""
def __init__(self, common, parent, image=False):
self.parent = parent
super(DropHereLabel, self).__init__(parent=parent)
@ -39,10 +41,16 @@ class DropHereLabel(QtWidgets.QLabel):
self.setAlignment(QtCore.Qt.AlignCenter)
if image:
self.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/logo_transparent.png'))))
self.setPixmap(
QtGui.QPixmap.fromImage(
QtGui.QImage(
self.common.get_resource_path("images/logo_transparent.png")
)
)
)
else:
self.setText(strings._('gui_drag_and_drop'))
self.setStyleSheet(self.common.css['share_file_selection_drop_here_label'])
self.setText(strings._("gui_drag_and_drop"))
self.setStyleSheet(self.common.css["share_file_selection_drop_here_label"])
self.hide()
@ -57,6 +65,7 @@ class DropCountLabel(QtWidgets.QLabel):
While dragging files over the FileList, this counter displays the
number of files you're dragging.
"""
def __init__(self, common, parent):
self.parent = parent
super(DropCountLabel, self).__init__(parent=parent)
@ -65,8 +74,8 @@ class DropCountLabel(QtWidgets.QLabel):
self.setAcceptDrops(True)
self.setAlignment(QtCore.Qt.AlignCenter)
self.setText(strings._('gui_drag_and_drop'))
self.setStyleSheet(self.common.css['share_file_selection_drop_count_label'])
self.setText(strings._("gui_drag_and_drop"))
self.setStyleSheet(self.common.css["share_file_selection_drop_count_label"])
self.hide()
def dragEnterEvent(self, event):
@ -78,6 +87,7 @@ class FileList(QtWidgets.QListWidget):
"""
The list of files and folders in the GUI.
"""
files_dropped = QtCore.pyqtSignal()
files_updated = QtCore.pyqtSignal()
@ -139,7 +149,7 @@ class FileList(QtWidgets.QListWidget):
if self.count() > 0:
# Add and delete an empty item, to force all items to get redrawn
# This is ugly, but the only way I could figure out how to proceed
item = QtWidgets.QListWidgetItem('fake item')
item = QtWidgets.QListWidgetItem("fake item")
self.addItem(item)
self.takeItem(self.row(item))
self.update()
@ -149,21 +159,27 @@ class FileList(QtWidgets.QListWidget):
# and extend based on the overall width minus that amount.
for index in range(self.count()):
metrics = QtGui.QFontMetrics(self.item(index).font())
elided = metrics.elidedText(self.item(index).basename, QtCore.Qt.ElideRight, self.width() - 200)
elided = metrics.elidedText(
self.item(index).basename, QtCore.Qt.ElideRight, self.width() - 200
)
self.item(index).setText(elided)
def dragEnterEvent(self, event):
"""
dragEnterEvent for dragging files and directories into the widget.
"""
if event.mimeData().hasUrls:
self.setStyleSheet(self.common.css['share_file_list_drag_enter'])
self.setStyleSheet(self.common.css["share_file_list_drag_enter"])
count = len(event.mimeData().urls())
self.drop_count.setText('+{}'.format(count))
self.drop_count.setText("+{}".format(count))
size_hint = self.drop_count.sizeHint()
self.drop_count.setGeometry(self.width() - size_hint.width() - 10, self.height() - size_hint.height() - 10, size_hint.width(), size_hint.height())
self.drop_count.setGeometry(
self.width() - size_hint.width() - 10,
self.height() - size_hint.height() - 10,
size_hint.width(),
size_hint.height(),
)
self.drop_count.show()
event.accept()
else:
@ -173,7 +189,7 @@ class FileList(QtWidgets.QListWidget):
"""
dragLeaveEvent for dragging files and directories into the widget.
"""
self.setStyleSheet(self.common.css['share_file_list_drag_leave'])
self.setStyleSheet(self.common.css["share_file_list_drag_leave"])
self.drop_count.hide()
event.accept()
self.update()
@ -201,7 +217,7 @@ class FileList(QtWidgets.QListWidget):
else:
event.ignore()
self.setStyleSheet(self.common.css['share_file_list_drag_leave'])
self.setStyleSheet(self.common.css["share_file_list_drag_leave"])
self.drop_count.hide()
self.files_dropped.emit()
@ -238,12 +254,14 @@ class FileList(QtWidgets.QListWidget):
# Item's filename attribute and size labels
item.filename = filename
item_size = QtWidgets.QLabel(size_readable)
item_size.setStyleSheet(self.common.css['share_file_list_item_size'])
item_size.setStyleSheet(self.common.css["share_file_list_item_size"])
item.basename = os.path.basename(filename.rstrip('/'))
item.basename = os.path.basename(filename.rstrip("/"))
# Use the basename as the method with which to sort the list
metrics = QtGui.QFontMetrics(item.font())
elided = metrics.elidedText(item.basename, QtCore.Qt.ElideRight, self.sizeHint().width())
elided = metrics.elidedText(
item.basename, QtCore.Qt.ElideRight, self.sizeHint().width()
)
item.setData(QtCore.Qt.DisplayRole, elided)
# Item's delete button
@ -255,9 +273,13 @@ class FileList(QtWidgets.QListWidget):
item.item_button = QtWidgets.QPushButton()
item.item_button.setDefault(False)
item.item_button.setFlat(True)
item.item_button.setIcon( QtGui.QIcon(self.common.get_resource_path('images/file_delete.png')) )
item.item_button.setIcon(
QtGui.QIcon(self.common.get_resource_path("images/file_delete.png"))
)
item.item_button.clicked.connect(delete_item)
item.item_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
item.item_button.setSizePolicy(
QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
)
# Item info widget, with a white background
item_info_layout = QtWidgets.QHBoxLayout()
@ -265,7 +287,7 @@ class FileList(QtWidgets.QListWidget):
item_info_layout.addWidget(item_size)
item_info_layout.addWidget(item.item_button)
item_info = QtWidgets.QWidget()
item_info.setObjectName('item-info')
item_info.setObjectName("item-info")
item_info.setLayout(item_info_layout)
# Create the item's widget and layouts
@ -288,6 +310,7 @@ class FileSelection(QtWidgets.QVBoxLayout):
The list of files and folders in the GUI, as well as buttons to add and
delete the files and folders.
"""
def __init__(self, common, parent):
super(FileSelection, self).__init__()
@ -303,21 +326,21 @@ class FileSelection(QtWidgets.QVBoxLayout):
self.file_list.files_updated.connect(self.update)
# Buttons
if self.common.platform == 'Darwin':
if self.common.platform == "Darwin":
# The macOS sandbox makes it so the Mac version needs separate add files
# and folders buttons, in order to use native file selection dialogs
self.add_files_button = QtWidgets.QPushButton(strings._('gui_add_files'))
self.add_files_button = QtWidgets.QPushButton(strings._("gui_add_files"))
self.add_files_button.clicked.connect(self.add_files)
self.add_folder_button = QtWidgets.QPushButton(strings._('gui_add_folder'))
self.add_folder_button = QtWidgets.QPushButton(strings._("gui_add_folder"))
self.add_folder_button.clicked.connect(self.add_folder)
else:
self.add_button = QtWidgets.QPushButton(strings._('gui_add'))
self.add_button = QtWidgets.QPushButton(strings._("gui_add"))
self.add_button.clicked.connect(self.add)
self.delete_button = QtWidgets.QPushButton(strings._('gui_delete'))
self.delete_button = QtWidgets.QPushButton(strings._("gui_delete"))
self.delete_button.clicked.connect(self.delete)
button_layout = QtWidgets.QHBoxLayout()
button_layout.addStretch()
if self.common.platform == 'Darwin':
if self.common.platform == "Darwin":
button_layout.addWidget(self.add_files_button)
button_layout.addWidget(self.add_folder_button)
else:
@ -336,14 +359,14 @@ class FileSelection(QtWidgets.QVBoxLayout):
"""
# All buttons should be hidden if the server is on
if self.server_on:
if self.common.platform == 'Darwin':
if self.common.platform == "Darwin":
self.add_files_button.hide()
self.add_folder_button.hide()
else:
self.add_button.hide()
self.delete_button.hide()
else:
if self.common.platform == 'Darwin':
if self.common.platform == "Darwin":
self.add_files_button.show()
self.add_folder_button.show()
else:
@ -362,7 +385,7 @@ class FileSelection(QtWidgets.QVBoxLayout):
"""
Add button clicked.
"""
file_dialog = AddFileDialog(self.common, caption=strings._('gui_choose_items'))
file_dialog = AddFileDialog(self.common, caption=strings._("gui_choose_items"))
if file_dialog.exec_() == QtWidgets.QDialog.Accepted:
for filename in file_dialog.selectedFiles():
self.file_list.add_file(filename)
@ -374,7 +397,9 @@ class FileSelection(QtWidgets.QVBoxLayout):
"""
Add files button clicked.
"""
files = QtWidgets.QFileDialog.getOpenFileNames(self.parent, caption=strings._('gui_choose_items'))
files = QtWidgets.QFileDialog.getOpenFileNames(
self.parent, caption=strings._("gui_choose_items")
)
filenames = files[0]
for filename in filenames:
self.file_list.add_file(filename)
@ -383,9 +408,11 @@ class FileSelection(QtWidgets.QVBoxLayout):
"""
Add folder button clicked.
"""
filename = QtWidgets.QFileDialog.getExistingDirectory(self.parent,
caption=strings._('gui_choose_items'),
options=QtWidgets.QFileDialog.ShowDirsOnly)
filename = QtWidgets.QFileDialog.getExistingDirectory(
self.parent,
caption=strings._("gui_choose_items"),
options=QtWidgets.QFileDialog.ShowDirsOnly,
)
self.file_list.add_file(filename)
def delete(self):

View file

@ -31,6 +31,7 @@ class HistoryItem(QtWidgets.QWidget):
"""
The base history item
"""
STATUS_STARTED = 0
STATUS_FINISHED = 1
STATUS_CANCELED = 2
@ -49,34 +50,42 @@ class HistoryItem(QtWidgets.QWidget):
When an item finishes, returns a string displaying the start/end datetime range.
started is a datetime object.
"""
return self._get_label_text('gui_all_modes_transfer_finished', 'gui_all_modes_transfer_finished_range', started)
return self._get_label_text(
"gui_all_modes_transfer_finished",
"gui_all_modes_transfer_finished_range",
started,
)
def get_canceled_label_text(self, started):
"""
When an item is canceled, returns a string displaying the start/end datetime range.
started is a datetime object.
"""
return self._get_label_text('gui_all_modes_transfer_canceled', 'gui_all_modes_transfer_canceled_range', started)
return self._get_label_text(
"gui_all_modes_transfer_canceled",
"gui_all_modes_transfer_canceled_range",
started,
)
def _get_label_text(self, string_name, string_range_name, started):
"""
Return a string that contains a date, or date range.
"""
ended = datetime.now()
if started.year == ended.year and started.month == ended.month and started.day == ended.day:
if (
started.year == ended.year
and started.month == ended.month
and started.day == ended.day
):
if started.hour == ended.hour and started.minute == ended.minute:
text = strings._(string_name).format(
started.strftime("%b %d, %I:%M%p")
)
text = strings._(string_name).format(started.strftime("%b %d, %I:%M%p"))
else:
text = strings._(string_range_name).format(
started.strftime("%b %d, %I:%M%p"),
ended.strftime("%I:%M%p")
started.strftime("%b %d, %I:%M%p"), ended.strftime("%I:%M%p")
)
else:
text = strings._(string_range_name).format(
started.strftime("%b %d, %I:%M%p"),
ended.strftime("%b %d, %I:%M%p")
started.strftime("%b %d, %I:%M%p"), ended.strftime("%b %d, %I:%M%p")
)
return text
@ -85,6 +94,7 @@ class ShareHistoryItem(HistoryItem):
"""
Download history item, for share mode
"""
def __init__(self, common, id, total_bytes):
super(ShareHistoryItem, self).__init__()
self.common = common
@ -97,7 +107,11 @@ class ShareHistoryItem(HistoryItem):
self.status = HistoryItem.STATUS_STARTED
# Label
self.label = QtWidgets.QLabel(strings._('gui_all_modes_transfer_started').format(self.started_dt.strftime("%b %d, %I:%M%p")))
self.label = QtWidgets.QLabel(
strings._("gui_all_modes_transfer_started").format(
self.started_dt.strftime("%b %d, %I:%M%p")
)
)
# Progress bar
self.progress_bar = QtWidgets.QProgressBar()
@ -107,7 +121,9 @@ class ShareHistoryItem(HistoryItem):
self.progress_bar.setMinimum(0)
self.progress_bar.setMaximum(total_bytes)
self.progress_bar.setValue(0)
self.progress_bar.setStyleSheet(self.common.css['downloads_uploads_progress_bar'])
self.progress_bar.setStyleSheet(
self.common.css["downloads_uploads_progress_bar"]
)
self.progress_bar.total_bytes = total_bytes
# Layout
@ -124,8 +140,9 @@ class ShareHistoryItem(HistoryItem):
self.progress_bar.setValue(downloaded_bytes)
if downloaded_bytes == self.progress_bar.total_bytes:
pb_fmt = strings._('gui_all_modes_progress_complete').format(
self.common.format_seconds(time.time() - self.started))
pb_fmt = strings._("gui_all_modes_progress_complete").format(
self.common.format_seconds(time.time() - self.started)
)
# Change the label
self.label.setText(self.get_finished_label_text(self.started_dt))
@ -137,24 +154,26 @@ class ShareHistoryItem(HistoryItem):
# Wait a couple of seconds for the download rate to stabilize.
# This prevents a "Windows copy dialog"-esque experience at
# the beginning of the download.
pb_fmt = strings._('gui_all_modes_progress_starting').format(
self.common.human_readable_filesize(downloaded_bytes))
pb_fmt = strings._("gui_all_modes_progress_starting").format(
self.common.human_readable_filesize(downloaded_bytes)
)
else:
pb_fmt = strings._('gui_all_modes_progress_eta').format(
pb_fmt = strings._("gui_all_modes_progress_eta").format(
self.common.human_readable_filesize(downloaded_bytes),
self.estimated_time_remaining)
self.estimated_time_remaining,
)
self.progress_bar.setFormat(pb_fmt)
def cancel(self):
self.progress_bar.setFormat(strings._('gui_canceled'))
self.progress_bar.setFormat(strings._("gui_canceled"))
self.status = HistoryItem.STATUS_CANCELED
@property
def estimated_time_remaining(self):
return self.common.estimated_time_remaining(self.downloaded_bytes,
self.total_bytes,
self.started)
return self.common.estimated_time_remaining(
self.downloaded_bytes, self.total_bytes, self.started
)
class ReceiveHistoryItemFile(QtWidgets.QWidget):
@ -162,7 +181,9 @@ class ReceiveHistoryItemFile(QtWidgets.QWidget):
super(ReceiveHistoryItemFile, self).__init__()
self.common = common
self.common.log('ReceiveHistoryItemFile', '__init__', 'filename: {}'.format(filename))
self.common.log(
"ReceiveHistoryItemFile", "__init__", "filename: {}".format(filename)
)
self.filename = filename
self.dir = None
@ -174,11 +195,13 @@ class ReceiveHistoryItemFile(QtWidgets.QWidget):
# File size label
self.filesize_label = QtWidgets.QLabel()
self.filesize_label.setStyleSheet(self.common.css['receive_file_size'])
self.filesize_label.setStyleSheet(self.common.css["receive_file_size"])
self.filesize_label.hide()
# Folder button
folder_pixmap = QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/open_folder.png')))
folder_pixmap = QtGui.QPixmap.fromImage(
QtGui.QImage(self.common.get_resource_path("images/open_folder.png"))
)
folder_icon = QtGui.QIcon(folder_pixmap)
self.folder_button = QtWidgets.QPushButton()
self.folder_button.clicked.connect(self.open_folder)
@ -213,29 +236,36 @@ class ReceiveHistoryItemFile(QtWidgets.QWidget):
"""
Open the downloads folder, with the file selected, in a cross-platform manner
"""
self.common.log('ReceiveHistoryItemFile', 'open_folder')
self.common.log("ReceiveHistoryItemFile", "open_folder")
if not self.dir:
self.common.log('ReceiveHistoryItemFile', 'open_folder', "dir has not been set yet, can't open folder")
self.common.log(
"ReceiveHistoryItemFile",
"open_folder",
"dir has not been set yet, can't open folder",
)
return
abs_filename = os.path.join(self.dir, self.filename)
# Linux
if self.common.platform == 'Linux' or self.common.platform == 'BSD':
if self.common.platform == "Linux" or self.common.platform == "BSD":
try:
# If nautilus is available, open it
subprocess.Popen(['nautilus', abs_filename])
subprocess.Popen(["nautilus", abs_filename])
except:
Alert(self.common, strings._('gui_open_folder_error_nautilus').format(abs_filename))
Alert(
self.common,
strings._("gui_open_folder_error_nautilus").format(abs_filename),
)
# macOS
elif self.common.platform == 'Darwin':
subprocess.call(['open', '-R', abs_filename])
elif self.common.platform == "Darwin":
subprocess.call(["open", "-R", abs_filename])
# Windows
elif self.common.platform == 'Windows':
subprocess.Popen(['explorer', '/select,{}'.format(abs_filename)])
elif self.common.platform == "Windows":
subprocess.Popen(["explorer", "/select,{}".format(abs_filename)])
class ReceiveHistoryItem(HistoryItem):
@ -248,7 +278,11 @@ class ReceiveHistoryItem(HistoryItem):
self.status = HistoryItem.STATUS_STARTED
# Label
self.label = QtWidgets.QLabel(strings._('gui_all_modes_transfer_started').format(self.started.strftime("%b %d, %I:%M%p")))
self.label = QtWidgets.QLabel(
strings._("gui_all_modes_transfer_started").format(
self.started.strftime("%b %d, %I:%M%p")
)
)
# Progress bar
self.progress_bar = QtWidgets.QProgressBar()
@ -257,13 +291,15 @@ class ReceiveHistoryItem(HistoryItem):
self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter)
self.progress_bar.setMinimum(0)
self.progress_bar.setValue(0)
self.progress_bar.setStyleSheet(self.common.css['downloads_uploads_progress_bar'])
self.progress_bar.setStyleSheet(
self.common.css["downloads_uploads_progress_bar"]
)
# This layout contains file widgets
self.files_layout = QtWidgets.QVBoxLayout()
self.files_layout.setContentsMargins(0, 0, 0, 0)
files_widget = QtWidgets.QWidget()
files_widget.setStyleSheet(self.common.css['receive_file'])
files_widget.setStyleSheet(self.common.css["receive_file"])
files_widget.setLayout(self.files_layout)
# Layout
@ -282,10 +318,10 @@ class ReceiveHistoryItem(HistoryItem):
Using the progress from Web, update the progress bar and file size labels
for each file
"""
if data['action'] == 'progress':
if data["action"] == "progress":
total_uploaded_bytes = 0
for filename in data['progress']:
total_uploaded_bytes += data['progress'][filename]['uploaded_bytes']
for filename in data["progress"]:
total_uploaded_bytes += data["progress"][filename]["uploaded_bytes"]
# Update the progress bar
self.progress_bar.setMaximum(self.content_length)
@ -293,35 +329,39 @@ class ReceiveHistoryItem(HistoryItem):
elapsed = datetime.now() - self.started
if elapsed.seconds < 10:
pb_fmt = strings._('gui_all_modes_progress_starting').format(
self.common.human_readable_filesize(total_uploaded_bytes))
pb_fmt = strings._("gui_all_modes_progress_starting").format(
self.common.human_readable_filesize(total_uploaded_bytes)
)
else:
estimated_time_remaining = self.common.estimated_time_remaining(
total_uploaded_bytes,
self.content_length,
self.started.timestamp())
pb_fmt = strings._('gui_all_modes_progress_eta').format(
total_uploaded_bytes, self.content_length, self.started.timestamp()
)
pb_fmt = strings._("gui_all_modes_progress_eta").format(
self.common.human_readable_filesize(total_uploaded_bytes),
estimated_time_remaining)
estimated_time_remaining,
)
# Using list(progress) to avoid "RuntimeError: dictionary changed size during iteration"
for filename in list(data['progress']):
for filename in list(data["progress"]):
# Add a new file if needed
if filename not in self.files:
self.files[filename] = ReceiveHistoryItemFile(self.common, filename)
self.files_layout.addWidget(self.files[filename])
# Update the file
self.files[filename].update(data['progress'][filename]['uploaded_bytes'], data['progress'][filename]['complete'])
self.files[filename].update(
data["progress"][filename]["uploaded_bytes"],
data["progress"][filename]["complete"],
)
elif data['action'] == 'rename':
self.files[data['old_filename']].rename(data['new_filename'])
self.files[data['new_filename']] = self.files.pop(data['old_filename'])
elif data["action"] == "rename":
self.files[data["old_filename"]].rename(data["new_filename"])
self.files[data["new_filename"]] = self.files.pop(data["old_filename"])
elif data['action'] == 'set_dir':
self.files[data['filename']].set_dir(data['dir'])
elif data["action"] == "set_dir":
self.files[data["filename"]].set_dir(data["dir"])
elif data['action'] == 'finished':
elif data["action"] == "finished":
# Change the status
self.status = HistoryItem.STATUS_FINISHED
@ -331,7 +371,7 @@ class ReceiveHistoryItem(HistoryItem):
# Change the label
self.label.setText(self.get_finished_label_text(self.started))
elif data['action'] == 'canceled':
elif data["action"] == "canceled":
# Change the status
self.status = HistoryItem.STATUS_CANCELED
@ -346,6 +386,7 @@ class IndividualFileHistoryItem(HistoryItem):
"""
Individual file history item, for share mode viewing of individual files
"""
def __init__(self, common, data, path):
super(IndividualFileHistoryItem, self).__init__()
self.status = HistoryItem.STATUS_STARTED
@ -359,11 +400,15 @@ class IndividualFileHistoryItem(HistoryItem):
self.started_dt = datetime.fromtimestamp(self.started)
self.status = HistoryItem.STATUS_STARTED
self.directory_listing = 'directory_listing' in data
self.directory_listing = "directory_listing" in data
# Labels
self.timestamp_label = QtWidgets.QLabel(self.started_dt.strftime("%b %d, %I:%M%p"))
self.timestamp_label.setStyleSheet(self.common.css['history_individual_file_timestamp_label'])
self.timestamp_label = QtWidgets.QLabel(
self.started_dt.strftime("%b %d, %I:%M%p")
)
self.timestamp_label.setStyleSheet(
self.common.css["history_individual_file_timestamp_label"]
)
self.path_label = QtWidgets.QLabel("{}".format(self.path))
self.status_code_label = QtWidgets.QLabel()
@ -373,7 +418,9 @@ class IndividualFileHistoryItem(HistoryItem):
self.progress_bar.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter)
self.progress_bar.setValue(0)
self.progress_bar.setStyleSheet(self.common.css['downloads_uploads_progress_bar'])
self.progress_bar.setStyleSheet(
self.common.css["downloads_uploads_progress_bar"]
)
# Text layout
labels_layout = QtWidgets.QHBoxLayout()
@ -389,21 +436,25 @@ class IndividualFileHistoryItem(HistoryItem):
self.setLayout(layout)
# Is a status code already sent?
if 'status_code' in data:
self.status_code_label.setText("{}".format(data['status_code']))
if data['status_code'] >= 200 and data['status_code'] < 300:
self.status_code_label.setStyleSheet(self.common.css['history_individual_file_status_code_label_2xx'])
if data['status_code'] >= 400 and data['status_code'] < 500:
self.status_code_label.setStyleSheet(self.common.css['history_individual_file_status_code_label_4xx'])
if "status_code" in data:
self.status_code_label.setText("{}".format(data["status_code"]))
if data["status_code"] >= 200 and data["status_code"] < 300:
self.status_code_label.setStyleSheet(
self.common.css["history_individual_file_status_code_label_2xx"]
)
if data["status_code"] >= 400 and data["status_code"] < 500:
self.status_code_label.setStyleSheet(
self.common.css["history_individual_file_status_code_label_4xx"]
)
self.status = HistoryItem.STATUS_FINISHED
self.progress_bar.hide()
return
else:
self.total_bytes = data['filesize']
self.total_bytes = data["filesize"]
self.progress_bar.setMinimum(0)
self.progress_bar.setMaximum(data['filesize'])
self.progress_bar.total_bytes = data['filesize']
self.progress_bar.setMaximum(data["filesize"])
self.progress_bar.total_bytes = data["filesize"]
# Start at 0
self.update(0)
@ -414,7 +465,9 @@ class IndividualFileHistoryItem(HistoryItem):
self.progress_bar.setValue(downloaded_bytes)
if downloaded_bytes == self.progress_bar.total_bytes:
self.status_code_label.setText("200")
self.status_code_label.setStyleSheet(self.common.css['history_individual_file_status_code_label_2xx'])
self.status_code_label.setStyleSheet(
self.common.css["history_individual_file_status_code_label_2xx"]
)
self.progress_bar.hide()
self.status = HistoryItem.STATUS_FINISHED
@ -424,30 +477,33 @@ class IndividualFileHistoryItem(HistoryItem):
# Wait a couple of seconds for the download rate to stabilize.
# This prevents a "Windows copy dialog"-esque experience at
# the beginning of the download.
pb_fmt = strings._('gui_all_modes_progress_starting').format(
self.common.human_readable_filesize(downloaded_bytes))
pb_fmt = strings._("gui_all_modes_progress_starting").format(
self.common.human_readable_filesize(downloaded_bytes)
)
else:
pb_fmt = strings._('gui_all_modes_progress_eta').format(
pb_fmt = strings._("gui_all_modes_progress_eta").format(
self.common.human_readable_filesize(downloaded_bytes),
self.estimated_time_remaining)
self.estimated_time_remaining,
)
self.progress_bar.setFormat(pb_fmt)
def cancel(self):
self.progress_bar.setFormat(strings._('gui_canceled'))
self.progress_bar.setFormat(strings._("gui_canceled"))
self.status = HistoryItem.STATUS_CANCELED
@property
def estimated_time_remaining(self):
return self.common.estimated_time_remaining(self.downloaded_bytes,
self.total_bytes,
self.started)
return self.common.estimated_time_remaining(
self.downloaded_bytes, self.total_bytes, self.started
)
class HistoryItemList(QtWidgets.QScrollArea):
"""
List of items
"""
def __init__(self, common):
super(HistoryItemList, self).__init__()
self.common = common
@ -511,12 +567,14 @@ class HistoryItemList(QtWidgets.QScrollArea):
item.close()
del self.items[key]
class History(QtWidgets.QWidget):
"""
A history of what's happened so far in this mode. This contains an internal
object full of a scrollable list of items.
"""
def __init__(self, common, empty_image, empty_text, header_text, mode=''):
def __init__(self, common, empty_image, empty_text, header_text, mode=""):
super(History, self).__init__()
self.common = common
self.mode = mode
@ -530,17 +588,19 @@ class History(QtWidgets.QWidget):
# In progress, completed, and requests labels
self.in_progress_label = QtWidgets.QLabel()
self.in_progress_label.setStyleSheet(self.common.css['mode_info_label'])
self.in_progress_label.setStyleSheet(self.common.css["mode_info_label"])
self.completed_label = QtWidgets.QLabel()
self.completed_label.setStyleSheet(self.common.css['mode_info_label'])
self.completed_label.setStyleSheet(self.common.css["mode_info_label"])
self.requests_label = QtWidgets.QLabel()
self.requests_label.setStyleSheet(self.common.css['mode_info_label'])
self.requests_label.setStyleSheet(self.common.css["mode_info_label"])
# Header
self.header_label = QtWidgets.QLabel(header_text)
self.header_label.setStyleSheet(self.common.css['downloads_uploads_label'])
self.clear_button = QtWidgets.QPushButton(strings._('gui_all_modes_clear_history'))
self.clear_button.setStyleSheet(self.common.css['downloads_uploads_clear'])
self.header_label.setStyleSheet(self.common.css["downloads_uploads_label"])
self.clear_button = QtWidgets.QPushButton(
strings._("gui_all_modes_clear_history")
)
self.clear_button.setStyleSheet(self.common.css["downloads_uploads_clear"])
self.clear_button.setFlat(True)
self.clear_button.clicked.connect(self.reset)
header_layout = QtWidgets.QHBoxLayout()
@ -557,14 +617,14 @@ class History(QtWidgets.QWidget):
self.empty_image.setPixmap(empty_image)
self.empty_text = QtWidgets.QLabel(empty_text)
self.empty_text.setAlignment(QtCore.Qt.AlignCenter)
self.empty_text.setStyleSheet(self.common.css['downloads_uploads_empty_text'])
self.empty_text.setStyleSheet(self.common.css["downloads_uploads_empty_text"])
empty_layout = QtWidgets.QVBoxLayout()
empty_layout.addStretch()
empty_layout.addWidget(self.empty_image)
empty_layout.addWidget(self.empty_text)
empty_layout.addStretch()
self.empty = QtWidgets.QWidget()
self.empty.setStyleSheet(self.common.css['downloads_uploads_empty'])
self.empty.setStyleSheet(self.common.css["downloads_uploads_empty"])
self.empty.setLayout(empty_layout)
# When there are items
@ -589,7 +649,7 @@ class History(QtWidgets.QWidget):
"""
Add a new item.
"""
self.common.log('History', 'add', 'id: {}, item: {}'.format(id, item))
self.common.log("History", "add", "id: {}, item: {}".format(id, item))
# Hide empty, show not empty
self.empty.hide()
@ -636,35 +696,47 @@ class History(QtWidgets.QWidget):
Update the 'completed' widget.
"""
if self.completed_count == 0:
image = self.common.get_resource_path('images/history_completed_none.png')
image = self.common.get_resource_path("images/history_completed_none.png")
else:
image = self.common.get_resource_path('images/history_completed.png')
self.completed_label.setText('<img src="{0:s}" /> {1:d}'.format(image, self.completed_count))
self.completed_label.setToolTip(strings._('history_completed_tooltip').format(self.completed_count))
image = self.common.get_resource_path("images/history_completed.png")
self.completed_label.setText(
'<img src="{0:s}" /> {1:d}'.format(image, self.completed_count)
)
self.completed_label.setToolTip(
strings._("history_completed_tooltip").format(self.completed_count)
)
def update_in_progress(self):
"""
Update the 'in progress' widget.
"""
if self.in_progress_count == 0:
image = self.common.get_resource_path('images/history_in_progress_none.png')
image = self.common.get_resource_path("images/history_in_progress_none.png")
else:
image = self.common.get_resource_path('images/history_in_progress.png')
image = self.common.get_resource_path("images/history_in_progress.png")
self.in_progress_label.setText('<img src="{0:s}" /> {1:d}'.format(image, self.in_progress_count))
self.in_progress_label.setToolTip(strings._('history_in_progress_tooltip').format(self.in_progress_count))
self.in_progress_label.setText(
'<img src="{0:s}" /> {1:d}'.format(image, self.in_progress_count)
)
self.in_progress_label.setToolTip(
strings._("history_in_progress_tooltip").format(self.in_progress_count)
)
def update_requests(self):
"""
Update the 'web requests' widget.
"""
if self.requests_count == 0:
image = self.common.get_resource_path('images/history_requests_none.png')
image = self.common.get_resource_path("images/history_requests_none.png")
else:
image = self.common.get_resource_path('images/history_requests.png')
image = self.common.get_resource_path("images/history_requests.png")
self.requests_label.setText('<img src="{0:s}" /> {1:d}'.format(image, self.requests_count))
self.requests_label.setToolTip(strings._('history_requests_tooltip').format(self.requests_count))
self.requests_label.setText(
'<img src="{0:s}" /> {1:d}'.format(image, self.requests_count)
)
self.requests_label.setToolTip(
strings._("history_requests_tooltip").format(self.requests_count)
)
class ToggleHistory(QtWidgets.QPushButton):
@ -672,6 +744,7 @@ class ToggleHistory(QtWidgets.QPushButton):
Widget for toggling showing or hiding the history, as well as keeping track
of the indicator counter if it's hidden
"""
def __init__(self, common, current_mode, history_widget, icon, selected_icon):
super(ToggleHistory, self).__init__()
self.common = common
@ -691,7 +764,9 @@ class ToggleHistory(QtWidgets.QPushButton):
# Keep track of indicator
self.indicator_count = 0
self.indicator_label = QtWidgets.QLabel(parent=self)
self.indicator_label.setStyleSheet(self.common.css['download_uploads_indicator'])
self.indicator_label.setStyleSheet(
self.common.css["download_uploads_indicator"]
)
self.update_indicator()
def update_indicator(self, increment=False):
@ -708,14 +783,16 @@ class ToggleHistory(QtWidgets.QPushButton):
self.indicator_label.hide()
else:
size = self.indicator_label.sizeHint()
self.indicator_label.setGeometry(35-size.width(), 0, size.width(), size.height())
self.indicator_label.setGeometry(
35 - size.width(), 0, size.width(), size.height()
)
self.indicator_label.show()
def toggle_clicked(self):
"""
Toggle showing and hiding the history widget
"""
self.common.log('ToggleHistory', 'toggle_clicked')
self.common.log("ToggleHistory", "toggle_clicked")
if self.history_widget.isVisible():
self.history_widget.hide()

View file

@ -25,19 +25,21 @@ from onionshare.web import Web
from ..history import History, ToggleHistory, ReceiveHistoryItem
from .. import Mode
class ReceiveMode(Mode):
"""
Parts of the main window UI for receiving files.
"""
def init(self):
"""
Custom initialization for ReceiveMode.
"""
# Create the Web object
self.web = Web(self.common, True, 'receive')
self.web = Web(self.common, True, "receive")
# Server status
self.server_status.set_mode('receive')
self.server_status.set_mode("receive")
self.server_status.server_started_finished.connect(self.update_primary_action)
self.server_status.server_stopped.connect(self.update_primary_action)
self.server_status.server_canceled.connect(self.update_primary_action)
@ -49,21 +51,31 @@ class ReceiveMode(Mode):
# Upload history
self.history = History(
self.common,
QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/receive_icon_transparent.png'))),
strings._('gui_receive_mode_no_files'),
strings._('gui_all_modes_history')
QtGui.QPixmap.fromImage(
QtGui.QImage(
self.common.get_resource_path("images/receive_icon_transparent.png")
)
),
strings._("gui_receive_mode_no_files"),
strings._("gui_all_modes_history"),
)
self.history.hide()
# Toggle history
self.toggle_history = ToggleHistory(
self.common, self, self.history,
QtGui.QIcon(self.common.get_resource_path('images/receive_icon_toggle.png')),
QtGui.QIcon(self.common.get_resource_path('images/receive_icon_toggle_selected.png'))
self.common,
self,
self.history,
QtGui.QIcon(
self.common.get_resource_path("images/receive_icon_toggle.png")
),
QtGui.QIcon(
self.common.get_resource_path("images/receive_icon_toggle_selected.png")
),
)
# Receive mode warning
receive_warning = QtWidgets.QLabel(strings._('gui_receive_mode_warning'))
receive_warning = QtWidgets.QLabel(strings._("gui_receive_mode_warning"))
receive_warning.setMinimumHeight(80)
receive_warning.setWordWrap(True)
@ -90,20 +102,25 @@ class ReceiveMode(Mode):
"""
Return the string to put on the stop server button, if there's an auto-stop timer
"""
return strings._('gui_receive_stop_server_autostop_timer')
return strings._("gui_receive_stop_server_autostop_timer")
def autostop_timer_finished_should_stop_server(self):
"""
The auto-stop timer expired, should we stop the server? Returns a bool
"""
# If there were no attempts to upload files, or all uploads are done, we can stop
if self.web.receive_mode.cur_history_id == 0 or not self.web.receive_mode.uploads_in_progress:
if (
self.web.receive_mode.cur_history_id == 0
or not self.web.receive_mode.uploads_in_progress
):
self.server_status.stop_server()
self.server_status_label.setText(strings._('close_on_autostop_timer'))
self.server_status_label.setText(strings._("close_on_autostop_timer"))
return True
# An upload is probably still running - hold off on stopping the share, but block new shares.
else:
self.server_status_label.setText(strings._('gui_receive_mode_autostop_timer_waiting'))
self.server_status_label.setText(
strings._("gui_receive_mode_autostop_timer_waiting")
)
self.web.receive_mode.can_upload = False
return False
@ -136,56 +153,68 @@ class ReceiveMode(Mode):
"""
Handle REQUEST_LOAD event.
"""
self.system_tray.showMessage(strings._('systray_page_loaded_title'), strings._('systray_page_loaded_message'))
self.system_tray.showMessage(
strings._("systray_page_loaded_title"),
strings._("systray_page_loaded_message"),
)
def handle_request_started(self, event):
"""
Handle REQUEST_STARTED event.
"""
item = ReceiveHistoryItem(self.common, event["data"]["id"], event["data"]["content_length"])
item = ReceiveHistoryItem(
self.common, event["data"]["id"], event["data"]["content_length"]
)
self.history.add(event["data"]["id"], item)
self.toggle_history.update_indicator(True)
self.history.in_progress_count += 1
self.history.update_in_progress()
self.system_tray.showMessage(strings._('systray_receive_started_title'), strings._('systray_receive_started_message'))
self.system_tray.showMessage(
strings._("systray_receive_started_title"),
strings._("systray_receive_started_message"),
)
def handle_request_progress(self, event):
"""
Handle REQUEST_PROGRESS event.
"""
self.history.update(event["data"]["id"], {
'action': 'progress',
'progress': event["data"]["progress"]
})
self.history.update(
event["data"]["id"],
{"action": "progress", "progress": event["data"]["progress"]},
)
def handle_request_upload_file_renamed(self, event):
"""
Handle REQUEST_UPLOAD_FILE_RENAMED event.
"""
self.history.update(event["data"]["id"], {
'action': 'rename',
'old_filename': event["data"]["old_filename"],
'new_filename': event["data"]["new_filename"]
})
self.history.update(
event["data"]["id"],
{
"action": "rename",
"old_filename": event["data"]["old_filename"],
"new_filename": event["data"]["new_filename"],
},
)
def handle_request_upload_set_dir(self, event):
"""
Handle REQUEST_UPLOAD_SET_DIR event.
"""
self.history.update(event["data"]["id"], {
'action': 'set_dir',
'filename': event["data"]["filename"],
'dir': event["data"]["dir"]
})
self.history.update(
event["data"]["id"],
{
"action": "set_dir",
"filename": event["data"]["filename"],
"dir": event["data"]["dir"],
},
)
def handle_request_upload_finished(self, event):
"""
Handle REQUEST_UPLOAD_FINISHED event.
"""
self.history.update(event["data"]["id"], {
'action': 'finished'
})
self.history.update(event["data"]["id"], {"action": "finished"})
self.history.completed_count += 1
self.history.in_progress_count -= 1
self.history.update_completed()
@ -195,9 +224,7 @@ class ReceiveMode(Mode):
"""
Handle REQUEST_UPLOAD_CANCELED event.
"""
self.history.update(event["data"]["id"], {
'action': 'canceled'
})
self.history.update(event["data"]["id"], {"action": "canceled"})
self.history.in_progress_count -= 1
self.history.update_in_progress()
@ -216,4 +243,4 @@ class ReceiveMode(Mode):
self.toggle_history.update_indicator()
def update_primary_action(self):
self.common.log('ReceiveMode', 'update_primary_action')
self.common.log("ReceiveMode", "update_primary_action")

View file

@ -36,6 +36,7 @@ class ShareMode(Mode):
"""
Parts of the main window UI for sharing files.
"""
def init(self):
"""
Custom initialization for ReceiveMode.
@ -44,7 +45,7 @@ class ShareMode(Mode):
self.compress_thread = None
# Create the Web object
self.web = Web(self.common, True, 'share')
self.web = Web(self.common, True, "share")
# File selection
self.file_selection = FileSelection(self.common, self)
@ -53,7 +54,7 @@ class ShareMode(Mode):
self.file_selection.file_list.add_file(filename)
# Server status
self.server_status.set_mode('share', self.file_selection)
self.server_status.set_mode("share", self.file_selection)
self.server_status.server_started.connect(self.file_selection.server_started)
self.server_status.server_stopped.connect(self.file_selection.server_stopped)
self.server_status.server_stopped.connect(self.update_primary_action)
@ -68,15 +69,19 @@ class ShareMode(Mode):
# Filesize warning
self.filesize_warning = QtWidgets.QLabel()
self.filesize_warning.setWordWrap(True)
self.filesize_warning.setStyleSheet(self.common.css['share_filesize_warning'])
self.filesize_warning.setStyleSheet(self.common.css["share_filesize_warning"])
self.filesize_warning.hide()
# Download history
self.history = History(
self.common,
QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/share_icon_transparent.png'))),
strings._('gui_share_mode_no_files'),
strings._('gui_all_modes_history')
QtGui.QPixmap.fromImage(
QtGui.QImage(
self.common.get_resource_path("images/share_icon_transparent.png")
)
),
strings._("gui_share_mode_no_files"),
strings._("gui_all_modes_history"),
)
self.history.hide()
@ -86,9 +91,13 @@ class ShareMode(Mode):
# Toggle history
self.toggle_history = ToggleHistory(
self.common, self, self.history,
QtGui.QIcon(self.common.get_resource_path('images/share_icon_toggle.png')),
QtGui.QIcon(self.common.get_resource_path('images/share_icon_toggle_selected.png'))
self.common,
self,
self.history,
QtGui.QIcon(self.common.get_resource_path("images/share_icon_toggle.png")),
QtGui.QIcon(
self.common.get_resource_path("images/share_icon_toggle_selected.png")
),
)
# Top bar
@ -125,7 +134,7 @@ class ShareMode(Mode):
"""
Return the string to put on the stop server button, if there's an auto-stop timer
"""
return strings._('gui_share_stop_server_autostop_timer')
return strings._("gui_share_stop_server_autostop_timer")
def autostop_timer_finished_should_stop_server(self):
"""
@ -134,11 +143,13 @@ class ShareMode(Mode):
# If there were no attempts to download the share, or all downloads are done, we can stop
if self.web.share_mode.cur_history_id == 0 or self.web.done:
self.server_status.stop_server()
self.server_status_label.setText(strings._('close_on_autostop_timer'))
self.server_status_label.setText(strings._("close_on_autostop_timer"))
return True
# A download is probably still running - hold off on stopping the share
else:
self.server_status_label.setText(strings._('gui_share_mode_autostop_timer_waiting'))
self.server_status_label.setText(
strings._("gui_share_mode_autostop_timer_waiting")
)
return False
def start_server_custom(self):
@ -162,7 +173,9 @@ class ShareMode(Mode):
for index in range(self.file_selection.file_list.count()):
self.filenames.append(self.file_selection.file_list.item(index).filename)
self._zip_progress_bar.total_files_size = ShareMode._compute_total_size(self.filenames)
self._zip_progress_bar.total_files_size = ShareMode._compute_total_size(
self.filenames
)
self.status_bar.insertWidget(0, self._zip_progress_bar)
# prepare the files for sending in a new thread
@ -216,7 +229,7 @@ class ShareMode(Mode):
Stop the compression thread on cancel
"""
if self.compress_thread:
self.common.log('ShareMode', 'cancel_server: quitting compress thread')
self.common.log("ShareMode", "cancel_server: quitting compress thread")
self.compress_thread.quit()
def handle_tor_broke_custom(self):
@ -240,7 +253,10 @@ class ShareMode(Mode):
self.history.in_progress_count += 1
self.history.update_in_progress()
self.system_tray.showMessage(strings._('systray_share_started_title'), strings._('systray_share_started_message'))
self.system_tray.showMessage(
strings._("systray_share_started_title"),
strings._("systray_share_started_message"),
)
def handle_request_progress(self, event):
"""
@ -250,7 +266,10 @@ class ShareMode(Mode):
# Is the download complete?
if event["data"]["bytes"] == self.web.share_mode.filesize:
self.system_tray.showMessage(strings._('systray_share_completed_title'), strings._('systray_share_completed_message'))
self.system_tray.showMessage(
strings._("systray_share_completed_title"),
strings._("systray_share_completed_message"),
)
# Update completed and in progress labels
self.history.completed_count += 1
@ -259,10 +278,10 @@ class ShareMode(Mode):
self.history.update_in_progress()
# Close on finish?
if self.common.settings.get('close_after_first_download'):
if self.common.settings.get("close_after_first_download"):
self.server_status.stop_server()
self.status_bar.clearMessage()
self.server_status_label.setText(strings._('closing_automatically'))
self.server_status_label.setText(strings._("closing_automatically"))
else:
if self.server_status.status == self.server_status.STATUS_STOPPED:
self.history.cancel(event["data"]["id"])
@ -278,7 +297,10 @@ class ShareMode(Mode):
# Update in progress count
self.history.in_progress_count -= 1
self.history.update_in_progress()
self.system_tray.showMessage(strings._('systray_share_canceled_title'), strings._('systray_share_canceled_message'))
self.system_tray.showMessage(
strings._("systray_share_canceled_title"),
strings._("systray_share_canceled_message"),
)
def on_reload_settings(self):
"""
@ -290,7 +312,7 @@ class ShareMode(Mode):
self.info_label.show()
def update_primary_action(self):
self.common.log('ShareMode', 'update_primary_action')
self.common.log("ShareMode", "update_primary_action")
# Show or hide primary action layout
file_count = self.file_selection.file_list.count()
@ -306,9 +328,15 @@ class ShareMode(Mode):
total_size_readable = self.common.human_readable_filesize(total_size_bytes)
if file_count > 1:
self.info_label.setText(strings._('gui_file_info').format(file_count, total_size_readable))
self.info_label.setText(
strings._("gui_file_info").format(file_count, total_size_readable)
)
else:
self.info_label.setText(strings._('gui_file_info_single').format(file_count, total_size_readable))
self.info_label.setText(
strings._("gui_file_info_single").format(
file_count, total_size_readable
)
)
else:
self.primary_action.hide()
@ -343,8 +371,8 @@ class ZipProgressBar(QtWidgets.QProgressBar):
self.setMaximumHeight(20)
self.setMinimumWidth(200)
self.setValue(0)
self.setFormat(strings._('zip_progress_bar_format'))
self.setStyleSheet(self.common.css['share_zip_progess_bar'])
self.setFormat(strings._("zip_progress_bar_format"))
self.setStyleSheet(self.common.css["share_zip_progess_bar"])
self._total_files_size = total_files_size
self._processed_size = 0

View file

@ -24,13 +24,14 @@ class CompressThread(QtCore.QThread):
"""
Compresses files to be shared
"""
success = QtCore.pyqtSignal()
error = QtCore.pyqtSignal(str)
def __init__(self, mode):
super(CompressThread, self).__init__()
self.mode = mode
self.mode.common.log('CompressThread', '__init__')
self.mode.common.log("CompressThread", "__init__")
# prepare files to share
def set_processed_size(self, x):
@ -38,17 +39,21 @@ class CompressThread(QtCore.QThread):
self.mode._zip_progress_bar.update_processed_size_signal.emit(x)
def run(self):
self.mode.common.log('CompressThread', 'run')
self.mode.common.log("CompressThread", "run")
try:
self.mode.web.share_mode.set_file_info(self.mode.filenames, processed_size_callback=self.set_processed_size)
self.mode.web.share_mode.set_file_info(
self.mode.filenames, processed_size_callback=self.set_processed_size
)
self.success.emit()
self.mode.app.cleanup_filenames += self.mode.web.share_mode.cleanup_filenames
self.mode.app.cleanup_filenames += (
self.mode.web.share_mode.cleanup_filenames
)
except OSError as e:
self.error.emit(e.strerror)
def cancel(self):
self.mode.common.log('CompressThread', 'cancel')
self.mode.common.log("CompressThread", "cancel")
# Let the Web and ZipWriter objects know that we're canceling compression early
self.mode.web.cancel_compression = True

View file

@ -33,10 +33,12 @@ from .. import Mode
from ..history import History, ToggleHistory
from ...widgets import Alert
class WebsiteMode(Mode):
"""
Parts of the main window UI for sharing files.
"""
success = QtCore.pyqtSignal()
error = QtCore.pyqtSignal(str)
@ -45,7 +47,7 @@ class WebsiteMode(Mode):
Custom initialization for ReceiveMode.
"""
# Create the Web object
self.web = Web(self.common, True, 'website')
self.web = Web(self.common, True, "website")
# File selection
self.file_selection = FileSelection(self.common, self)
@ -54,7 +56,7 @@ class WebsiteMode(Mode):
self.file_selection.file_list.add_file(filename)
# Server status
self.server_status.set_mode('website', self.file_selection)
self.server_status.set_mode("website", self.file_selection)
self.server_status.server_started.connect(self.file_selection.server_started)
self.server_status.server_stopped.connect(self.file_selection.server_stopped)
self.server_status.server_stopped.connect(self.update_primary_action)
@ -69,16 +71,20 @@ class WebsiteMode(Mode):
# Filesize warning
self.filesize_warning = QtWidgets.QLabel()
self.filesize_warning.setWordWrap(True)
self.filesize_warning.setStyleSheet(self.common.css['share_filesize_warning'])
self.filesize_warning.setStyleSheet(self.common.css["share_filesize_warning"])
self.filesize_warning.hide()
# Download history
self.history = History(
self.common,
QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/share_icon_transparent.png'))),
strings._('gui_website_mode_no_files'),
strings._('gui_all_modes_history'),
'website'
QtGui.QPixmap.fromImage(
QtGui.QImage(
self.common.get_resource_path("images/share_icon_transparent.png")
)
),
strings._("gui_website_mode_no_files"),
strings._("gui_all_modes_history"),
"website",
)
self.history.in_progress_label.hide()
self.history.completed_label.hide()
@ -90,9 +96,13 @@ class WebsiteMode(Mode):
# Toggle history
self.toggle_history = ToggleHistory(
self.common, self, self.history,
QtGui.QIcon(self.common.get_resource_path('images/share_icon_toggle.png')),
QtGui.QIcon(self.common.get_resource_path('images/share_icon_toggle_selected.png'))
self.common,
self,
self.history,
QtGui.QIcon(self.common.get_resource_path("images/share_icon_toggle.png")),
QtGui.QIcon(
self.common.get_resource_path("images/share_icon_toggle_selected.png")
),
)
# Top bar
@ -126,7 +136,7 @@ class WebsiteMode(Mode):
"""
Return the string to put on the stop server button, if there's an auto-stop timer
"""
return strings._('gui_share_stop_server_autostop_timer')
return strings._("gui_share_stop_server_autostop_timer")
def autostop_timer_finished_should_stop_server(self):
"""
@ -134,10 +144,9 @@ class WebsiteMode(Mode):
"""
self.server_status.stop_server()
self.server_status_label.setText(strings._('close_on_autostop_timer'))
self.server_status_label.setText(strings._("close_on_autostop_timer"))
return True
def start_server_custom(self):
"""
Starting the server.
@ -161,7 +170,6 @@ class WebsiteMode(Mode):
self.starting_server_step3.emit()
self.start_server_finished.emit()
def start_server_step3_custom(self):
"""
Step 3 in starting the server. Display large filesize
@ -191,8 +199,7 @@ class WebsiteMode(Mode):
"""
Log that the server has been cancelled
"""
self.common.log('WebsiteMode', 'cancel_server')
self.common.log("WebsiteMode", "cancel_server")
def handle_tor_broke_custom(self):
"""
@ -210,7 +217,7 @@ class WebsiteMode(Mode):
self.info_label.show()
def update_primary_action(self):
self.common.log('WebsiteMode', 'update_primary_action')
self.common.log("WebsiteMode", "update_primary_action")
# Show or hide primary action layout
file_count = self.file_selection.file_list.count()
@ -226,9 +233,15 @@ class WebsiteMode(Mode):
total_size_readable = self.common.human_readable_filesize(total_size_bytes)
if file_count > 1:
self.info_label.setText(strings._('gui_file_info').format(file_count, total_size_readable))
self.info_label.setText(
strings._("gui_file_info").format(file_count, total_size_readable)
)
else:
self.info_label.setText(strings._('gui_file_info_single').format(file_count, total_size_readable))
self.info_label.setText(
strings._("gui_file_info_single").format(
file_count, total_size_readable
)
)
else:
self.primary_action.hide()

View file

@ -33,20 +33,24 @@ from .widgets import Alert
from .update_checker import UpdateThread
from .server_status import ServerStatus
class OnionShareGui(QtWidgets.QMainWindow):
"""
OnionShareGui is the main window for the GUI that contains all of the
GUI elements.
"""
MODE_SHARE = 'share'
MODE_RECEIVE = 'receive'
MODE_WEBSITE = 'website'
def __init__(self, common, onion, qtapp, app, filenames, config=False, local_only=False):
MODE_SHARE = "share"
MODE_RECEIVE = "receive"
MODE_WEBSITE = "website"
def __init__(
self, common, onion, qtapp, app, filenames, config=False, local_only=False
):
super(OnionShareGui, self).__init__()
self.common = common
self.common.log('OnionShareGui', '__init__')
self.common.log("OnionShareGui", "__init__")
self.setMinimumWidth(820)
self.setMinimumHeight(660)
@ -57,8 +61,10 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.mode = self.MODE_SHARE
self.setWindowTitle('OnionShare')
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
self.setWindowTitle("OnionShare")
self.setWindowIcon(
QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
)
# Load settings, if a custom config was passed in
self.config = config
@ -71,40 +77,52 @@ class OnionShareGui(QtWidgets.QMainWindow):
# System tray
menu = QtWidgets.QMenu()
self.settings_action = menu.addAction(strings._('gui_settings_window_title'))
self.settings_action = menu.addAction(strings._("gui_settings_window_title"))
self.settings_action.triggered.connect(self.open_settings)
self.help_action = menu.addAction(strings._('gui_settings_button_help'))
self.help_action = menu.addAction(strings._("gui_settings_button_help"))
self.help_action.triggered.connect(lambda: SettingsDialog.help_clicked(self))
exit_action = menu.addAction(strings._('systray_menu_exit'))
exit_action = menu.addAction(strings._("systray_menu_exit"))
exit_action.triggered.connect(self.close)
self.system_tray = QtWidgets.QSystemTrayIcon(self)
# The convention is Mac systray icons are always grayscale
if self.common.platform == 'Darwin':
self.system_tray.setIcon(QtGui.QIcon(self.common.get_resource_path('images/logo_grayscale.png')))
if self.common.platform == "Darwin":
self.system_tray.setIcon(
QtGui.QIcon(self.common.get_resource_path("images/logo_grayscale.png"))
)
else:
self.system_tray.setIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
self.system_tray.setIcon(
QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
)
self.system_tray.setContextMenu(menu)
self.system_tray.show()
# Mode switcher, to switch between share files and receive files
self.share_mode_button = QtWidgets.QPushButton(strings._('gui_mode_share_button'));
self.share_mode_button = QtWidgets.QPushButton(
strings._("gui_mode_share_button")
)
self.share_mode_button.setFixedHeight(50)
self.share_mode_button.clicked.connect(self.share_mode_clicked)
self.receive_mode_button = QtWidgets.QPushButton(strings._('gui_mode_receive_button'));
self.receive_mode_button = QtWidgets.QPushButton(
strings._("gui_mode_receive_button")
)
self.receive_mode_button.setFixedHeight(50)
self.receive_mode_button.clicked.connect(self.receive_mode_clicked)
self.website_mode_button = QtWidgets.QPushButton(strings._('gui_mode_website_button'));
self.website_mode_button = QtWidgets.QPushButton(
strings._("gui_mode_website_button")
)
self.website_mode_button.setFixedHeight(50)
self.website_mode_button.clicked.connect(self.website_mode_clicked)
self.settings_button = QtWidgets.QPushButton()
self.settings_button.setDefault(False)
self.settings_button.setFixedWidth(40)
self.settings_button.setFixedHeight(50)
self.settings_button.setIcon( QtGui.QIcon(self.common.get_resource_path('images/settings.png')) )
self.settings_button.setIcon(
QtGui.QIcon(self.common.get_resource_path("images/settings.png"))
)
self.settings_button.clicked.connect(self.open_settings)
self.settings_button.setStyleSheet(self.common.css['settings_button'])
mode_switcher_layout = QtWidgets.QHBoxLayout();
self.settings_button.setStyleSheet(self.common.css["settings_button"])
mode_switcher_layout = QtWidgets.QHBoxLayout()
mode_switcher_layout.setSpacing(0)
mode_switcher_layout.addWidget(self.share_mode_button)
mode_switcher_layout.addWidget(self.receive_mode_button)
@ -112,13 +130,21 @@ class OnionShareGui(QtWidgets.QMainWindow):
mode_switcher_layout.addWidget(self.settings_button)
# Server status indicator on the status bar
self.server_status_image_stopped = QtGui.QImage(self.common.get_resource_path('images/server_stopped.png'))
self.server_status_image_working = QtGui.QImage(self.common.get_resource_path('images/server_working.png'))
self.server_status_image_started = QtGui.QImage(self.common.get_resource_path('images/server_started.png'))
self.server_status_image_stopped = QtGui.QImage(
self.common.get_resource_path("images/server_stopped.png")
)
self.server_status_image_working = QtGui.QImage(
self.common.get_resource_path("images/server_working.png")
)
self.server_status_image_started = QtGui.QImage(
self.common.get_resource_path("images/server_started.png")
)
self.server_status_image_label = QtWidgets.QLabel()
self.server_status_image_label.setFixedWidth(20)
self.server_status_label = QtWidgets.QLabel('')
self.server_status_label.setStyleSheet(self.common.css['server_status_indicator_label'])
self.server_status_label = QtWidgets.QLabel("")
self.server_status_label.setStyleSheet(
self.common.css["server_status_indicator_label"]
)
server_status_indicator_layout = QtWidgets.QHBoxLayout()
server_status_indicator_layout.addWidget(self.server_status_image_label)
server_status_indicator_layout.addWidget(self.server_status_label)
@ -128,17 +154,34 @@ class OnionShareGui(QtWidgets.QMainWindow):
# Status bar
self.status_bar = QtWidgets.QStatusBar()
self.status_bar.setSizeGripEnabled(False)
self.status_bar.setStyleSheet(self.common.css['status_bar'])
self.status_bar.setStyleSheet(self.common.css["status_bar"])
self.status_bar.addPermanentWidget(self.server_status_indicator)
self.setStatusBar(self.status_bar)
# Share mode
self.share_mode = ShareMode(self.common, qtapp, app, self.status_bar, self.server_status_label, self.system_tray, filenames, self.local_only)
self.share_mode = ShareMode(
self.common,
qtapp,
app,
self.status_bar,
self.server_status_label,
self.system_tray,
filenames,
self.local_only,
)
self.share_mode.init()
self.share_mode.server_status.server_started.connect(self.update_server_status_indicator)
self.share_mode.server_status.server_stopped.connect(self.update_server_status_indicator)
self.share_mode.start_server_finished.connect(self.update_server_status_indicator)
self.share_mode.stop_server_finished.connect(self.update_server_status_indicator)
self.share_mode.server_status.server_started.connect(
self.update_server_status_indicator
)
self.share_mode.server_status.server_stopped.connect(
self.update_server_status_indicator
)
self.share_mode.start_server_finished.connect(
self.update_server_status_indicator
)
self.share_mode.stop_server_finished.connect(
self.update_server_status_indicator
)
self.share_mode.stop_server_finished.connect(self.stop_server_finished)
self.share_mode.start_server_finished.connect(self.clear_message)
self.share_mode.server_status.button_clicked.connect(self.clear_message)
@ -147,31 +190,68 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.share_mode.set_server_active.connect(self.set_server_active)
# Receive mode
self.receive_mode = ReceiveMode(self.common, qtapp, app, self.status_bar, self.server_status_label, self.system_tray, None, self.local_only)
self.receive_mode = ReceiveMode(
self.common,
qtapp,
app,
self.status_bar,
self.server_status_label,
self.system_tray,
None,
self.local_only,
)
self.receive_mode.init()
self.receive_mode.server_status.server_started.connect(self.update_server_status_indicator)
self.receive_mode.server_status.server_stopped.connect(self.update_server_status_indicator)
self.receive_mode.start_server_finished.connect(self.update_server_status_indicator)
self.receive_mode.stop_server_finished.connect(self.update_server_status_indicator)
self.receive_mode.server_status.server_started.connect(
self.update_server_status_indicator
)
self.receive_mode.server_status.server_stopped.connect(
self.update_server_status_indicator
)
self.receive_mode.start_server_finished.connect(
self.update_server_status_indicator
)
self.receive_mode.stop_server_finished.connect(
self.update_server_status_indicator
)
self.receive_mode.stop_server_finished.connect(self.stop_server_finished)
self.receive_mode.start_server_finished.connect(self.clear_message)
self.receive_mode.server_status.button_clicked.connect(self.clear_message)
self.receive_mode.server_status.url_copied.connect(self.copy_url)
self.receive_mode.server_status.hidservauth_copied.connect(self.copy_hidservauth)
self.receive_mode.server_status.hidservauth_copied.connect(
self.copy_hidservauth
)
self.receive_mode.set_server_active.connect(self.set_server_active)
# Website mode
self.website_mode = WebsiteMode(self.common, qtapp, app, self.status_bar, self.server_status_label, self.system_tray, filenames)
self.website_mode = WebsiteMode(
self.common,
qtapp,
app,
self.status_bar,
self.server_status_label,
self.system_tray,
filenames,
)
self.website_mode.init()
self.website_mode.server_status.server_started.connect(self.update_server_status_indicator)
self.website_mode.server_status.server_stopped.connect(self.update_server_status_indicator)
self.website_mode.start_server_finished.connect(self.update_server_status_indicator)
self.website_mode.stop_server_finished.connect(self.update_server_status_indicator)
self.website_mode.server_status.server_started.connect(
self.update_server_status_indicator
)
self.website_mode.server_status.server_stopped.connect(
self.update_server_status_indicator
)
self.website_mode.start_server_finished.connect(
self.update_server_status_indicator
)
self.website_mode.stop_server_finished.connect(
self.update_server_status_indicator
)
self.website_mode.stop_server_finished.connect(self.stop_server_finished)
self.website_mode.start_server_finished.connect(self.clear_message)
self.website_mode.server_status.button_clicked.connect(self.clear_message)
self.website_mode.server_status.url_copied.connect(self.copy_url)
self.website_mode.server_status.hidservauth_copied.connect(self.copy_hidservauth)
self.website_mode.server_status.hidservauth_copied.connect(
self.copy_hidservauth
)
self.website_mode.set_server_active.connect(self.set_server_active)
self.update_mode_switcher()
@ -218,25 +298,43 @@ class OnionShareGui(QtWidgets.QMainWindow):
# Based on the current mode, switch the mode switcher button styles,
# and show and hide widgets to switch modes
if self.mode == self.MODE_SHARE:
self.share_mode_button.setStyleSheet(self.common.css['mode_switcher_selected_style'])
self.receive_mode_button.setStyleSheet(self.common.css['mode_switcher_unselected_style'])
self.website_mode_button.setStyleSheet(self.common.css['mode_switcher_unselected_style'])
self.share_mode_button.setStyleSheet(
self.common.css["mode_switcher_selected_style"]
)
self.receive_mode_button.setStyleSheet(
self.common.css["mode_switcher_unselected_style"]
)
self.website_mode_button.setStyleSheet(
self.common.css["mode_switcher_unselected_style"]
)
self.receive_mode.hide()
self.share_mode.show()
self.website_mode.hide()
elif self.mode == self.MODE_WEBSITE:
self.share_mode_button.setStyleSheet(self.common.css['mode_switcher_unselected_style'])
self.receive_mode_button.setStyleSheet(self.common.css['mode_switcher_unselected_style'])
self.website_mode_button.setStyleSheet(self.common.css['mode_switcher_selected_style'])
self.share_mode_button.setStyleSheet(
self.common.css["mode_switcher_unselected_style"]
)
self.receive_mode_button.setStyleSheet(
self.common.css["mode_switcher_unselected_style"]
)
self.website_mode_button.setStyleSheet(
self.common.css["mode_switcher_selected_style"]
)
self.receive_mode.hide()
self.share_mode.hide()
self.website_mode.show()
else:
self.share_mode_button.setStyleSheet(self.common.css['mode_switcher_unselected_style'])
self.receive_mode_button.setStyleSheet(self.common.css['mode_switcher_selected_style'])
self.website_mode_button.setStyleSheet(self.common.css['mode_switcher_unselected_style'])
self.share_mode_button.setStyleSheet(
self.common.css["mode_switcher_unselected_style"]
)
self.receive_mode_button.setStyleSheet(
self.common.css["mode_switcher_selected_style"]
)
self.website_mode_button.setStyleSheet(
self.common.css["mode_switcher_unselected_style"]
)
self.share_mode.hide()
self.receive_mode.show()
@ -246,19 +344,19 @@ class OnionShareGui(QtWidgets.QMainWindow):
def share_mode_clicked(self):
if self.mode != self.MODE_SHARE:
self.common.log('OnionShareGui', 'share_mode_clicked')
self.common.log("OnionShareGui", "share_mode_clicked")
self.mode = self.MODE_SHARE
self.update_mode_switcher()
def receive_mode_clicked(self):
if self.mode != self.MODE_RECEIVE:
self.common.log('OnionShareGui', 'receive_mode_clicked')
self.common.log("OnionShareGui", "receive_mode_clicked")
self.mode = self.MODE_RECEIVE
self.update_mode_switcher()
def website_mode_clicked(self):
if self.mode != self.MODE_WEBSITE:
self.common.log('OnionShareGui', 'website_mode_clicked')
self.common.log("OnionShareGui", "website_mode_clicked")
self.mode = self.MODE_WEBSITE
self.update_mode_switcher()
@ -267,42 +365,82 @@ class OnionShareGui(QtWidgets.QMainWindow):
if self.mode == self.MODE_SHARE:
# Share mode
if self.share_mode.server_status.status == ServerStatus.STATUS_STOPPED:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_stopped))
self.server_status_label.setText(strings._('gui_status_indicator_share_stopped'))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_stopped)
)
self.server_status_label.setText(
strings._("gui_status_indicator_share_stopped")
)
elif self.share_mode.server_status.status == ServerStatus.STATUS_WORKING:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_working))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_working)
)
if self.share_mode.server_status.autostart_timer_datetime:
self.server_status_label.setText(strings._('gui_status_indicator_share_scheduled'))
self.server_status_label.setText(
strings._("gui_status_indicator_share_scheduled")
)
else:
self.server_status_label.setText(strings._('gui_status_indicator_share_working'))
self.server_status_label.setText(
strings._("gui_status_indicator_share_working")
)
elif self.share_mode.server_status.status == ServerStatus.STATUS_STARTED:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_started))
self.server_status_label.setText(strings._('gui_status_indicator_share_started'))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_started)
)
self.server_status_label.setText(
strings._("gui_status_indicator_share_started")
)
elif self.mode == self.MODE_WEBSITE:
# Website mode
if self.website_mode.server_status.status == ServerStatus.STATUS_STOPPED:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_stopped))
self.server_status_label.setText(strings._('gui_status_indicator_share_stopped'))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_stopped)
)
self.server_status_label.setText(
strings._("gui_status_indicator_share_stopped")
)
elif self.website_mode.server_status.status == ServerStatus.STATUS_WORKING:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_working))
self.server_status_label.setText(strings._('gui_status_indicator_share_working'))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_working)
)
self.server_status_label.setText(
strings._("gui_status_indicator_share_working")
)
elif self.website_mode.server_status.status == ServerStatus.STATUS_STARTED:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_started))
self.server_status_label.setText(strings._('gui_status_indicator_share_started'))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_started)
)
self.server_status_label.setText(
strings._("gui_status_indicator_share_started")
)
else:
# Receive mode
if self.receive_mode.server_status.status == ServerStatus.STATUS_STOPPED:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_stopped))
self.server_status_label.setText(strings._('gui_status_indicator_receive_stopped'))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_stopped)
)
self.server_status_label.setText(
strings._("gui_status_indicator_receive_stopped")
)
elif self.receive_mode.server_status.status == ServerStatus.STATUS_WORKING:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_working))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_working)
)
if self.receive_mode.server_status.autostart_timer_datetime:
self.server_status_label.setText(strings._('gui_status_indicator_receive_scheduled'))
self.server_status_label.setText(
strings._("gui_status_indicator_receive_scheduled")
)
else:
self.server_status_label.setText(strings._('gui_status_indicator_receive_working'))
self.server_status_label.setText(
strings._("gui_status_indicator_receive_working")
)
elif self.receive_mode.server_status.status == ServerStatus.STATUS_STARTED:
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_started))
self.server_status_label.setText(strings._('gui_status_indicator_receive_started'))
self.server_status_image_label.setPixmap(
QtGui.QPixmap.fromImage(self.server_status_image_started)
)
self.server_status_label.setText(
strings._("gui_status_indicator_receive_started")
)
def stop_server_finished(self):
# When the server stopped, cleanup the ephemeral onion service
@ -313,12 +451,22 @@ class OnionShareGui(QtWidgets.QMainWindow):
If the user cancels before Tor finishes connecting, ask if they want to
quit, or open settings.
"""
self.common.log('OnionShareGui', '_tor_connection_canceled')
self.common.log("OnionShareGui", "_tor_connection_canceled")
def ask():
a = Alert(self.common, strings._('gui_tor_connection_ask'), QtWidgets.QMessageBox.Question, buttons=QtWidgets.QMessageBox.NoButton, autostart=False)
settings_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_open_settings'))
quit_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_quit'))
a = Alert(
self.common,
strings._("gui_tor_connection_ask"),
QtWidgets.QMessageBox.Question,
buttons=QtWidgets.QMessageBox.NoButton,
autostart=False,
)
settings_button = QtWidgets.QPushButton(
strings._("gui_tor_connection_ask_open_settings")
)
quit_button = QtWidgets.QPushButton(
strings._("gui_tor_connection_ask_quit")
)
a.addButton(settings_button, QtWidgets.QMessageBox.AcceptRole)
a.addButton(quit_button, QtWidgets.QMessageBox.RejectRole)
a.setDefaultButton(settings_button)
@ -326,12 +474,18 @@ class OnionShareGui(QtWidgets.QMainWindow):
if a.clickedButton() == settings_button:
# Open settings
self.common.log('OnionShareGui', '_tor_connection_canceled', 'Settings button clicked')
self.common.log(
"OnionShareGui",
"_tor_connection_canceled",
"Settings button clicked",
)
self.open_settings()
if a.clickedButton() == quit_button:
# Quit
self.common.log('OnionShareGui', '_tor_connection_canceled', 'Quit button clicked')
self.common.log(
"OnionShareGui", "_tor_connection_canceled", "Quit button clicked"
)
# Wait 1ms for the event loop to finish, then quit
QtCore.QTimer.singleShot(1, self.qtapp.quit)
@ -343,7 +497,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
"""
The TorConnectionDialog wants to open the Settings dialog
"""
self.common.log('OnionShareGui', '_tor_connection_open_settings')
self.common.log("OnionShareGui", "_tor_connection_open_settings")
# Wait 1ms for the event loop to finish closing the TorConnectionDialog
QtCore.QTimer.singleShot(1, self.open_settings)
@ -352,10 +506,12 @@ class OnionShareGui(QtWidgets.QMainWindow):
"""
Open the SettingsDialog.
"""
self.common.log('OnionShareGui', 'open_settings')
self.common.log("OnionShareGui", "open_settings")
def reload_settings():
self.common.log('OnionShareGui', 'open_settings', 'settings have changed, reloading')
self.common.log(
"OnionShareGui", "open_settings", "settings have changed, reloading"
)
self.common.settings.load()
# We might've stopped the main requests timer if a Tor connection failed.
@ -371,12 +527,12 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.status_bar.clearMessage()
# If we switched off the auto-stop timer setting, ensure the widget is hidden.
if not self.common.settings.get('autostop_timer'):
if not self.common.settings.get("autostop_timer"):
self.share_mode.server_status.autostop_timer_container.hide()
self.receive_mode.server_status.autostop_timer_container.hide()
self.website_mode.server_status.autostop_timer_container.hide()
# If we switched off the auto-start timer setting, ensure the widget is hidden.
if not self.common.settings.get('autostart_timer'):
if not self.common.settings.get("autostart_timer"):
self.share_mode.server_status.autostart_timer_datetime = None
self.receive_mode.server_status.autostart_timer_datetime = None
self.website_mode.server_status.autostart_timer_datetime = None
@ -384,7 +540,9 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.receive_mode.server_status.autostart_timer_container.hide()
self.website_mode.server_status.autostart_timer_container.hide()
d = SettingsDialog(self.common, self.onion, self.qtapp, self.config, self.local_only)
d = SettingsDialog(
self.common, self.onion, self.qtapp, self.config, self.local_only
)
d.settings_saved.connect(reload_settings)
d.exec_()
@ -397,10 +555,16 @@ class OnionShareGui(QtWidgets.QMainWindow):
"""
Check for updates in a new thread, if enabled.
"""
if self.common.platform == 'Windows' or self.common.platform == 'Darwin':
if self.common.settings.get('use_autoupdate'):
if self.common.platform == "Windows" or self.common.platform == "Darwin":
if self.common.settings.get("use_autoupdate"):
def update_available(update_url, installed_version, latest_version):
Alert(self.common, strings._("update_available").format(update_url, installed_version, latest_version))
Alert(
self.common,
strings._("update_available").format(
update_url, installed_version, latest_version
),
)
self.update_thread = UpdateThread(self.common, self.onion, self.config)
self.update_thread.update_available.connect(update_available)
@ -417,8 +581,11 @@ class OnionShareGui(QtWidgets.QMainWindow):
# Have we lost connection to Tor somehow?
if not self.onion.is_authenticated():
self.timer.stop()
self.status_bar.showMessage(strings._('gui_tor_connection_lost'))
self.system_tray.showMessage(strings._('gui_tor_connection_lost'), strings._('gui_tor_connection_error_settings'))
self.status_bar.showMessage(strings._("gui_tor_connection_lost"))
self.system_tray.showMessage(
strings._("gui_tor_connection_lost"),
strings._("gui_tor_connection_error_settings"),
)
self.share_mode.handle_tor_broke()
self.receive_mode.handle_tor_broke()
@ -480,14 +647,31 @@ class OnionShareGui(QtWidgets.QMainWindow):
mode.handle_request_individual_file_canceled(event)
if event["type"] == Web.REQUEST_ERROR_DATA_DIR_CANNOT_CREATE:
Alert(self.common, strings._('error_cannot_create_data_dir').format(event["data"]["receive_mode_dir"]))
Alert(
self.common,
strings._("error_cannot_create_data_dir").format(
event["data"]["receive_mode_dir"]
),
)
if event["type"] == Web.REQUEST_OTHER:
if event["path"] != '/favicon.ico' and event["path"] != "/{}/shutdown".format(mode.web.shutdown_password):
self.status_bar.showMessage('{0:s}: {1:s}'.format(strings._('other_page_loaded'), event["path"]))
if event["path"] != "/favicon.ico" and event[
"path"
] != "/{}/shutdown".format(mode.web.shutdown_password):
self.status_bar.showMessage(
"{0:s}: {1:s}".format(
strings._("other_page_loaded"), event["path"]
)
)
if event["type"] == Web.REQUEST_INVALID_PASSWORD:
self.status_bar.showMessage('[#{0:d}] {1:s}: {2:s}'.format(mode.web.invalid_passwords_count, strings._('incorrect_password'), event["data"]))
self.status_bar.showMessage(
"[#{0:d}] {1:s}: {2:s}".format(
mode.web.invalid_passwords_count,
strings._("incorrect_password"),
event["data"],
)
)
mode.timer_callback()
@ -495,15 +679,20 @@ class OnionShareGui(QtWidgets.QMainWindow):
"""
When the URL gets copied to the clipboard, display this in the status bar.
"""
self.common.log('OnionShareGui', 'copy_url')
self.system_tray.showMessage(strings._('gui_copied_url_title'), strings._('gui_copied_url'))
self.common.log("OnionShareGui", "copy_url")
self.system_tray.showMessage(
strings._("gui_copied_url_title"), strings._("gui_copied_url")
)
def copy_hidservauth(self):
"""
When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar.
"""
self.common.log('OnionShareGui', 'copy_hidservauth')
self.system_tray.showMessage(strings._('gui_copied_hidservauth_title'), strings._('gui_copied_hidservauth'))
self.common.log("OnionShareGui", "copy_hidservauth")
self.system_tray.showMessage(
strings._("gui_copied_hidservauth_title"),
strings._("gui_copied_hidservauth"),
)
def clear_message(self):
"""
@ -539,7 +728,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.settings_action.setEnabled(not active)
def closeEvent(self, e):
self.common.log('OnionShareGui', 'closeEvent')
self.common.log("OnionShareGui", "closeEvent")
self.system_tray.hide()
try:
if self.mode == OnionShareGui.MODE_SHARE:
@ -549,16 +738,21 @@ class OnionShareGui(QtWidgets.QMainWindow):
else:
server_status = self.receive_mode.server_status
if server_status.status != server_status.STATUS_STOPPED:
self.common.log('OnionShareGui', 'closeEvent, opening warning dialog')
self.common.log("OnionShareGui", "closeEvent, opening warning dialog")
dialog = QtWidgets.QMessageBox()
dialog.setWindowTitle(strings._('gui_quit_title'))
dialog.setWindowTitle(strings._("gui_quit_title"))
if self.mode == OnionShareGui.MODE_SHARE:
dialog.setText(strings._('gui_share_quit_warning'))
dialog.setText(strings._("gui_share_quit_warning"))
else:
dialog.setText(strings._('gui_receive_quit_warning'))
dialog.setText(strings._("gui_receive_quit_warning"))
dialog.setIcon(QtWidgets.QMessageBox.Critical)
quit_button = dialog.addButton(strings._('gui_quit_warning_quit'), QtWidgets.QMessageBox.YesRole)
dont_quit_button = dialog.addButton(strings._('gui_quit_warning_dont_quit'), QtWidgets.QMessageBox.NoRole)
quit_button = dialog.addButton(
strings._("gui_quit_warning_quit"), QtWidgets.QMessageBox.YesRole
)
dont_quit_button = dialog.addButton(
strings._("gui_quit_warning_dont_quit"),
QtWidgets.QMessageBox.NoRole,
)
dialog.setDefaultButton(dont_quit_button)
reply = dialog.exec_()

View file

@ -25,10 +25,12 @@ from onionshare import strings
from .widgets import Alert
class ServerStatus(QtWidgets.QWidget):
"""
The server status chunk of the GUI.
"""
server_started = QtCore.pyqtSignal()
server_started_finished = QtCore.pyqtSignal()
server_stopped = QtCore.pyqtSignal()
@ -37,9 +39,9 @@ class ServerStatus(QtWidgets.QWidget):
url_copied = QtCore.pyqtSignal()
hidservauth_copied = QtCore.pyqtSignal()
MODE_SHARE = 'share'
MODE_RECEIVE = 'receive'
MODE_WEBSITE = 'website'
MODE_SHARE = "share"
MODE_RECEIVE = "receive"
MODE_WEBSITE = "website"
STATUS_STOPPED = 0
STATUS_WORKING = 1
@ -51,7 +53,7 @@ class ServerStatus(QtWidgets.QWidget):
self.common = common
self.status = self.STATUS_STOPPED
self.mode = None # Gets set in self.set_mode
self.mode = None # Gets set in self.set_mode
self.qtapp = qtapp
self.app = app
@ -63,19 +65,31 @@ class ServerStatus(QtWidgets.QWidget):
self.resizeEvent(None)
# Auto-start timer layout
self.autostart_timer_label = QtWidgets.QLabel(strings._('gui_settings_autostart_timer'))
self.autostart_timer_label = QtWidgets.QLabel(
strings._("gui_settings_autostart_timer")
)
self.autostart_timer_widget = QtWidgets.QDateTimeEdit()
self.autostart_timer_widget.setDisplayFormat("hh:mm A MMM d, yy")
if self.local_only:
# For testing
self.autostart_timer_widget.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(15))
self.autostart_timer_widget.setMinimumDateTime(QtCore.QDateTime.currentDateTime())
self.autostart_timer_widget.setDateTime(
QtCore.QDateTime.currentDateTime().addSecs(15)
)
self.autostart_timer_widget.setMinimumDateTime(
QtCore.QDateTime.currentDateTime()
)
else:
# Set proposed timer to be 5 minutes into the future
self.autostart_timer_widget.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(300))
self.autostart_timer_widget.setDateTime(
QtCore.QDateTime.currentDateTime().addSecs(300)
)
# Onion services can take a little while to start, so reduce the risk of it expiring too soon by setting the minimum to 60s from now
self.autostart_timer_widget.setMinimumDateTime(QtCore.QDateTime.currentDateTime().addSecs(60))
self.autostart_timer_widget.setCurrentSection(QtWidgets.QDateTimeEdit.MinuteSection)
self.autostart_timer_widget.setMinimumDateTime(
QtCore.QDateTime.currentDateTime().addSecs(60)
)
self.autostart_timer_widget.setCurrentSection(
QtWidgets.QDateTimeEdit.MinuteSection
)
autostart_timer_layout = QtWidgets.QHBoxLayout()
autostart_timer_layout.addWidget(self.autostart_timer_label)
autostart_timer_layout.addWidget(self.autostart_timer_widget)
@ -88,19 +102,31 @@ class ServerStatus(QtWidgets.QWidget):
self.autostart_timer_container.hide()
# Auto-stop timer layout
self.autostop_timer_label = QtWidgets.QLabel(strings._('gui_settings_autostop_timer'))
self.autostop_timer_label = QtWidgets.QLabel(
strings._("gui_settings_autostop_timer")
)
self.autostop_timer_widget = QtWidgets.QDateTimeEdit()
self.autostop_timer_widget.setDisplayFormat("hh:mm A MMM d, yy")
if self.local_only:
# For testing
self.autostop_timer_widget.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(15))
self.autostop_timer_widget.setMinimumDateTime(QtCore.QDateTime.currentDateTime())
self.autostop_timer_widget.setDateTime(
QtCore.QDateTime.currentDateTime().addSecs(15)
)
self.autostop_timer_widget.setMinimumDateTime(
QtCore.QDateTime.currentDateTime()
)
else:
# Set proposed timer to be 5 minutes into the future
self.autostop_timer_widget.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(300))
self.autostop_timer_widget.setDateTime(
QtCore.QDateTime.currentDateTime().addSecs(300)
)
# Onion services can take a little while to start, so reduce the risk of it expiring too soon by setting the minimum to 60s from now
self.autostop_timer_widget.setMinimumDateTime(QtCore.QDateTime.currentDateTime().addSecs(60))
self.autostop_timer_widget.setCurrentSection(QtWidgets.QDateTimeEdit.MinuteSection)
self.autostop_timer_widget.setMinimumDateTime(
QtCore.QDateTime.currentDateTime().addSecs(60)
)
self.autostop_timer_widget.setCurrentSection(
QtWidgets.QDateTimeEdit.MinuteSection
)
autostop_timer_layout = QtWidgets.QHBoxLayout()
autostop_timer_layout.addWidget(self.autostop_timer_label)
autostop_timer_layout.addWidget(self.autostop_timer_widget)
@ -125,16 +151,20 @@ class ServerStatus(QtWidgets.QWidget):
self.url.setFont(url_font)
self.url.setWordWrap(True)
self.url.setMinimumSize(self.url.sizeHint())
self.url.setStyleSheet(self.common.css['server_status_url'])
self.url.setStyleSheet(self.common.css["server_status_url"])
self.copy_url_button = QtWidgets.QPushButton(strings._('gui_copy_url'))
self.copy_url_button = QtWidgets.QPushButton(strings._("gui_copy_url"))
self.copy_url_button.setFlat(True)
self.copy_url_button.setStyleSheet(self.common.css['server_status_url_buttons'])
self.copy_url_button.setStyleSheet(self.common.css["server_status_url_buttons"])
self.copy_url_button.setMinimumHeight(65)
self.copy_url_button.clicked.connect(self.copy_url)
self.copy_hidservauth_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth'))
self.copy_hidservauth_button = QtWidgets.QPushButton(
strings._("gui_copy_hidservauth")
)
self.copy_hidservauth_button.setFlat(True)
self.copy_hidservauth_button.setStyleSheet(self.common.css['server_status_url_buttons'])
self.copy_hidservauth_button.setStyleSheet(
self.common.css["server_status_url_buttons"]
)
self.copy_hidservauth_button.clicked.connect(self.copy_hidservauth)
url_buttons_layout = QtWidgets.QHBoxLayout()
url_buttons_layout.addWidget(self.copy_url_button)
@ -160,7 +190,9 @@ class ServerStatus(QtWidgets.QWidget):
"""
self.mode = share_mode
if (self.mode == ServerStatus.MODE_SHARE) or (self.mode == ServerStatus.MODE_WEBSITE):
if (self.mode == ServerStatus.MODE_SHARE) or (
self.mode == ServerStatus.MODE_WEBSITE
):
self.file_selection = file_selection
self.update()
@ -171,7 +203,7 @@ class ServerStatus(QtWidgets.QWidget):
"""
try:
# Wrap the URL label
url_length=len(self.get_url())
url_length = len(self.get_url())
if url_length > 60:
width = self.frameGeometry().width()
if width < 530:
@ -186,17 +218,25 @@ class ServerStatus(QtWidgets.QWidget):
"""
Reset the auto-start timer in the UI after stopping a share
"""
self.autostart_timer_widget.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(300))
self.autostart_timer_widget.setDateTime(
QtCore.QDateTime.currentDateTime().addSecs(300)
)
if not self.local_only:
self.autostart_timer_widget.setMinimumDateTime(QtCore.QDateTime.currentDateTime().addSecs(60))
self.autostart_timer_widget.setMinimumDateTime(
QtCore.QDateTime.currentDateTime().addSecs(60)
)
def autostop_timer_reset(self):
"""
Reset the auto-stop timer in the UI after stopping a share
"""
self.autostop_timer_widget.setDateTime(QtCore.QDateTime.currentDateTime().addSecs(300))
self.autostop_timer_widget.setDateTime(
QtCore.QDateTime.currentDateTime().addSecs(300)
)
if not self.local_only:
self.autostop_timer_widget.setMinimumDateTime(QtCore.QDateTime.currentDateTime().addSecs(60))
self.autostop_timer_widget.setMinimumDateTime(
QtCore.QDateTime.currentDateTime().addSecs(60)
)
def show_url(self):
"""
@ -204,26 +244,38 @@ class ServerStatus(QtWidgets.QWidget):
"""
self.url_description.show()
info_image = self.common.get_resource_path('images/info.png')
info_image = self.common.get_resource_path("images/info.png")
if self.mode == ServerStatus.MODE_SHARE:
self.url_description.setText(strings._('gui_share_url_description').format(info_image))
self.url_description.setText(
strings._("gui_share_url_description").format(info_image)
)
elif self.mode == ServerStatus.MODE_WEBSITE:
self.url_description.setText(strings._('gui_website_url_description').format(info_image))
self.url_description.setText(
strings._("gui_website_url_description").format(info_image)
)
else:
self.url_description.setText(strings._('gui_receive_url_description').format(info_image))
self.url_description.setText(
strings._("gui_receive_url_description").format(info_image)
)
# Show a Tool Tip explaining the lifecycle of this URL
if self.common.settings.get('save_private_key'):
if self.mode == ServerStatus.MODE_SHARE and self.common.settings.get('close_after_first_download'):
self.url_description.setToolTip(strings._('gui_url_label_onetime_and_persistent'))
if self.common.settings.get("save_private_key"):
if self.mode == ServerStatus.MODE_SHARE and self.common.settings.get(
"close_after_first_download"
):
self.url_description.setToolTip(
strings._("gui_url_label_onetime_and_persistent")
)
else:
self.url_description.setToolTip(strings._('gui_url_label_persistent'))
self.url_description.setToolTip(strings._("gui_url_label_persistent"))
else:
if self.mode == ServerStatus.MODE_SHARE and self.common.settings.get('close_after_first_download'):
self.url_description.setToolTip(strings._('gui_url_label_onetime'))
if self.mode == ServerStatus.MODE_SHARE and self.common.settings.get(
"close_after_first_download"
):
self.url_description.setToolTip(strings._("gui_url_label_onetime"))
else:
self.url_description.setToolTip(strings._('gui_url_label_stay_open'))
self.url_description.setToolTip(strings._("gui_url_label_stay_open"))
self.url.setText(self.get_url())
self.url.show()
@ -245,15 +297,15 @@ class ServerStatus(QtWidgets.QWidget):
self.common.settings.load()
self.show_url()
if self.common.settings.get('save_private_key'):
if not self.common.settings.get('password'):
self.common.settings.set('password', self.web.password)
if self.common.settings.get("save_private_key"):
if not self.common.settings.get("password"):
self.common.settings.set("password", self.web.password)
self.common.settings.save()
if self.common.settings.get('autostart_timer'):
if self.common.settings.get("autostart_timer"):
self.autostart_timer_container.hide()
if self.common.settings.get('autostop_timer'):
if self.common.settings.get("autostop_timer"):
self.autostop_timer_container.hide()
else:
self.url_description.hide()
@ -262,59 +314,91 @@ class ServerStatus(QtWidgets.QWidget):
self.copy_hidservauth_button.hide()
# Button
if self.mode == ServerStatus.MODE_SHARE and self.file_selection.get_num_files() == 0:
if (
self.mode == ServerStatus.MODE_SHARE
and self.file_selection.get_num_files() == 0
):
self.server_button.hide()
elif self.mode == ServerStatus.MODE_WEBSITE and self.file_selection.get_num_files() == 0:
elif (
self.mode == ServerStatus.MODE_WEBSITE
and self.file_selection.get_num_files() == 0
):
self.server_button.hide()
else:
self.server_button.show()
if self.status == self.STATUS_STOPPED:
self.server_button.setStyleSheet(self.common.css['server_status_button_stopped'])
self.server_button.setStyleSheet(
self.common.css["server_status_button_stopped"]
)
self.server_button.setEnabled(True)
if self.mode == ServerStatus.MODE_SHARE:
self.server_button.setText(strings._('gui_share_start_server'))
self.server_button.setText(strings._("gui_share_start_server"))
elif self.mode == ServerStatus.MODE_WEBSITE:
self.server_button.setText(strings._('gui_share_start_server'))
self.server_button.setText(strings._("gui_share_start_server"))
else:
self.server_button.setText(strings._('gui_receive_start_server'))
self.server_button.setToolTip('')
if self.common.settings.get('autostart_timer'):
self.server_button.setText(strings._("gui_receive_start_server"))
self.server_button.setToolTip("")
if self.common.settings.get("autostart_timer"):
self.autostart_timer_container.show()
if self.common.settings.get('autostop_timer'):
if self.common.settings.get("autostop_timer"):
self.autostop_timer_container.show()
elif self.status == self.STATUS_STARTED:
self.server_button.setStyleSheet(self.common.css['server_status_button_started'])
self.server_button.setStyleSheet(
self.common.css["server_status_button_started"]
)
self.server_button.setEnabled(True)
if self.mode == ServerStatus.MODE_SHARE:
self.server_button.setText(strings._('gui_share_stop_server'))
self.server_button.setText(strings._("gui_share_stop_server"))
elif self.mode == ServerStatus.MODE_WEBSITE:
self.server_button.setText(strings._('gui_share_stop_server'))
self.server_button.setText(strings._("gui_share_stop_server"))
else:
self.server_button.setText(strings._('gui_receive_stop_server'))
if self.common.settings.get('autostart_timer'):
self.server_button.setText(strings._("gui_receive_stop_server"))
if self.common.settings.get("autostart_timer"):
self.autostart_timer_container.hide()
if self.common.settings.get('autostop_timer'):
if self.common.settings.get("autostop_timer"):
self.autostop_timer_container.hide()
self.server_button.setToolTip(strings._('gui_stop_server_autostop_timer_tooltip').format(self.autostop_timer_widget.dateTime().toString("h:mm AP, MMMM dd, yyyy")))
self.server_button.setToolTip(
strings._("gui_stop_server_autostop_timer_tooltip").format(
self.autostop_timer_widget.dateTime().toString(
"h:mm AP, MMMM dd, yyyy"
)
)
)
elif self.status == self.STATUS_WORKING:
self.server_button.setStyleSheet(self.common.css['server_status_button_working'])
self.server_button.setStyleSheet(
self.common.css["server_status_button_working"]
)
self.server_button.setEnabled(True)
if self.autostart_timer_datetime:
self.autostart_timer_container.hide()
self.server_button.setToolTip(strings._('gui_start_server_autostart_timer_tooltip').format(self.autostart_timer_widget.dateTime().toString("h:mm AP, MMMM dd, yyyy")))
self.server_button.setToolTip(
strings._("gui_start_server_autostart_timer_tooltip").format(
self.autostart_timer_widget.dateTime().toString(
"h:mm AP, MMMM dd, yyyy"
)
)
)
else:
self.server_button.setText(strings._('gui_please_wait'))
if self.common.settings.get('autostop_timer'):
self.server_button.setText(strings._("gui_please_wait"))
if self.common.settings.get("autostop_timer"):
self.autostop_timer_container.hide()
else:
self.server_button.setStyleSheet(self.common.css['server_status_button_working'])
self.server_button.setStyleSheet(
self.common.css["server_status_button_working"]
)
self.server_button.setEnabled(False)
self.server_button.setText(strings._('gui_please_wait'))
if self.common.settings.get('autostart_timer'):
self.server_button.setText(strings._("gui_please_wait"))
if self.common.settings.get("autostart_timer"):
self.autostart_timer_container.hide()
self.server_button.setToolTip(strings._('gui_start_server_autostart_timer_tooltip').format(self.autostart_timer_widget.dateTime().toString("h:mm AP, MMMM dd, yyyy")))
if self.common.settings.get('autostop_timer'):
self.server_button.setToolTip(
strings._("gui_start_server_autostart_timer_tooltip").format(
self.autostart_timer_widget.dateTime().toString(
"h:mm AP, MMMM dd, yyyy"
)
)
)
if self.common.settings.get("autostop_timer"):
self.autostop_timer_container.hide()
def server_button_clicked(self):
@ -323,28 +407,60 @@ class ServerStatus(QtWidgets.QWidget):
"""
if self.status == self.STATUS_STOPPED:
can_start = True
if self.common.settings.get('autostart_timer'):
if self.common.settings.get("autostart_timer"):
if self.local_only:
self.autostart_timer_datetime = self.autostart_timer_widget.dateTime().toPyDateTime()
self.autostart_timer_datetime = (
self.autostart_timer_widget.dateTime().toPyDateTime()
)
else:
self.autostart_timer_datetime = self.autostart_timer_widget.dateTime().toPyDateTime().replace(second=0, microsecond=0)
self.autostart_timer_datetime = (
self.autostart_timer_widget.dateTime()
.toPyDateTime()
.replace(second=0, microsecond=0)
)
# If the timer has actually passed already before the user hit Start, refuse to start the server.
if QtCore.QDateTime.currentDateTime().toPyDateTime() > self.autostart_timer_datetime:
if (
QtCore.QDateTime.currentDateTime().toPyDateTime()
> self.autostart_timer_datetime
):
can_start = False
Alert(self.common, strings._('gui_server_autostart_timer_expired'), QtWidgets.QMessageBox.Warning)
if self.common.settings.get('autostop_timer'):
Alert(
self.common,
strings._("gui_server_autostart_timer_expired"),
QtWidgets.QMessageBox.Warning,
)
if self.common.settings.get("autostop_timer"):
if self.local_only:
self.autostop_timer_datetime = self.autostop_timer_widget.dateTime().toPyDateTime()
self.autostop_timer_datetime = (
self.autostop_timer_widget.dateTime().toPyDateTime()
)
else:
# Get the timer chosen, stripped of its seconds. This prevents confusion if the share stops at (say) 37 seconds past the minute chosen
self.autostop_timer_datetime = self.autostop_timer_widget.dateTime().toPyDateTime().replace(second=0, microsecond=0)
self.autostop_timer_datetime = (
self.autostop_timer_widget.dateTime()
.toPyDateTime()
.replace(second=0, microsecond=0)
)
# If the timer has actually passed already before the user hit Start, refuse to start the server.
if QtCore.QDateTime.currentDateTime().toPyDateTime() > self.autostop_timer_datetime:
if (
QtCore.QDateTime.currentDateTime().toPyDateTime()
> self.autostop_timer_datetime
):
can_start = False
Alert(self.common, strings._('gui_server_autostop_timer_expired'), QtWidgets.QMessageBox.Warning)
if self.common.settings.get('autostart_timer'):
Alert(
self.common,
strings._("gui_server_autostop_timer_expired"),
QtWidgets.QMessageBox.Warning,
)
if self.common.settings.get("autostart_timer"):
if self.autostop_timer_datetime <= self.autostart_timer_datetime:
Alert(self.common, strings._('gui_autostop_timer_cant_be_earlier_than_autostart_timer'), QtWidgets.QMessageBox.Warning)
Alert(
self.common,
strings._(
"gui_autostop_timer_cant_be_earlier_than_autostart_timer"
),
QtWidgets.QMessageBox.Warning,
)
can_start = False
if can_start:
self.start_server()
@ -385,7 +501,9 @@ class ServerStatus(QtWidgets.QWidget):
"""
Cancel the server.
"""
self.common.log('ServerStatus', 'cancel_server', 'Canceling the server mid-startup')
self.common.log(
"ServerStatus", "cancel_server", "Canceling the server mid-startup"
)
self.status = self.STATUS_WORKING
self.autostart_timer_reset()
self.autostop_timer_reset()
@ -421,8 +539,10 @@ class ServerStatus(QtWidgets.QWidget):
"""
Returns the OnionShare URL.
"""
if self.common.settings.get('public_mode'):
url = 'http://{0:s}'.format(self.app.onion_host)
if self.common.settings.get("public_mode"):
url = "http://{0:s}".format(self.app.onion_host)
else:
url = 'http://onionshare:{0:s}@{1:s}'.format(self.web.password, self.app.onion_host)
url = "http://onionshare:{0:s}@{1:s}".format(
self.web.password, self.app.onion_host
)
return url

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,7 @@ class OnionThread(QtCore.QThread):
"""
Starts the onion service, and waits for it to finish
"""
success = QtCore.pyqtSignal()
success_early = QtCore.pyqtSignal()
error = QtCore.pyqtSignal(str)
@ -34,28 +35,34 @@ class OnionThread(QtCore.QThread):
def __init__(self, mode):
super(OnionThread, self).__init__()
self.mode = mode
self.mode.common.log('OnionThread', '__init__')
self.mode.common.log("OnionThread", "__init__")
# allow this thread to be terminated
self.setTerminationEnabled()
def run(self):
self.mode.common.log('OnionThread', 'run')
self.mode.common.log("OnionThread", "run")
# Make a new static URL path for each new share
self.mode.web.generate_static_url_path()
# Choose port and password early, because we need them to exist in advance for scheduled shares
self.mode.app.stay_open = not self.mode.common.settings.get('close_after_first_download')
self.mode.app.stay_open = not self.mode.common.settings.get(
"close_after_first_download"
)
if not self.mode.app.port:
self.mode.app.choose_port()
if not self.mode.common.settings.get('public_mode'):
if not self.mode.common.settings.get("public_mode"):
if not self.mode.web.password:
self.mode.web.generate_password(self.mode.common.settings.get('password'))
self.mode.web.generate_password(
self.mode.common.settings.get("password")
)
try:
if self.mode.obtain_onion_early:
self.mode.app.start_onion_service(await_publication=False, save_scheduled_key=True)
self.mode.app.start_onion_service(
await_publication=False, save_scheduled_key=True
)
# wait for modules in thread to load, preventing a thread-related cx_Freeze crash
time.sleep(0.2)
self.success_early.emit()
@ -70,7 +77,19 @@ class OnionThread(QtCore.QThread):
self.mode.web_thread.start()
self.success.emit()
except (TorTooOld, TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorTimeout, OSError) as e:
except (
TorTooOld,
TorErrorInvalidSetting,
TorErrorAutomatic,
TorErrorSocketPort,
TorErrorSocketFile,
TorErrorMissingPassword,
TorErrorUnreadableCookieFile,
TorErrorAuthError,
TorErrorProtocolError,
BundledTorTimeout,
OSError,
) as e:
self.error.emit(e.args[0])
return
@ -79,17 +98,23 @@ class WebThread(QtCore.QThread):
"""
Starts the web service
"""
success = QtCore.pyqtSignal()
error = QtCore.pyqtSignal(str)
def __init__(self, mode):
super(WebThread, self).__init__()
self.mode = mode
self.mode.common.log('WebThread', '__init__')
self.mode.common.log("WebThread", "__init__")
def run(self):
self.mode.common.log('WebThread', 'run')
self.mode.web.start(self.mode.app.port, self.mode.app.stay_open, self.mode.common.settings.get('public_mode'), self.mode.web.password)
self.mode.common.log("WebThread", "run")
self.mode.web.start(
self.mode.app.port,
self.mode.app.stay_open,
self.mode.common.settings.get("public_mode"),
self.mode.web.password,
)
self.success.emit()
@ -97,30 +122,40 @@ class AutoStartTimer(QtCore.QThread):
"""
Waits for a prescribed time before allowing a share to start
"""
success = QtCore.pyqtSignal()
error = QtCore.pyqtSignal(str)
def __init__(self, mode, canceled=False):
super(AutoStartTimer, self).__init__()
self.mode = mode
self.canceled = canceled
self.mode.common.log('AutoStartTimer', '__init__')
self.mode.common.log("AutoStartTimer", "__init__")
# allow this thread to be terminated
self.setTerminationEnabled()
def run(self):
now = QtCore.QDateTime.currentDateTime()
autostart_timer_datetime_delta = now.secsTo(self.mode.server_status.autostart_timer_datetime)
autostart_timer_datetime_delta = now.secsTo(
self.mode.server_status.autostart_timer_datetime
)
try:
# Sleep until scheduled time
while autostart_timer_datetime_delta > 0 and self.canceled == False:
time.sleep(0.1)
now = QtCore.QDateTime.currentDateTime()
autostart_timer_datetime_delta = now.secsTo(self.mode.server_status.autostart_timer_datetime)
autostart_timer_datetime_delta = now.secsTo(
self.mode.server_status.autostart_timer_datetime
)
# Timer has now finished
if self.canceled == False:
self.mode.server_status.server_button.setText(strings._('gui_please_wait'))
self.mode.server_status_label.setText(strings._('gui_status_indicator_share_working'))
self.mode.server_status.server_button.setText(
strings._("gui_please_wait")
)
self.mode.server_status_label.setText(
strings._("gui_status_indicator_share_working")
)
self.success.emit()
except ValueError as e:
self.error.emit(e.args[0])

View file

@ -24,10 +24,12 @@ from onionshare.onion import *
from .widgets import Alert
class TorConnectionDialog(QtWidgets.QProgressDialog):
"""
Connecting to Tor dialog.
"""
open_settings = QtCore.pyqtSignal()
def __init__(self, common, qtapp, onion, custom_settings=False):
@ -40,18 +42,20 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
else:
self.settings = self.common.settings
self.common.log('TorConnectionDialog', '__init__')
self.common.log("TorConnectionDialog", "__init__")
self.qtapp = qtapp
self.onion = onion
self.setWindowTitle("OnionShare")
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
self.setWindowIcon(
QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
)
self.setModal(True)
self.setFixedSize(400, 150)
# Label
self.setLabelText(strings._('connecting_to_tor'))
self.setLabelText(strings._("connecting_to_tor"))
# Progress bar ticks from 0 to 100
self.setRange(0, 100)
@ -59,10 +63,10 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
self.setMinimumDuration(100)
# Start displaying the status at 0
self._tor_status_update(0, '')
self._tor_status_update(0, "")
def start(self):
self.common.log('TorConnectionDialog', 'start')
self.common.log("TorConnectionDialog", "start")
t = TorConnectionThread(self.common, self.settings, self, self.onion)
t.tor_status_update.connect(self._tor_status_update)
@ -81,17 +85,19 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
def _tor_status_update(self, progress, summary):
self.setValue(int(progress))
self.setLabelText("<strong>{}</strong><br>{}".format(strings._('connecting_to_tor'), summary))
self.setLabelText(
"<strong>{}</strong><br>{}".format(strings._("connecting_to_tor"), summary)
)
def _connected_to_tor(self):
self.common.log('TorConnectionDialog', '_connected_to_tor')
self.common.log("TorConnectionDialog", "_connected_to_tor")
self.active = False
# Close the dialog after connecting
self.setValue(self.maximum())
def _canceled_connecting_to_tor(self):
self.common.log('TorConnectionDialog', '_canceled_connecting_to_tor')
self.common.log("TorConnectionDialog", "_canceled_connecting_to_tor")
self.active = False
self.onion.cleanup()
@ -99,12 +105,16 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
QtCore.QTimer.singleShot(1, self.cancel)
def _error_connecting_to_tor(self, msg):
self.common.log('TorConnectionDialog', '_error_connecting_to_tor')
self.common.log("TorConnectionDialog", "_error_connecting_to_tor")
self.active = False
def alert_and_open_settings():
# Display the exception in an alert box
Alert(self.common, "{}\n\n{}".format(msg, strings._('gui_tor_connection_error_settings')), QtWidgets.QMessageBox.Warning)
Alert(
self.common,
"{}\n\n{}".format(msg, strings._("gui_tor_connection_error_settings")),
QtWidgets.QMessageBox.Warning,
)
# Open settings
self.open_settings.emit()
@ -114,6 +124,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
# Cancel connecting to Tor
QtCore.QTimer.singleShot(1, self.cancel)
class TorConnectionThread(QtCore.QThread):
tor_status_update = QtCore.pyqtSignal(str, str)
connected_to_tor = QtCore.pyqtSignal()
@ -125,7 +136,7 @@ class TorConnectionThread(QtCore.QThread):
self.common = common
self.common.log('TorConnectionThread', '__init__')
self.common.log("TorConnectionThread", "__init__")
self.settings = settings
@ -133,7 +144,7 @@ class TorConnectionThread(QtCore.QThread):
self.onion = onion
def run(self):
self.common.log('TorConnectionThread', 'run')
self.common.log("TorConnectionThread", "run")
# Connect to the Onion
try:
@ -144,11 +155,15 @@ class TorConnectionThread(QtCore.QThread):
self.canceled_connecting_to_tor.emit()
except BundledTorCanceled as e:
self.common.log('TorConnectionThread', 'run', 'caught exception: BundledTorCanceled')
self.common.log(
"TorConnectionThread", "run", "caught exception: BundledTorCanceled"
)
self.canceled_connecting_to_tor.emit()
except Exception as e:
self.common.log('TorConnectionThread', 'run', 'caught exception: {}'.format(e.args[0]))
self.common.log(
"TorConnectionThread", "run", "caught exception: {}".format(e.args[0])
)
self.error_connecting_to_tor.emit(str(e.args[0]))
def _tor_status_update(self, progress, summary):

View file

@ -27,21 +27,26 @@ from onionshare.onion import Onion
from onionshare import strings
class UpdateCheckerCheckError(Exception):
"""
Error checking for updates because of some Tor connection issue, or because
the OnionShare website is down.
"""
pass
class UpdateCheckerInvalidLatestVersion(Exception):
"""
Successfully downloaded the latest version, but it doesn't appear to be a
valid version string.
"""
def __init__(self, latest_version):
self.latest_version = latest_version
class UpdateChecker(QtCore.QObject):
"""
Load http://elx57ue5uyfplgva.onion/latest-version.txt to see what the latest
@ -50,6 +55,7 @@ class UpdateChecker(QtCore.QObject):
Only check at most once per day, unless force is True.
"""
update_available = QtCore.pyqtSignal(str, str, str)
update_not_available = QtCore.pyqtSignal()
update_error = QtCore.pyqtSignal()
@ -60,12 +66,12 @@ class UpdateChecker(QtCore.QObject):
self.common = common
self.common.log('UpdateChecker', '__init__')
self.common.log("UpdateChecker", "__init__")
self.onion = onion
self.config = config
def check(self, force=False, config=False):
self.common.log('UpdateChecker', 'check', 'force={}'.format(force))
self.common.log("UpdateChecker", "check", "force={}".format(force))
# Load the settings
settings = Settings(self.common, config)
settings.load()
@ -77,7 +83,7 @@ class UpdateChecker(QtCore.QObject):
check_for_updates = False
# See if it's been 1 day since the last check
autoupdate_timestamp = settings.get('autoupdate_timestamp')
autoupdate_timestamp = settings.get("autoupdate_timestamp")
if autoupdate_timestamp:
last_checked = datetime.datetime.fromtimestamp(autoupdate_timestamp)
now = datetime.datetime.now()
@ -90,45 +96,61 @@ class UpdateChecker(QtCore.QObject):
# Check for updates
if check_for_updates:
self.common.log('UpdateChecker', 'check', 'checking for updates')
self.common.log("UpdateChecker", "check", "checking for updates")
# Download the latest-version file over Tor
try:
# User agent string includes OnionShare version and platform
user_agent = 'OnionShare {}, {}'.format(self.common.version, self.common.platform)
user_agent = "OnionShare {}, {}".format(
self.common.version, self.common.platform
)
# If the update is forced, add '?force=1' to the URL, to more
# accurately measure daily users
path = '/latest-version.txt'
path = "/latest-version.txt"
if force:
path += '?force=1'
path += "?force=1"
if Version(self.onion.tor_version) >= Version('0.3.2.9'):
onion_domain = 'lldan5gahapx5k7iafb3s4ikijc4ni7gx5iywdflkba5y2ezyg6sjgyd.onion'
if Version(self.onion.tor_version) >= Version("0.3.2.9"):
onion_domain = (
"lldan5gahapx5k7iafb3s4ikijc4ni7gx5iywdflkba5y2ezyg6sjgyd.onion"
)
else:
onion_domain = 'elx57ue5uyfplgva.onion'
onion_domain = "elx57ue5uyfplgva.onion"
self.common.log('UpdateChecker', 'check', 'loading http://{}{}'.format(onion_domain, path))
self.common.log(
"UpdateChecker",
"check",
"loading http://{}{}".format(onion_domain, path),
)
(socks_address, socks_port) = self.onion.get_tor_socks_port()
socks.set_default_proxy(socks.SOCKS5, socks_address, socks_port)
s = socks.socksocket()
s.settimeout(15) # 15 second timeout
s.settimeout(15) # 15 second timeout
s.connect((onion_domain, 80))
http_request = 'GET {} HTTP/1.0\r\n'.format(path)
http_request += 'Host: {}\r\n'.format(onion_domain)
http_request += 'User-Agent: {}\r\n'.format(user_agent)
http_request += '\r\n'
s.sendall(http_request.encode('utf-8'))
http_request = "GET {} HTTP/1.0\r\n".format(path)
http_request += "Host: {}\r\n".format(onion_domain)
http_request += "User-Agent: {}\r\n".format(user_agent)
http_request += "\r\n"
s.sendall(http_request.encode("utf-8"))
http_response = s.recv(1024)
latest_version = http_response[http_response.find(b'\r\n\r\n'):].strip().decode('utf-8')
latest_version = (
http_response[http_response.find(b"\r\n\r\n") :]
.strip()
.decode("utf-8")
)
self.common.log('UpdateChecker', 'check', 'latest OnionShare version: {}'.format(latest_version))
self.common.log(
"UpdateChecker",
"check",
"latest OnionShare version: {}".format(latest_version),
)
except Exception as e:
self.common.log('UpdateChecker', 'check', '{}'.format(e))
self.common.log("UpdateChecker", "check", "{}".format(e))
self.update_error.emit()
raise UpdateCheckerCheckError
@ -140,22 +162,32 @@ class UpdateChecker(QtCore.QObject):
raise UpdateCheckerInvalidLatestVersion(latest_version)
# Update the last checked timestamp (dropping the seconds and milliseconds)
timestamp = datetime.datetime.now().replace(microsecond=0).replace(second=0).timestamp()
timestamp = (
datetime.datetime.now()
.replace(microsecond=0)
.replace(second=0)
.timestamp()
)
# Re-load the settings first before saving, just in case they've changed since we started our thread
settings.load()
settings.set('autoupdate_timestamp', timestamp)
settings.set("autoupdate_timestamp", timestamp)
settings.save()
# Do we need to update?
update_url = 'https://github.com/micahflee/onionshare/releases/tag/v{}'.format(latest_version)
update_url = "https://github.com/micahflee/onionshare/releases/tag/v{}".format(
latest_version
)
installed_version = self.common.version
if installed_version < latest_version:
self.update_available.emit(update_url, installed_version, latest_version)
self.update_available.emit(
update_url, installed_version, latest_version
)
return
# No updates are available
self.update_not_available.emit()
class UpdateThread(QtCore.QThread):
update_available = QtCore.pyqtSignal(str, str, str)
update_not_available = QtCore.pyqtSignal()
@ -167,13 +199,13 @@ class UpdateThread(QtCore.QThread):
self.common = common
self.common.log('UpdateThread', '__init__')
self.common.log("UpdateThread", "__init__")
self.onion = onion
self.config = config
self.force = force
def run(self):
self.common.log('UpdateThread', 'run')
self.common.log("UpdateThread", "run")
u = UpdateChecker(self.common, self.onion, self.config)
u.update_available.connect(self._update_available)
@ -182,28 +214,28 @@ class UpdateThread(QtCore.QThread):
u.update_invalid_version.connect(self._update_invalid_version)
try:
u.check(config=self.config,force=self.force)
u.check(config=self.config, force=self.force)
except Exception as e:
# If update check fails, silently ignore
self.common.log('UpdateThread', 'run', '{}'.format(e))
self.common.log("UpdateThread", "run", "{}".format(e))
pass
def _update_available(self, update_url, installed_version, latest_version):
self.common.log('UpdateThread', '_update_available')
self.common.log("UpdateThread", "_update_available")
self.active = False
self.update_available.emit(update_url, installed_version, latest_version)
def _update_not_available(self):
self.common.log('UpdateThread', '_update_not_available')
self.common.log("UpdateThread", "_update_not_available")
self.active = False
self.update_not_available.emit()
def _update_error(self):
self.common.log('UpdateThread', '_update_error')
self.common.log("UpdateThread", "_update_error")
self.active = False
self.update_error.emit()
def _update_invalid_version(self, latest_version):
self.common.log('UpdateThread', '_update_invalid_version')
self.common.log("UpdateThread", "_update_invalid_version")
self.active = False
self.update_invalid_version.emit(latest_version)

View file

@ -19,19 +19,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from PyQt5 import QtCore, QtWidgets, QtGui
class Alert(QtWidgets.QMessageBox):
"""
An alert box dialog.
"""
def __init__(self, common, message, icon=QtWidgets.QMessageBox.NoIcon, buttons=QtWidgets.QMessageBox.Ok, autostart=True):
def __init__(
self,
common,
message,
icon=QtWidgets.QMessageBox.NoIcon,
buttons=QtWidgets.QMessageBox.Ok,
autostart=True,
):
super(Alert, self).__init__(None)
self.common = common
self.common.log('Alert', '__init__')
self.common.log("Alert", "__init__")
self.setWindowTitle("OnionShare")
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
self.setWindowIcon(
QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
)
self.setText(message)
self.setIcon(icon)
self.setStandardButtons(buttons)
@ -49,11 +60,12 @@ class AddFileDialog(QtWidgets.QFileDialog):
This is because the macOS sandbox requires native dialogs, and this is a Qt5
dialog.
"""
def __init__(self, common, *args, **kwargs):
QtWidgets.QFileDialog.__init__(self, *args, **kwargs)
self.common = common
self.common.log('AddFileDialog', '__init__')
self.common.log("AddFileDialog", "__init__")
self.setOption(self.DontUseNativeDialog, True)
self.setOption(self.ReadOnly, True)
@ -65,5 +77,5 @@ class AddFileDialog(QtWidgets.QFileDialog):
list_view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
def accept(self):
self.common.log('AddFileDialog', 'accept')
self.common.log("AddFileDialog", "accept")
QtWidgets.QDialog.accept(self)