From c77db82e67d828ef2aa34ba31288a3e41b933547 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Sun, 20 Oct 2019 22:08:47 -0700 Subject: [PATCH] Move all of the normal onionshare logic into Tab, and make a new placeholder GUI for the main window --- onionshare_gui/gui_common.py | 4 + onionshare_gui/main_window.py | 551 +---------------- onionshare_gui/settings_dialog.py | 53 +- onionshare_gui/tab/__init__.py | 20 + onionshare_gui/{ => tab}/mode/__init__.py | 0 .../{ => tab}/mode/file_selection.py | 0 onionshare_gui/{ => tab}/mode/history.py | 0 .../{ => tab}/mode/receive_mode/__init__.py | 0 .../{ => tab}/mode/share_mode/__init__.py | 0 .../{ => tab}/mode/share_mode/threads.py | 0 .../{ => tab}/mode/website_mode/__init__.py | 0 onionshare_gui/{ => tab}/server_status.py | 0 onionshare_gui/tab/tab.py | 562 ++++++++++++++++++ onionshare_gui/tor_connection_dialog.py | 18 +- 14 files changed, 634 insertions(+), 574 deletions(-) create mode 100644 onionshare_gui/tab/__init__.py rename onionshare_gui/{ => tab}/mode/__init__.py (100%) rename onionshare_gui/{ => tab}/mode/file_selection.py (100%) rename onionshare_gui/{ => tab}/mode/history.py (100%) rename onionshare_gui/{ => tab}/mode/receive_mode/__init__.py (100%) rename onionshare_gui/{ => tab}/mode/share_mode/__init__.py (100%) rename onionshare_gui/{ => tab}/mode/share_mode/threads.py (100%) rename onionshare_gui/{ => tab}/mode/website_mode/__init__.py (100%) rename onionshare_gui/{ => tab}/server_status.py (100%) create mode 100644 onionshare_gui/tab/tab.py diff --git a/onionshare_gui/gui_common.py b/onionshare_gui/gui_common.py index 940d813b..73951b67 100644 --- a/onionshare_gui/gui_common.py +++ b/onionshare_gui/gui_common.py @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ from onionshare import strings +from onionshare.onion import Onion class GuiCommon: @@ -44,6 +45,9 @@ class GuiCommon: # Load strings strings.load_strings(self.common) + # Start the Onion + self.onion = Onion(common) + self.css = { # OnionShareGui styles "mode_switcher_selected_style": """ diff --git a/onionshare_gui/main_window.py b/onionshare_gui/main_window.py index 1f800000..e3ab5808 100644 --- a/onionshare_gui/main_window.py +++ b/onionshare_gui/main_window.py @@ -23,18 +23,10 @@ from PyQt5 import QtCore, QtWidgets, QtGui from onionshare import strings from onionshare.web import Web -from onionshare.onion import Onion -from onionshare.onionshare import OnionShare - -from .mode.share_mode import ShareMode -from .mode.receive_mode import ReceiveMode -from .mode.website_mode import WebsiteMode - from .tor_connection_dialog import TorConnectionDialog from .settings_dialog import SettingsDialog from .widgets import Alert from .update_checker import UpdateThread -from .server_status import ServerStatus class MainWindow(QtWidgets.QMainWindow): @@ -48,18 +40,9 @@ class MainWindow(QtWidgets.QMainWindow): self.common = common self.common.log("MainWindow", "__init__") - self.mode = self.common.gui.MODE_SHARE - - # Start the Onion - self.onion = Onion(common) - - # Start the OnionShare app - self.app = OnionShare(common, self.onion, self.common.gui.local_only) - # Initialize the window self.setMinimumWidth(820) self.setMinimumHeight(660) - self.setWindowTitle("OnionShare") self.setWindowIcon( QtGui.QIcon(self.common.get_resource_path("images/logo.png")) @@ -88,48 +71,7 @@ class MainWindow(QtWidgets.QMainWindow): 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.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.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.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.clicked.connect(self.open_settings) - self.settings_button.setStyleSheet(self.common.gui.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) - mode_switcher_layout.addWidget(self.website_mode_button) - 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_label = QtWidgets.QLabel() self.server_status_image_label.setFixedWidth(20) self.server_status_label = QtWidgets.QLabel("") @@ -149,300 +91,35 @@ class MainWindow(QtWidgets.QMainWindow): self.status_bar.addPermanentWidget(self.server_status_indicator) self.setStatusBar(self.status_bar) - # Share mode - self.share_mode = ShareMode( - self.common, - self.common.gui.qtapp, - self.app, - self.status_bar, - self.server_status_label, - self.system_tray, - filenames, - self.common.gui.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.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) - self.share_mode.server_status.url_copied.connect(self.copy_url) - self.share_mode.server_status.hidservauth_copied.connect(self.copy_hidservauth) - self.share_mode.set_server_active.connect(self.set_server_active) - - # Receive mode - self.receive_mode = ReceiveMode( - self.common, - self.common.gui.qtapp, - self.app, - self.status_bar, - self.server_status_label, - self.system_tray, - None, - self.common.gui.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.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.set_server_active.connect(self.set_server_active) - - # Website mode - self.website_mode = WebsiteMode( - self.common, - self.common.gui.qtapp, - self.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.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.set_server_active.connect(self.set_server_active) - - self.update_mode_switcher() - self.update_server_status_indicator() - - # Layouts - contents_layout = QtWidgets.QVBoxLayout() - contents_layout.setContentsMargins(10, 0, 10, 0) - contents_layout.addWidget(self.receive_mode) - contents_layout.addWidget(self.share_mode) - contents_layout.addWidget(self.website_mode) + # Placeholder label + label = QtWidgets.QLabel("coming soon...") + # Layout layout = QtWidgets.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) - layout.addLayout(mode_switcher_layout) - layout.addLayout(contents_layout) + layout.addWidget(label) central_widget = QtWidgets.QWidget() central_widget.setLayout(layout) self.setCentralWidget(central_widget) self.show() - # The server isn't active yet - self.set_server_active(False) - - # Create the timer - self.timer = QtCore.QTimer() - self.timer.timeout.connect(self.timer_callback) - # Start the "Connecting to Tor" dialog, which calls onion.connect() - tor_con = TorConnectionDialog(self.common, self.common.gui.qtapp, self.onion) - tor_con.canceled.connect(self._tor_connection_canceled) - tor_con.open_settings.connect(self._tor_connection_open_settings) + tor_con = TorConnectionDialog(self.common) + tor_con.canceled.connect(self.tor_connection_canceled) + tor_con.open_settings.connect(self.tor_connection_open_settings) if not self.common.gui.local_only: tor_con.start() - # Start the timer - self.timer.start(500) - # After connecting to Tor, check for updates self.check_for_updates() - def update_mode_switcher(self): - # Based on the current mode, switch the mode switcher button styles, - # and show and hide widgets to switch modes - if self.mode == self.common.gui.MODE_SHARE: - self.share_mode_button.setStyleSheet( - self.common.gui.css["mode_switcher_selected_style"] - ) - self.receive_mode_button.setStyleSheet( - self.common.gui.css["mode_switcher_unselected_style"] - ) - self.website_mode_button.setStyleSheet( - self.common.gui.css["mode_switcher_unselected_style"] - ) - - self.receive_mode.hide() - self.share_mode.show() - self.website_mode.hide() - elif self.mode == self.common.gui.MODE_WEBSITE: - self.share_mode_button.setStyleSheet( - self.common.gui.css["mode_switcher_unselected_style"] - ) - self.receive_mode_button.setStyleSheet( - self.common.gui.css["mode_switcher_unselected_style"] - ) - self.website_mode_button.setStyleSheet( - self.common.gui.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.gui.css["mode_switcher_unselected_style"] - ) - self.receive_mode_button.setStyleSheet( - self.common.gui.css["mode_switcher_selected_style"] - ) - self.website_mode_button.setStyleSheet( - self.common.gui.css["mode_switcher_unselected_style"] - ) - - self.share_mode.hide() - self.receive_mode.show() - self.website_mode.hide() - - self.update_server_status_indicator() - - def share_mode_clicked(self): - if self.mode != self.common.gui.MODE_SHARE: - self.common.log("MainWindow", "share_mode_clicked") - self.mode = self.common.gui.MODE_SHARE - self.update_mode_switcher() - - def receive_mode_clicked(self): - if self.mode != self.common.gui.MODE_RECEIVE: - self.common.log("MainWindow", "receive_mode_clicked") - self.mode = self.common.gui.MODE_RECEIVE - self.update_mode_switcher() - - def website_mode_clicked(self): - if self.mode != self.common.gui.MODE_WEBSITE: - self.common.log("MainWindow", "website_mode_clicked") - self.mode = self.common.gui.MODE_WEBSITE - self.update_mode_switcher() - - def update_server_status_indicator(self): - # Set the status image - if self.mode == self.common.gui.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") - ) - elif self.share_mode.server_status.status == ServerStatus.STATUS_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") - ) - else: - 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") - ) - elif self.mode == self.common.gui.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") - ) - 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") - ) - 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") - ) - 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") - ) - elif self.receive_mode.server_status.status == ServerStatus.STATUS_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") - ) - else: - 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") - ) - - def stop_server_finished(self): - # When the server stopped, cleanup the ephemeral onion service - self.onion.cleanup(stop_tor=False) - - def _tor_connection_canceled(self): + def tor_connection_canceled(self): """ If the user cancels before Tor finishes connecting, ask if they want to quit, or open settings. """ - self.common.log("MainWindow", "_tor_connection_canceled") + self.common.log("MainWindow", "tor_connection_canceled") def ask(): a = Alert( @@ -484,11 +161,11 @@ class MainWindow(QtWidgets.QMainWindow): # Wait 100ms before asking QtCore.QTimer.singleShot(100, ask) - def _tor_connection_open_settings(self): + def tor_connection_open_settings(self): """ The TorConnectionDialog wants to open the Settings dialog """ - self.common.log("MainWindow", "_tor_connection_open_settings") + self.common.log("MainWindow", "tor_connection_open_settings") # Wait 1ms for the event loop to finish closing the TorConnectionDialog QtCore.QTimer.singleShot(1, self.open_settings) @@ -509,7 +186,7 @@ class MainWindow(QtWidgets.QMainWindow): # If we've reloaded settings, we probably succeeded in obtaining a new # connection. If so, restart the timer. if not self.common.gui.local_only: - if self.onion.is_authenticated(): + if self.common.gui.onion.is_authenticated(): if not self.timer.isActive(): self.timer.start(500) self.share_mode.on_reload_settings() @@ -531,13 +208,7 @@ class MainWindow(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.common.gui.qtapp, - self.common.gui.config, - self.common.gui.local_only, - ) + d = SettingsDialog(self.common) d.settings_saved.connect(reload_settings) d.exec_() @@ -562,203 +233,17 @@ class MainWindow(QtWidgets.QMainWindow): ) self.update_thread = UpdateThread( - self.common, self.onion, self.common.gui.config + self.common, self.common.gui.onion, self.common.gui.config ) self.update_thread.update_available.connect(update_available) self.update_thread.start() - def timer_callback(self): - """ - Check for messages communicated from the web app, and update the GUI accordingly. Also, - call ShareMode and ReceiveMode's timer_callbacks. - """ - self.update() - - if not self.common.gui.local_only: - # 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.share_mode.handle_tor_broke() - self.receive_mode.handle_tor_broke() - self.website_mode.handle_tor_broke() - - # Process events from the web object - if self.mode == self.common.gui.MODE_SHARE: - mode = self.share_mode - elif self.mode == self.common.gui.MODE_WEBSITE: - mode = self.website_mode - else: - mode = self.receive_mode - - events = [] - - done = False - while not done: - try: - r = mode.web.q.get(False) - events.append(r) - except queue.Empty: - done = True - - for event in events: - if event["type"] == Web.REQUEST_LOAD: - mode.handle_request_load(event) - - elif event["type"] == Web.REQUEST_STARTED: - mode.handle_request_started(event) - - elif event["type"] == Web.REQUEST_RATE_LIMIT: - mode.handle_request_rate_limit(event) - - elif event["type"] == Web.REQUEST_PROGRESS: - mode.handle_request_progress(event) - - elif event["type"] == Web.REQUEST_CANCELED: - mode.handle_request_canceled(event) - - elif event["type"] == Web.REQUEST_UPLOAD_FILE_RENAMED: - mode.handle_request_upload_file_renamed(event) - - elif event["type"] == Web.REQUEST_UPLOAD_SET_DIR: - mode.handle_request_upload_set_dir(event) - - elif event["type"] == Web.REQUEST_UPLOAD_FINISHED: - mode.handle_request_upload_finished(event) - - elif event["type"] == Web.REQUEST_UPLOAD_CANCELED: - mode.handle_request_upload_canceled(event) - - elif event["type"] == Web.REQUEST_INDIVIDUAL_FILE_STARTED: - mode.handle_request_individual_file_started(event) - - elif event["type"] == Web.REQUEST_INDIVIDUAL_FILE_PROGRESS: - mode.handle_request_individual_file_progress(event) - - elif event["type"] == Web.REQUEST_INDIVIDUAL_FILE_CANCELED: - 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"] - ), - ) - - if event["type"] == Web.REQUEST_OTHER: - if ( - event["path"] != "/favicon.ico" - and event["path"] != f"/{mode.web.shutdown_password}/shutdown" - ): - self.status_bar.showMessage( - f"{strings._('other_page_loaded')}: {event['path']}" - ) - - if event["type"] == Web.REQUEST_INVALID_PASSWORD: - self.status_bar.showMessage( - f"[#{mode.web.invalid_passwords_count}] {strings._('incorrect_password')}: {event['data']}" - ) - - mode.timer_callback() - - def copy_url(self): - """ - When the URL gets copied to the clipboard, display this in the status bar. - """ - self.common.log("MainWindow", "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("MainWindow", "copy_hidservauth") - self.system_tray.showMessage( - strings._("gui_copied_hidservauth_title"), - strings._("gui_copied_hidservauth"), - ) - - def clear_message(self): - """ - Clear messages from the status bar. - """ - self.status_bar.clearMessage() - - def set_server_active(self, active): - """ - Disable the Settings and Receive Files buttons while an Share Files server is active. - """ - if active: - self.settings_button.hide() - if self.mode == self.common.gui.MODE_SHARE: - self.share_mode_button.show() - self.receive_mode_button.hide() - self.website_mode_button.hide() - elif self.mode == self.common.gui.MODE_WEBSITE: - self.share_mode_button.hide() - self.receive_mode_button.hide() - self.website_mode_button.show() - else: - self.share_mode_button.hide() - self.receive_mode_button.show() - self.website_mode_button.hide() - else: - self.settings_button.show() - self.share_mode_button.show() - self.receive_mode_button.show() - self.website_mode_button.show() - - # Disable settings menu action when server is active - self.settings_action.setEnabled(not active) - def closeEvent(self, e): self.common.log("MainWindow", "closeEvent") self.system_tray.hide() - try: - if self.mode == self.common.gui.MODE_WEBSITE: - server_status = self.share_mode.server_status - if self.mode == self.common.gui.MODE_WEBSITE: - server_status = self.website_mode.server_status - else: - server_status = self.receive_mode.server_status - if server_status.status != server_status.STATUS_STOPPED: - self.common.log("MainWindow", "closeEvent, opening warning dialog") - dialog = QtWidgets.QMessageBox() - dialog.setWindowTitle(strings._("gui_quit_title")) - if self.mode == self.common.gui.MODE_WEBSITE: - dialog.setText(strings._("gui_share_quit_warning")) - else: - 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, - ) - dialog.setDefaultButton(dont_quit_button) - reply = dialog.exec_() - - # Quit - if reply == 0: - self.stop_server() - e.accept() - # Don't Quit - else: - e.ignore() - - except: - e.accept() + # TODO: Run the tab's close_event + e.accept() def cleanup(self): - self.onion.cleanup() - self.app.cleanup() + self.common.gui.onion.cleanup() + # TODO: Run the tab's cleanup diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py index c285b4e6..aaa1fb31 100644 --- a/onionshare_gui/settings_dialog.py +++ b/onionshare_gui/settings_dialog.py @@ -40,18 +40,13 @@ class SettingsDialog(QtWidgets.QDialog): settings_saved = QtCore.pyqtSignal() - def __init__(self, common, onion, qtapp, config=False, local_only=False): + def __init__(self, common): super(SettingsDialog, self).__init__() self.common = common self.common.log("SettingsDialog", "__init__") - self.onion = onion - self.qtapp = qtapp - self.config = config - self.local_only = local_only - self.setModal(True) self.setWindowTitle(strings._("gui_settings_window_title")) self.setWindowIcon( @@ -346,7 +341,7 @@ class SettingsDialog(QtWidgets.QDialog): ) self.check_for_updates_button.clicked.connect(self.check_for_updates) # We can't check for updates if not connected to Tor - if not self.onion.connected_to_tor: + if not self.common.gui.onion.connected_to_tor: self.check_for_updates_button.setEnabled(False) # Autoupdate options layout @@ -721,7 +716,7 @@ class SettingsDialog(QtWidgets.QDialog): def reload_settings(self): # Load settings, and fill them in - self.old_settings = Settings(self.common, self.config) + self.old_settings = Settings(self.common, self.common.gui.config) self.old_settings.load() close_after_first_download = self.old_settings.get("close_after_first_download") @@ -861,12 +856,12 @@ class SettingsDialog(QtWidgets.QDialog): self.tor_bridges_use_custom_textbox.setPlainText(new_bridges) # If we're connected to Tor, show onion service settings, show label if not - if self.onion.is_authenticated(): + if self.common.gui.onion.is_authenticated(): self.connect_to_tor_label.hide() self.onion_settings_widget.show() # If v3 onion services are supported, allow using legacy mode - if self.onion.supports_v3_onions: + if self.common.gui.onion.supports_v3_onions: self.common.log("SettingsDialog", "__init__", "v3 onions are supported") self.use_legacy_v2_onions_checkbox.show() else: @@ -1005,7 +1000,7 @@ class SettingsDialog(QtWidgets.QDialog): "hidservauth_copy_button_clicked", "HidServAuth was copied to clipboard", ) - clipboard = self.qtapp.clipboard() + clipboard = self.common.gui.qtapp.clipboard() clipboard.setText(self.old_settings.get("hidservauth_string")) def use_legacy_v2_onions_checkbox_clicked(self, checked): @@ -1068,7 +1063,7 @@ class SettingsDialog(QtWidgets.QDialog): onion = Onion(self.common) onion.connect( custom_settings=settings, - config=self.config, + config=self.common.gui.config, tor_status_update_func=tor_status_update_func, ) @@ -1110,11 +1105,11 @@ class SettingsDialog(QtWidgets.QDialog): self.common.log("SettingsDialog", "check_for_updates") # Disable buttons self._disable_buttons() - self.qtapp.processEvents() + self.common.gui.qtapp.processEvents() def update_timestamp(): # Update the last checked label - settings = Settings(self.common, self.config) + settings = Settings(self.common, self.common.gui.config) settings.load() autoupdate_timestamp = settings.get("autoupdate_timestamp") self._update_autoupdate_timestamp(autoupdate_timestamp) @@ -1157,7 +1152,7 @@ class SettingsDialog(QtWidgets.QDialog): close_forced_update_thread() forced_update_thread = UpdateThread( - self.common, self.onion, self.config, force=True + self.common, self.onion, self.common.gui.config, force=True ) forced_update_thread.update_available.connect(update_available) forced_update_thread.update_not_available.connect(update_not_available) @@ -1205,8 +1200,8 @@ class SettingsDialog(QtWidgets.QDialog): # If Tor isn't connected, or if Tor settings have changed, Reinitialize # the Onion object reboot_onion = False - if not self.local_only: - if self.onion.is_authenticated(): + if not self.common.gui.local_only: + if self.common.gui.onion.is_authenticated(): self.common.log( "SettingsDialog", "save_clicked", "Connected to Tor" ) @@ -1245,20 +1240,18 @@ class SettingsDialog(QtWidgets.QDialog): self.common.log( "SettingsDialog", "save_clicked", "rebooting the Onion" ) - self.onion.cleanup() + self.common.gui.onion.cleanup() - tor_con = TorConnectionDialog( - self.common, self.qtapp, self.onion, settings - ) + tor_con = TorConnectionDialog(self.common, settings) tor_con.start() self.common.log( "SettingsDialog", "save_clicked", - f"Onion done rebooting, connected to Tor: {self.onion.connected_to_tor}", + f"Onion done rebooting, connected to Tor: {self.common.gui.onion.connected_to_tor}", ) - if self.onion.is_authenticated() and not tor_con.wasCanceled(): + if self.common.gui.onion.is_authenticated() and not tor_con.wasCanceled(): self.settings_saved.emit() self.close() @@ -1274,7 +1267,7 @@ class SettingsDialog(QtWidgets.QDialog): Cancel button clicked. """ self.common.log("SettingsDialog", "cancel_clicked") - if not self.local_only and not self.onion.is_authenticated(): + if not self.common.gui.local_only and not self.common.gui.onion.is_authenticated(): Alert( self.common, strings._("gui_tor_connection_canceled"), @@ -1301,7 +1294,7 @@ class SettingsDialog(QtWidgets.QDialog): Return a Settings object that's full of values from the settings dialog. """ self.common.log("SettingsDialog", "settings_from_fields") - settings = Settings(self.common, self.config) + settings = Settings(self.common, self.common.gui.config) settings.load() # To get the last update timestamp settings.set( @@ -1448,14 +1441,14 @@ class SettingsDialog(QtWidgets.QDialog): self.common.log("SettingsDialog", "closeEvent") # On close, if Tor isn't connected, then quit OnionShare altogether - if not self.local_only: - if not self.onion.is_authenticated(): + if not self.common.gui.local_only: + if not self.common.gui.onion.is_authenticated(): self.common.log( "SettingsDialog", "closeEvent", "Closing while not connected to Tor" ) # Wait 1ms for the event loop to finish, then quit - QtCore.QTimer.singleShot(1, self.qtapp.quit) + QtCore.QTimer.singleShot(1, self.common.gui.qtapp.quit) def _update_autoupdate_timestamp(self, autoupdate_timestamp): self.common.log("SettingsDialog", "_update_autoupdate_timestamp") @@ -1473,7 +1466,7 @@ class SettingsDialog(QtWidgets.QDialog): self.tor_status.setText( f"{strings._('connecting_to_tor')}
{progress}% {summary}" ) - self.qtapp.processEvents() + self.common.gui.qtapp.processEvents() if "Done" in summary: self.tor_status.hide() self._enable_buttons() @@ -1489,7 +1482,7 @@ class SettingsDialog(QtWidgets.QDialog): def _enable_buttons(self): self.common.log("SettingsDialog", "_enable_buttons") # We can't check for updates if we're still not connected to Tor - if not self.onion.connected_to_tor: + if not self.common.gui.onion.connected_to_tor: self.check_for_updates_button.setEnabled(False) else: self.check_for_updates_button.setEnabled(True) diff --git a/onionshare_gui/tab/__init__.py b/onionshare_gui/tab/__init__.py new file mode 100644 index 00000000..ca346a7d --- /dev/null +++ b/onionshare_gui/tab/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +""" +OnionShare | https://onionshare.org/ + +Copyright (C) 2014-2018 Micah Lee + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" +from .tab import Tab diff --git a/onionshare_gui/mode/__init__.py b/onionshare_gui/tab/mode/__init__.py similarity index 100% rename from onionshare_gui/mode/__init__.py rename to onionshare_gui/tab/mode/__init__.py diff --git a/onionshare_gui/mode/file_selection.py b/onionshare_gui/tab/mode/file_selection.py similarity index 100% rename from onionshare_gui/mode/file_selection.py rename to onionshare_gui/tab/mode/file_selection.py diff --git a/onionshare_gui/mode/history.py b/onionshare_gui/tab/mode/history.py similarity index 100% rename from onionshare_gui/mode/history.py rename to onionshare_gui/tab/mode/history.py diff --git a/onionshare_gui/mode/receive_mode/__init__.py b/onionshare_gui/tab/mode/receive_mode/__init__.py similarity index 100% rename from onionshare_gui/mode/receive_mode/__init__.py rename to onionshare_gui/tab/mode/receive_mode/__init__.py diff --git a/onionshare_gui/mode/share_mode/__init__.py b/onionshare_gui/tab/mode/share_mode/__init__.py similarity index 100% rename from onionshare_gui/mode/share_mode/__init__.py rename to onionshare_gui/tab/mode/share_mode/__init__.py diff --git a/onionshare_gui/mode/share_mode/threads.py b/onionshare_gui/tab/mode/share_mode/threads.py similarity index 100% rename from onionshare_gui/mode/share_mode/threads.py rename to onionshare_gui/tab/mode/share_mode/threads.py diff --git a/onionshare_gui/mode/website_mode/__init__.py b/onionshare_gui/tab/mode/website_mode/__init__.py similarity index 100% rename from onionshare_gui/mode/website_mode/__init__.py rename to onionshare_gui/tab/mode/website_mode/__init__.py diff --git a/onionshare_gui/server_status.py b/onionshare_gui/tab/server_status.py similarity index 100% rename from onionshare_gui/server_status.py rename to onionshare_gui/tab/server_status.py diff --git a/onionshare_gui/tab/tab.py b/onionshare_gui/tab/tab.py new file mode 100644 index 00000000..a921fe98 --- /dev/null +++ b/onionshare_gui/tab/tab.py @@ -0,0 +1,562 @@ +# -*- coding: utf-8 -*- +""" +OnionShare | https://onionshare.org/ + +Copyright (C) 2014-2018 Micah Lee + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" +from PyQt5 import QtCore, QtWidgets, QtGui + +from onionshare import strings +from onionshare.onionshare import OnionShare +from onionshare.web import Web + +from .mode.share_mode import ShareMode +from .mode.receive_mode import ReceiveMode +from .mode.website_mode import WebsiteMode + +from .server_status import ServerStatus + +from ..widgets import Alert + + +class Tab(QtWidgets.QWidget): + """ + A GUI tab, you know, sort of like in a web browser + """ + + def __init__(self, common, system_tray, status_bar, filenames): + super(Tab, self).__init__() + self.common = common + self.common.log("Tab", "__init__") + + self.system_tray = system_tray + self.status_bar = status_bar + + self.mode = self.common.gui.MODE_SHARE + + # Start the OnionShare app + self.app = OnionShare(common, self.common.gui.onion, self.common.gui.local_only) + + # 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.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.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.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.clicked.connect(self.open_settings) + self.settings_button.setStyleSheet(self.common.gui.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) + mode_switcher_layout.addWidget(self.website_mode_button) + mode_switcher_layout.addWidget(self.settings_button) + + # Server status indicator icons + 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") + ) + + # Share mode + self.share_mode = ShareMode( + self.common, + self.common.gui.qtapp, + self.app, + self.status_bar, + self.server_status_label, + self.system_tray, + filenames, + self.common.gui.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.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) + self.share_mode.server_status.url_copied.connect(self.copy_url) + self.share_mode.server_status.hidservauth_copied.connect(self.copy_hidservauth) + self.share_mode.set_server_active.connect(self.set_server_active) + + # Receive mode + self.receive_mode = ReceiveMode( + self.common, + self.common.gui.qtapp, + self.app, + self.status_bar, + self.server_status_label, + self.system_tray, + None, + self.common.gui.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.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.set_server_active.connect(self.set_server_active) + + # Website mode + self.website_mode = WebsiteMode( + self.common, + self.common.gui.qtapp, + self.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.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.set_server_active.connect(self.set_server_active) + + self.update_mode_switcher() + self.update_server_status_indicator() + + # Layouts + contents_layout = QtWidgets.QVBoxLayout() + contents_layout.setContentsMargins(10, 0, 10, 0) + contents_layout.addWidget(self.receive_mode) + contents_layout.addWidget(self.share_mode) + contents_layout.addWidget(self.website_mode) + + layout = QtWidgets.QVBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) + layout.addLayout(mode_switcher_layout) + layout.addLayout(contents_layout) + self.setLayout(layout) + + # The server isn't active yet + self.set_server_active(False) + + # Create the timer + self.timer = QtCore.QTimer() + self.timer.timeout.connect(self.timer_callback) + + # Start the timer + self.timer.start(500) + + def update_mode_switcher(self): + # Based on the current mode, switch the mode switcher button styles, + # and show and hide widgets to switch modes + if self.mode == self.common.gui.MODE_SHARE: + self.share_mode_button.setStyleSheet( + self.common.gui.css["mode_switcher_selected_style"] + ) + self.receive_mode_button.setStyleSheet( + self.common.gui.css["mode_switcher_unselected_style"] + ) + self.website_mode_button.setStyleSheet( + self.common.gui.css["mode_switcher_unselected_style"] + ) + + self.receive_mode.hide() + self.share_mode.show() + self.website_mode.hide() + elif self.mode == self.common.gui.MODE_WEBSITE: + self.share_mode_button.setStyleSheet( + self.common.gui.css["mode_switcher_unselected_style"] + ) + self.receive_mode_button.setStyleSheet( + self.common.gui.css["mode_switcher_unselected_style"] + ) + self.website_mode_button.setStyleSheet( + self.common.gui.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.gui.css["mode_switcher_unselected_style"] + ) + self.receive_mode_button.setStyleSheet( + self.common.gui.css["mode_switcher_selected_style"] + ) + self.website_mode_button.setStyleSheet( + self.common.gui.css["mode_switcher_unselected_style"] + ) + + self.share_mode.hide() + self.receive_mode.show() + self.website_mode.hide() + + self.update_server_status_indicator() + + def share_mode_clicked(self): + if self.mode != self.common.gui.MODE_SHARE: + self.common.log("Tab", "share_mode_clicked") + self.mode = self.common.gui.MODE_SHARE + self.update_mode_switcher() + + def receive_mode_clicked(self): + if self.mode != self.common.gui.MODE_RECEIVE: + self.common.log("Tab", "receive_mode_clicked") + self.mode = self.common.gui.MODE_RECEIVE + self.update_mode_switcher() + + def website_mode_clicked(self): + if self.mode != self.common.gui.MODE_WEBSITE: + self.common.log("Tab", "website_mode_clicked") + self.mode = self.common.gui.MODE_WEBSITE + self.update_mode_switcher() + + def update_server_status_indicator(self): + # Set the status image + if self.mode == self.common.gui.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") + ) + elif self.share_mode.server_status.status == ServerStatus.STATUS_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") + ) + else: + 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") + ) + elif self.mode == self.common.gui.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") + ) + 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") + ) + 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") + ) + 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") + ) + elif self.receive_mode.server_status.status == ServerStatus.STATUS_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") + ) + else: + 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") + ) + + def stop_server_finished(self): + # When the server stopped, cleanup the ephemeral onion service + self.common.gui.onion.cleanup(stop_tor=False) + + def timer_callback(self): + """ + Check for messages communicated from the web app, and update the GUI accordingly. Also, + call ShareMode and ReceiveMode's timer_callbacks. + """ + self.update() + + if not self.common.gui.local_only: + # Have we lost connection to Tor somehow? + if not self.common.gui.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.share_mode.handle_tor_broke() + self.receive_mode.handle_tor_broke() + self.website_mode.handle_tor_broke() + + # Process events from the web object + if self.mode == self.common.gui.MODE_SHARE: + mode = self.share_mode + elif self.mode == self.common.gui.MODE_WEBSITE: + mode = self.website_mode + else: + mode = self.receive_mode + + events = [] + + done = False + while not done: + try: + r = mode.web.q.get(False) + events.append(r) + except queue.Empty: + done = True + + for event in events: + if event["type"] == Web.REQUEST_LOAD: + mode.handle_request_load(event) + + elif event["type"] == Web.REQUEST_STARTED: + mode.handle_request_started(event) + + elif event["type"] == Web.REQUEST_RATE_LIMIT: + mode.handle_request_rate_limit(event) + + elif event["type"] == Web.REQUEST_PROGRESS: + mode.handle_request_progress(event) + + elif event["type"] == Web.REQUEST_CANCELED: + mode.handle_request_canceled(event) + + elif event["type"] == Web.REQUEST_UPLOAD_FILE_RENAMED: + mode.handle_request_upload_file_renamed(event) + + elif event["type"] == Web.REQUEST_UPLOAD_SET_DIR: + mode.handle_request_upload_set_dir(event) + + elif event["type"] == Web.REQUEST_UPLOAD_FINISHED: + mode.handle_request_upload_finished(event) + + elif event["type"] == Web.REQUEST_UPLOAD_CANCELED: + mode.handle_request_upload_canceled(event) + + elif event["type"] == Web.REQUEST_INDIVIDUAL_FILE_STARTED: + mode.handle_request_individual_file_started(event) + + elif event["type"] == Web.REQUEST_INDIVIDUAL_FILE_PROGRESS: + mode.handle_request_individual_file_progress(event) + + elif event["type"] == Web.REQUEST_INDIVIDUAL_FILE_CANCELED: + 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"] + ), + ) + + if event["type"] == Web.REQUEST_OTHER: + if ( + event["path"] != "/favicon.ico" + and event["path"] != f"/{mode.web.shutdown_password}/shutdown" + ): + self.status_bar.showMessage( + f"{strings._('other_page_loaded')}: {event['path']}" + ) + + if event["type"] == Web.REQUEST_INVALID_PASSWORD: + self.status_bar.showMessage( + f"[#{mode.web.invalid_passwords_count}] {strings._('incorrect_password')}: {event['data']}" + ) + + mode.timer_callback() + + def copy_url(self): + """ + When the URL gets copied to the clipboard, display this in the status bar. + """ + self.common.log("Tab", "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("Tab", "copy_hidservauth") + self.system_tray.showMessage( + strings._("gui_copied_hidservauth_title"), + strings._("gui_copied_hidservauth"), + ) + + def set_server_active(self, active): + """ + Disable the Settings and Receive Files buttons while an Share Files server is active. + """ + if active: + self.settings_button.hide() + if self.mode == self.common.gui.MODE_SHARE: + self.share_mode_button.show() + self.receive_mode_button.hide() + self.website_mode_button.hide() + elif self.mode == self.common.gui.MODE_WEBSITE: + self.share_mode_button.hide() + self.receive_mode_button.hide() + self.website_mode_button.show() + else: + self.share_mode_button.hide() + self.receive_mode_button.show() + self.website_mode_button.hide() + else: + self.settings_button.show() + self.share_mode_button.show() + self.receive_mode_button.show() + self.website_mode_button.show() + + # Disable settings menu action when server is active + self.settings_action.setEnabled(not active) + + def clear_message(self): + """ + Clear messages from the status bar. + """ + self.status_bar.clearMessage() + + def close_event(self, e): + self.common.log("Tab", "close_event") + try: + if self.mode == self.common.gui.MODE_WEBSITE: + server_status = self.share_mode.server_status + if self.mode == self.common.gui.MODE_WEBSITE: + server_status = self.website_mode.server_status + else: + server_status = self.receive_mode.server_status + if server_status.status != server_status.STATUS_STOPPED: + self.common.log("MainWindow", "closeEvent, opening warning dialog") + dialog = QtWidgets.QMessageBox() + dialog.setWindowTitle(strings._("gui_quit_title")) + if self.mode == self.common.gui.MODE_WEBSITE: + dialog.setText(strings._("gui_share_quit_warning")) + else: + 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, + ) + dialog.setDefaultButton(dont_quit_button) + reply = dialog.exec_() + + # Quit + if reply == 0: + self.stop_server() + e.accept() + # Don't Quit + else: + e.ignore() + + except: + e.accept() + + def cleanup(self): + self.app.cleanup() diff --git a/onionshare_gui/tor_connection_dialog.py b/onionshare_gui/tor_connection_dialog.py index 95e61eb3..37c0ebc3 100644 --- a/onionshare_gui/tor_connection_dialog.py +++ b/onionshare_gui/tor_connection_dialog.py @@ -32,7 +32,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog): open_settings = QtCore.pyqtSignal() - def __init__(self, common, qtapp, onion, custom_settings=False): + def __init__(self, common, custom_settings=False): super(TorConnectionDialog, self).__init__(None) self.common = common @@ -44,9 +44,6 @@ class TorConnectionDialog(QtWidgets.QProgressDialog): 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")) @@ -68,7 +65,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog): def start(self): self.common.log("TorConnectionDialog", "start") - t = TorConnectionThread(self.common, self.settings, self, self.onion) + t = TorConnectionThread(self.common, self.settings, self) t.tor_status_update.connect(self._tor_status_update) t.connected_to_tor.connect(self._connected_to_tor) t.canceled_connecting_to_tor.connect(self._canceled_connecting_to_tor) @@ -81,7 +78,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog): self.active = True while self.active: time.sleep(0.1) - self.qtapp.processEvents() + self.common.gui.qtapp.processEvents() def _tor_status_update(self, progress, summary): self.setValue(int(progress)) @@ -99,7 +96,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog): def _canceled_connecting_to_tor(self): self.common.log("TorConnectionDialog", "_canceled_connecting_to_tor") self.active = False - self.onion.cleanup() + self.common.gui.onion.cleanup() # Cancel connecting to Tor QtCore.QTimer.singleShot(1, self.cancel) @@ -131,7 +128,7 @@ class TorConnectionThread(QtCore.QThread): canceled_connecting_to_tor = QtCore.pyqtSignal() error_connecting_to_tor = QtCore.pyqtSignal(str) - def __init__(self, common, settings, dialog, onion): + def __init__(self, common, settings, dialog): super(TorConnectionThread, self).__init__() self.common = common @@ -141,15 +138,14 @@ class TorConnectionThread(QtCore.QThread): self.settings = settings self.dialog = dialog - self.onion = onion def run(self): self.common.log("TorConnectionThread", "run") # Connect to the Onion try: - self.onion.connect(self.settings, False, self._tor_status_update) - if self.onion.connected_to_tor: + self.common.gui.onion.connect(self.settings, False, self._tor_status_update) + if self.common.gui.onion.connected_to_tor: self.connected_to_tor.emit() else: self.canceled_connecting_to_tor.emit()