diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py index 39b75449..53858eeb 100644 --- a/onionshare_gui/onionshare_gui.py +++ b/onionshare_gui/onionshare_gui.py @@ -125,95 +125,6 @@ class OnionShareGui(QtWidgets.QMainWindow): self.update_mode_switcher() - # File selection - self.file_selection = FileSelection(self.common) - if filenames: - for filename in filenames: - self.file_selection.file_list.add_file(filename) - - # Server status - self.server_status = ServerStatus(self.common, self.qtapp, self.app, self.web, self.file_selection) - self.server_status.server_started.connect(self.file_selection.server_started) - self.server_status.server_started.connect(self.start_server) - self.server_status.server_started.connect(self.update_server_status_indicator) - self.server_status.server_stopped.connect(self.file_selection.server_stopped) - self.server_status.server_stopped.connect(self.stop_server) - self.server_status.server_stopped.connect(self.update_server_status_indicator) - self.server_status.server_stopped.connect(self.update_primary_action) - self.server_status.server_canceled.connect(self.cancel_server) - self.server_status.server_canceled.connect(self.file_selection.server_stopped) - self.server_status.server_canceled.connect(self.update_primary_action) - self.start_server_finished.connect(self.clear_message) - self.start_server_finished.connect(self.server_status.start_server_finished) - self.start_server_finished.connect(self.update_server_status_indicator) - self.stop_server_finished.connect(self.server_status.stop_server_finished) - self.stop_server_finished.connect(self.update_server_status_indicator) - self.file_selection.file_list.files_updated.connect(self.server_status.update) - self.file_selection.file_list.files_updated.connect(self.update_primary_action) - self.server_status.url_copied.connect(self.copy_url) - self.server_status.hidservauth_copied.connect(self.copy_hidservauth) - self.starting_server_step2.connect(self.start_server_step2) - self.starting_server_step3.connect(self.start_server_step3) - self.starting_server_error.connect(self.start_server_error) - self.server_status.button_clicked.connect(self.clear_message) - - # Filesize warning - self.filesize_warning = QtWidgets.QLabel() - self.filesize_warning.setWordWrap(True) - self.filesize_warning.setStyleSheet('padding: 10px 0; font-weight: bold; color: #333333;') - self.filesize_warning.hide() - - # Downloads - self.downloads = Downloads(self.common) - self.new_download = False - self.downloads_in_progress = 0 - self.downloads_completed = 0 - - # Info label along top of screen - self.info_layout = QtWidgets.QHBoxLayout() - self.info_label = QtWidgets.QLabel() - self.info_label.setStyleSheet('QLabel { font-size: 12px; color: #666666; }') - - self.info_show_downloads = QtWidgets.QToolButton() - self.info_show_downloads.setIcon(QtGui.QIcon(self.common.get_resource_path('images/download_window_gray.png'))) - self.info_show_downloads.setCheckable(True) - self.info_show_downloads.toggled.connect(self.downloads_toggled) - self.info_show_downloads.setToolTip(strings._('gui_downloads_window_tooltip', True)) - - self.info_in_progress_downloads_count = QtWidgets.QLabel() - self.info_in_progress_downloads_count.setStyleSheet('QLabel { font-size: 12px; color: #666666; }') - - self.info_completed_downloads_count = QtWidgets.QLabel() - self.info_completed_downloads_count.setStyleSheet('QLabel { font-size: 12px; color: #666666; }') - - self.update_downloads_completed(self.downloads_in_progress) - self.update_downloads_in_progress(self.downloads_in_progress) - - self.info_layout.addWidget(self.info_label) - self.info_layout.addStretch() - self.info_layout.addWidget(self.info_in_progress_downloads_count) - self.info_layout.addWidget(self.info_completed_downloads_count) - self.info_layout.addWidget(self.info_show_downloads) - - self.info_widget = QtWidgets.QWidget() - self.info_widget.setLayout(self.info_layout) - self.info_widget.hide() - - # 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() - self.server_status_label.setStyleSheet('QLabel { font-style: italic; color: #666666; }') - 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) - self.server_status_indicator = QtWidgets.QWidget() - self.server_status_indicator.setLayout(server_status_indicator_layout) - self.update_server_status_indicator() - # Status bar self.status_bar = QtWidgets.QStatusBar() self.status_bar.setSizeGripEnabled(False) @@ -236,24 +147,11 @@ class OnionShareGui(QtWidgets.QMainWindow): self.server_share_status_label.setStyleSheet('QLabel { font-style: italic; color: #666666; padding: 2px; }') self.status_bar.insertWidget(0, self.server_share_status_label) - # Primary action layout - primary_action_layout = QtWidgets.QVBoxLayout() - primary_action_layout.addWidget(self.server_status) - primary_action_layout.addWidget(self.filesize_warning) - self.primary_action = QtWidgets.QWidget() - self.primary_action.setLayout(primary_action_layout) - self.primary_action.hide() - self.update_primary_action() - # Layouts contents_layout = QtWidgets.QVBoxLayout() contents_layout.setContentsMargins(10, 10, 10, 10) contents_layout.addWidget(self.receive_mode) contents_layout.addWidget(self.share_mode) - # TODO: move these into ShareMode - contents_layout.addWidget(self.info_widget) - contents_layout.addLayout(self.file_selection) - contents_layout.addWidget(self.primary_action) layout = QtWidgets.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) @@ -265,9 +163,6 @@ class OnionShareGui(QtWidgets.QMainWindow): self.setCentralWidget(central_widget) self.show() - # Always start with focus on file selection - self.file_selection.setFocus() - # The server isn't active yet self.set_server_active(False) @@ -314,46 +209,6 @@ class OnionShareGui(QtWidgets.QMainWindow): self.mode = self.MODE_RECEIVE self.update_mode_switcher() - def update_primary_action(self): - # Show or hide primary action layout - file_count = self.file_selection.file_list.count() - if file_count > 0: - self.primary_action.show() - self.info_widget.show() - - # Update the file count in the info label - total_size_bytes = 0 - for index in range(self.file_selection.file_list.count()): - item = self.file_selection.file_list.item(index) - total_size_bytes += item.size_bytes - total_size_readable = self.common.human_readable_filesize(total_size_bytes) - - if file_count > 1: - self.info_label.setText(strings._('gui_file_info', True).format(file_count, total_size_readable)) - else: - self.info_label.setText(strings._('gui_file_info_single', True).format(file_count, total_size_readable)) - - else: - self.primary_action.hide() - self.info_widget.hide() - - # Resize window - self.adjustSize() - - def update_server_status_indicator(self): - self.common.log('OnionShareGui', 'update_server_status_indicator') - - # Set the status image - if self.server_status.status == self.server_status.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_stopped', True)) - elif self.server_status.status == self.server_status.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_working', True)) - elif self.server_status.status == self.server_status.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_started', True)) - def _initSystemTray(self): menu = QtWidgets.QMenu() self.settingsAction = menu.addAction(strings._('gui_settings_window_title', True)) @@ -445,165 +300,6 @@ class OnionShareGui(QtWidgets.QMainWindow): # When settings close, refresh the server status UI self.server_status.update() - def start_server(self): - """ - Start the onionshare server. This uses multiple threads to start the Tor onion - server and the web app. - """ - self.common.log('OnionShareGui', 'start_server') - - self.set_server_active(True) - - self.app.set_stealth(self.common.settings.get('use_stealth')) - - # Hide and reset the downloads if we have previously shared - self.downloads.reset_downloads() - self.reset_info_counters() - self.status_bar.clearMessage() - self.server_share_status_label.setText('') - - # Reset web counters - self.web.download_count = 0 - self.web.error404_count = 0 - - # start the onion service in a new thread - def start_onion_service(self): - try: - self.app.start_onion_service() - self.starting_server_step2.emit() - - except (TorTooOld, TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorTimeout, OSError) as e: - self.starting_server_error.emit(e.args[0]) - return - - - self.app.stay_open = not self.common.settings.get('close_after_first_download') - - # start onionshare http service in new thread - t = threading.Thread(target=self.web.start, args=(self.app.port, self.app.stay_open, self.common.settings.get('slug'))) - t.daemon = True - t.start() - # wait for modules in thread to load, preventing a thread-related cx_Freeze crash - time.sleep(0.2) - - self.common.log('OnionshareGui', 'start_server', 'Starting an onion thread') - self.t = OnionThread(self.common, function=start_onion_service, kwargs={'self': self}) - self.t.daemon = True - self.t.start() - - def start_server_step2(self): - """ - Step 2 in starting the onionshare server. Zipping up files. - """ - self.common.log('OnionShareGui', 'start_server_step2') - - # add progress bar to the status bar, indicating the compressing of files. - self._zip_progress_bar = ZipProgressBar(0) - self.filenames = [] - 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 = OnionShareGui._compute_total_size(self.filenames) - self.status_bar.insertWidget(0, self._zip_progress_bar) - - # prepare the files for sending in a new thread - def finish_starting_server(self): - # prepare files to share - def _set_processed_size(x): - if self._zip_progress_bar != None: - self._zip_progress_bar.update_processed_size_signal.emit(x) - try: - self.web.set_file_info(self.filenames, processed_size_callback=_set_processed_size) - self.app.cleanup_filenames.append(self.web.zip_filename) - self.starting_server_step3.emit() - - # done - self.start_server_finished.emit() - except OSError as e: - self.starting_server_error.emit(e.strerror) - return - - t = threading.Thread(target=finish_starting_server, kwargs={'self': self}) - t.daemon = True - t.start() - - def start_server_step3(self): - """ - Step 3 in starting the onionshare server. This displays the large filesize - warning, if applicable. - """ - self.common.log('OnionShareGui', 'start_server_step3') - - # Remove zip progress bar - if self._zip_progress_bar is not None: - self.status_bar.removeWidget(self._zip_progress_bar) - self._zip_progress_bar = None - - # warn about sending large files over Tor - if self.web.zip_filesize >= 157286400: # 150mb - self.filesize_warning.setText(strings._("large_filesize", True)) - self.filesize_warning.show() - - if self.common.settings.get('shutdown_timeout'): - # Convert the date value to seconds between now and then - now = QtCore.QDateTime.currentDateTime() - self.timeout = now.secsTo(self.server_status.timeout) - # Set the shutdown timeout value - if self.timeout > 0: - self.app.shutdown_timer = ShutdownTimer(self.common, self.timeout) - self.app.shutdown_timer.start() - # The timeout 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_timeout')) - - def start_server_error(self, error): - """ - If there's an error when trying to start the onion service - """ - self.common.log('OnionShareGui', 'start_server_error') - - self.set_server_active(False) - - Alert(self.common, error, QtWidgets.QMessageBox.Warning) - self.server_status.stop_server() - if self._zip_progress_bar is not None: - self.status_bar.removeWidget(self._zip_progress_bar) - self._zip_progress_bar = None - self.status_bar.clearMessage() - - def cancel_server(self): - """ - Cancel the server while it is preparing to start - """ - if self.t: - self.t.quit() - self.stop_server() - - def stop_server(self): - """ - Stop the onionshare server. - """ - self.common.log('OnionShareGui', 'stop_server') - - if self.server_status.status != self.server_status.STATUS_STOPPED: - try: - self.web.stop(self.app.port) - except: - # Probably we had no port to begin with (Onion service didn't start) - pass - self.app.cleanup() - # Remove ephemeral service, but don't disconnect from Tor - self.onion.cleanup(stop_tor=False) - self.filesize_warning.hide() - self.downloads_in_progress = 0 - self.downloads_completed = 0 - self.update_downloads_in_progress(0) - self.file_selection.file_list.adjustSize() - - self.set_server_active(False) - self.stop_server_finished.emit() - def check_for_updates(self): """ Check for updates in a new thread, if enabled. @@ -617,16 +313,6 @@ class OnionShareGui(QtWidgets.QMainWindow): self.update_thread.update_available.connect(update_available) self.update_thread.start() - @staticmethod - def _compute_total_size(filenames): - total_size = 0 - for filename in filenames: - if os.path.isfile(filename): - total_size += os.path.getsize(filename) - if os.path.isdir(filename): - total_size += Common.dir_size(filename) - return total_size - def check_for_requests(self): """ Check for messages communicated from the web app, and update the GUI accordingly. @@ -733,16 +419,6 @@ class OnionShareGui(QtWidgets.QMainWindow): self.status_bar.clearMessage() self.server_share_status_label.setText(strings._('timeout_download_still_running', True)) - def downloads_toggled(self, checked): - """ - When the 'Show/hide downloads' button is toggled, show or hide the downloads window. - """ - self.common.log('OnionShareGui', 'toggle_downloads') - if checked: - self.downloads.downloads_container.show() - else: - self.downloads.downloads_container.hide() - def copy_url(self): """ When the URL gets copied to the clipboard, display this in the status bar. @@ -777,39 +453,6 @@ class OnionShareGui(QtWidgets.QMainWindow): # Disable settings menu action when server is active self.settingsAction.setEnabled(not active) - def reset_info_counters(self): - """ - Set the info counters back to zero. - """ - self.update_downloads_completed(0) - self.update_downloads_in_progress(0) - self.info_show_downloads.setIcon(QtGui.QIcon(self.common.get_resource_path('images/download_window_gray.png'))) - self.downloads.no_downloads_label.show() - self.downloads.downloads_container.resize(self.downloads.downloads_container.sizeHint()) - - def update_downloads_completed(self, count): - """ - Update the 'Downloads completed' info widget. - """ - if count == 0: - self.info_completed_downloads_image = self.common.get_resource_path('images/download_completed_none.png') - else: - self.info_completed_downloads_image = self.common.get_resource_path('images/download_completed.png') - self.info_completed_downloads_count.setText(' {1:d}'.format(self.info_completed_downloads_image, count)) - self.info_completed_downloads_count.setToolTip(strings._('info_completed_downloads_tooltip', True).format(count)) - - def update_downloads_in_progress(self, count): - """ - Update the 'Downloads in progress' info widget. - """ - if count == 0: - self.info_in_progress_downloads_image = self.common.get_resource_path('images/download_in_progress_none.png') - else: - self.info_in_progress_downloads_image = self.common.get_resource_path('images/download_in_progress.png') - self.info_show_downloads.setIcon(QtGui.QIcon(self.common.get_resource_path('images/download_window_green.png'))) - self.info_in_progress_downloads_count.setText(' {1:d}'.format(self.info_in_progress_downloads_image, count)) - self.info_in_progress_downloads_count.setToolTip(strings._('info_in_progress_downloads_tooltip', True).format(count)) - def closeEvent(self, e): self.common.log('OnionShareGui', 'closeEvent') try: diff --git a/onionshare_gui/share_mode.py b/onionshare_gui/share_mode.py index 81dd62d5..b6aa02c9 100644 --- a/onionshare_gui/share_mode.py +++ b/onionshare_gui/share_mode.py @@ -20,6 +20,7 @@ along with this program. If not, see . from PyQt5 import QtCore, QtWidgets, QtGui from onionshare import strings +from .mode import Mode class ShareMode(QtWidgets.QWidget): """ @@ -28,3 +29,363 @@ class ShareMode(QtWidgets.QWidget): def __init__(self, common): super(ShareMode, self).__init__() self.common = common + + # File selection + self.file_selection = FileSelection(self.common) + if filenames: + for filename in filenames: + self.file_selection.file_list.add_file(filename) + + # Server status + self.server_status = ServerStatus(self.common, self.qtapp, self.app, self.web, self.file_selection) + self.server_status.server_started.connect(self.file_selection.server_started) + self.server_status.server_started.connect(self.start_server) + self.server_status.server_started.connect(self.update_server_status_indicator) + self.server_status.server_stopped.connect(self.file_selection.server_stopped) + self.server_status.server_stopped.connect(self.stop_server) + self.server_status.server_stopped.connect(self.update_server_status_indicator) + self.server_status.server_stopped.connect(self.update_primary_action) + self.server_status.server_canceled.connect(self.cancel_server) + self.server_status.server_canceled.connect(self.file_selection.server_stopped) + self.server_status.server_canceled.connect(self.update_primary_action) + self.start_server_finished.connect(self.clear_message) + self.start_server_finished.connect(self.server_status.start_server_finished) + self.start_server_finished.connect(self.update_server_status_indicator) + self.stop_server_finished.connect(self.server_status.stop_server_finished) + self.stop_server_finished.connect(self.update_server_status_indicator) + self.file_selection.file_list.files_updated.connect(self.server_status.update) + self.file_selection.file_list.files_updated.connect(self.update_primary_action) + self.server_status.url_copied.connect(self.copy_url) + self.server_status.hidservauth_copied.connect(self.copy_hidservauth) + self.starting_server_step2.connect(self.start_server_step2) + self.starting_server_step3.connect(self.start_server_step3) + self.starting_server_error.connect(self.start_server_error) + self.server_status.button_clicked.connect(self.clear_message) + + # Filesize warning + self.filesize_warning = QtWidgets.QLabel() + self.filesize_warning.setWordWrap(True) + self.filesize_warning.setStyleSheet('padding: 10px 0; font-weight: bold; color: #333333;') + self.filesize_warning.hide() + + # Downloads + self.downloads = Downloads(self.common) + self.new_download = False + self.downloads_in_progress = 0 + self.downloads_completed = 0 + + # Info label along top of screen + self.info_layout = QtWidgets.QHBoxLayout() + self.info_label = QtWidgets.QLabel() + self.info_label.setStyleSheet('QLabel { font-size: 12px; color: #666666; }') + + self.info_show_downloads = QtWidgets.QToolButton() + self.info_show_downloads.setIcon(QtGui.QIcon(self.common.get_resource_path('images/download_window_gray.png'))) + self.info_show_downloads.setCheckable(True) + self.info_show_downloads.toggled.connect(self.downloads_toggled) + self.info_show_downloads.setToolTip(strings._('gui_downloads_window_tooltip', True)) + + self.info_in_progress_downloads_count = QtWidgets.QLabel() + self.info_in_progress_downloads_count.setStyleSheet('QLabel { font-size: 12px; color: #666666; }') + + self.info_completed_downloads_count = QtWidgets.QLabel() + self.info_completed_downloads_count.setStyleSheet('QLabel { font-size: 12px; color: #666666; }') + + self.update_downloads_completed(self.downloads_in_progress) + self.update_downloads_in_progress(self.downloads_in_progress) + + self.info_layout.addWidget(self.info_label) + self.info_layout.addStretch() + self.info_layout.addWidget(self.info_in_progress_downloads_count) + self.info_layout.addWidget(self.info_completed_downloads_count) + self.info_layout.addWidget(self.info_show_downloads) + + self.info_widget = QtWidgets.QWidget() + self.info_widget.setLayout(self.info_layout) + self.info_widget.hide() + + # 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() + self.server_status_label.setStyleSheet('QLabel { font-style: italic; color: #666666; }') + 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) + self.server_status_indicator = QtWidgets.QWidget() + self.server_status_indicator.setLayout(server_status_indicator_layout) + self.update_server_status_indicator() + + # Primary action layout + primary_action_layout = QtWidgets.QVBoxLayout() + primary_action_layout.addWidget(self.server_status) + primary_action_layout.addWidget(self.filesize_warning) + self.primary_action = QtWidgets.QWidget() + self.primary_action.setLayout(primary_action_layout) + self.primary_action.hide() + self.update_primary_action() + + # Layout + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.info_widget) + layout.addLayout(self.file_selection) + layout.addWidget(self.primary_action) + self.setLayout(layout) + + # Always start with focus on file selection + self.file_selection.setFocus() + + def update_primary_action(self): + # Show or hide primary action layout + file_count = self.file_selection.file_list.count() + if file_count > 0: + self.primary_action.show() + self.info_widget.show() + + # Update the file count in the info label + total_size_bytes = 0 + for index in range(self.file_selection.file_list.count()): + item = self.file_selection.file_list.item(index) + total_size_bytes += item.size_bytes + total_size_readable = self.common.human_readable_filesize(total_size_bytes) + + if file_count > 1: + self.info_label.setText(strings._('gui_file_info', True).format(file_count, total_size_readable)) + else: + self.info_label.setText(strings._('gui_file_info_single', True).format(file_count, total_size_readable)) + + else: + self.primary_action.hide() + self.info_widget.hide() + + # Resize window + self.adjustSize() + + def update_server_status_indicator(self): + self.common.log('OnionShareGui', 'update_server_status_indicator') + + # Set the status image + if self.server_status.status == self.server_status.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_stopped', True)) + elif self.server_status.status == self.server_status.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_working', True)) + elif self.server_status.status == self.server_status.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_started', True)) + + def start_server(self): + """ + Start the onionshare server. This uses multiple threads to start the Tor onion + server and the web app. + """ + self.common.log('OnionShareGui', 'start_server') + + self.set_server_active(True) + + self.app.set_stealth(self.common.settings.get('use_stealth')) + + # Hide and reset the downloads if we have previously shared + self.downloads.reset_downloads() + self.reset_info_counters() + self.status_bar.clearMessage() + self.server_share_status_label.setText('') + + # Reset web counters + self.web.download_count = 0 + self.web.error404_count = 0 + + # start the onion service in a new thread + def start_onion_service(self): + try: + self.app.start_onion_service() + self.starting_server_step2.emit() + + except (TorTooOld, TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorTimeout, OSError) as e: + self.starting_server_error.emit(e.args[0]) + return + + + self.app.stay_open = not self.common.settings.get('close_after_first_download') + + # start onionshare http service in new thread + t = threading.Thread(target=self.web.start, args=(self.app.port, self.app.stay_open, self.common.settings.get('slug'))) + t.daemon = True + t.start() + # wait for modules in thread to load, preventing a thread-related cx_Freeze crash + time.sleep(0.2) + + self.common.log('OnionshareGui', 'start_server', 'Starting an onion thread') + self.t = OnionThread(self.common, function=start_onion_service, kwargs={'self': self}) + self.t.daemon = True + self.t.start() + + def start_server_step2(self): + """ + Step 2 in starting the onionshare server. Zipping up files. + """ + self.common.log('OnionShareGui', 'start_server_step2') + + # add progress bar to the status bar, indicating the compressing of files. + self._zip_progress_bar = ZipProgressBar(0) + self.filenames = [] + 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.status_bar.insertWidget(0, self._zip_progress_bar) + + # prepare the files for sending in a new thread + def finish_starting_server(self): + # prepare files to share + def _set_processed_size(x): + if self._zip_progress_bar != None: + self._zip_progress_bar.update_processed_size_signal.emit(x) + try: + self.web.set_file_info(self.filenames, processed_size_callback=_set_processed_size) + self.app.cleanup_filenames.append(self.web.zip_filename) + self.starting_server_step3.emit() + + # done + self.start_server_finished.emit() + except OSError as e: + self.starting_server_error.emit(e.strerror) + return + + t = threading.Thread(target=finish_starting_server, kwargs={'self': self}) + t.daemon = True + t.start() + + def start_server_step3(self): + """ + Step 3 in starting the onionshare server. This displays the large filesize + warning, if applicable. + """ + self.common.log('OnionShareGui', 'start_server_step3') + + # Remove zip progress bar + if self._zip_progress_bar is not None: + self.status_bar.removeWidget(self._zip_progress_bar) + self._zip_progress_bar = None + + # warn about sending large files over Tor + if self.web.zip_filesize >= 157286400: # 150mb + self.filesize_warning.setText(strings._("large_filesize", True)) + self.filesize_warning.show() + + if self.common.settings.get('shutdown_timeout'): + # Convert the date value to seconds between now and then + now = QtCore.QDateTime.currentDateTime() + self.timeout = now.secsTo(self.server_status.timeout) + # Set the shutdown timeout value + if self.timeout > 0: + self.app.shutdown_timer = ShutdownTimer(self.common, self.timeout) + self.app.shutdown_timer.start() + # The timeout 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_timeout')) + + def start_server_error(self, error): + """ + If there's an error when trying to start the onion service + """ + self.common.log('OnionShareGui', 'start_server_error') + + self.set_server_active(False) + + Alert(self.common, error, QtWidgets.QMessageBox.Warning) + self.server_status.stop_server() + if self._zip_progress_bar is not None: + self.status_bar.removeWidget(self._zip_progress_bar) + self._zip_progress_bar = None + self.status_bar.clearMessage() + + def cancel_server(self): + """ + Cancel the server while it is preparing to start + """ + if self.t: + self.t.quit() + self.stop_server() + + def stop_server(self): + """ + Stop the onionshare server. + """ + self.common.log('OnionShareGui', 'stop_server') + + if self.server_status.status != self.server_status.STATUS_STOPPED: + try: + self.web.stop(self.app.port) + except: + # Probably we had no port to begin with (Onion service didn't start) + pass + self.app.cleanup() + # Remove ephemeral service, but don't disconnect from Tor + self.onion.cleanup(stop_tor=False) + self.filesize_warning.hide() + self.downloads_in_progress = 0 + self.downloads_completed = 0 + self.update_downloads_in_progress(0) + self.file_selection.file_list.adjustSize() + + self.set_server_active(False) + self.stop_server_finished.emit() + + def downloads_toggled(self, checked): + """ + When the 'Show/hide downloads' button is toggled, show or hide the downloads window. + """ + self.common.log('OnionShareGui', 'toggle_downloads') + if checked: + self.downloads.downloads_container.show() + else: + self.downloads.downloads_container.hide() + + def reset_info_counters(self): + """ + Set the info counters back to zero. + """ + self.update_downloads_completed(0) + self.update_downloads_in_progress(0) + self.info_show_downloads.setIcon(QtGui.QIcon(self.common.get_resource_path('images/download_window_gray.png'))) + self.downloads.no_downloads_label.show() + self.downloads.downloads_container.resize(self.downloads.downloads_container.sizeHint()) + + def update_downloads_completed(self, count): + """ + Update the 'Downloads completed' info widget. + """ + if count == 0: + self.info_completed_downloads_image = self.common.get_resource_path('images/download_completed_none.png') + else: + self.info_completed_downloads_image = self.common.get_resource_path('images/download_completed.png') + self.info_completed_downloads_count.setText(' {1:d}'.format(self.info_completed_downloads_image, count)) + self.info_completed_downloads_count.setToolTip(strings._('info_completed_downloads_tooltip', True).format(count)) + + def update_downloads_in_progress(self, count): + """ + Update the 'Downloads in progress' info widget. + """ + if count == 0: + self.info_in_progress_downloads_image = self.common.get_resource_path('images/download_in_progress_none.png') + else: + self.info_in_progress_downloads_image = self.common.get_resource_path('images/download_in_progress.png') + self.info_show_downloads.setIcon(QtGui.QIcon(self.common.get_resource_path('images/download_window_green.png'))) + self.info_in_progress_downloads_count.setText(' {1:d}'.format(self.info_in_progress_downloads_image, count)) + self.info_in_progress_downloads_count.setToolTip(strings._('info_in_progress_downloads_tooltip', True).format(count)) + + @staticmethod + def _compute_total_size(filenames): + total_size = 0 + for filename in filenames: + if os.path.isfile(filename): + total_size += os.path.getsize(filename) + if os.path.isdir(filename): + total_size += Common.dir_size(filename) + return total_size