def check_for_updates(self): """ Check for Updates button clicked. Manually force an update check. """ common.log('SettingsDialog', 'check_for_updates') # Disable buttons self._disable_buttons() self.qtapp.processEvents() # Check for updates def update_available(update_url, installed_version, latest_version): Alert(strings._("update_available", True).format(update_url, installed_version, latest_version)) def update_not_available(): Alert(strings._('update_not_available', True)) u = UpdateChecker(self.onion) u.update_available.connect(update_available) u.update_not_available.connect(update_not_available) try: u.check(force=True) except UpdateCheckerCheckError: Alert(strings._('update_error_check_error', True), QtWidgets.QMessageBox.Warning) except UpdateCheckerInvalidLatestVersion as e: Alert(strings._('update_error_invalid_latest_version', True).format(e.latest_version), QtWidgets.QMessageBox.Warning) # Enable buttons self._enable_buttons() # Update the last checked label settings = Settings(self.config) settings.load() autoupdate_timestamp = settings.get('autoupdate_timestamp') self._update_autoupdate_timestamp(autoupdate_timestamp)
def __init__(self): super(FileSelection, self).__init__() self.server_on = False # File list self.file_list = FileList() self.file_list.itemSelectionChanged.connect(self.update) self.file_list.files_dropped.connect(self.update) self.file_list.files_updated.connect(self.update) # Buttons self.add_button = QtWidgets.QPushButton(strings._('gui_add', True)) self.add_button.clicked.connect(self.add) self.delete_button = QtWidgets.QPushButton(strings._('gui_delete', True)) self.delete_button.clicked.connect(self.delete) button_layout = QtWidgets.QHBoxLayout() button_layout.addStretch() button_layout.addWidget(self.add_button) button_layout.addWidget(self.delete_button) # Add the widgets self.addWidget(self.file_list) self.addLayout(button_layout) self.update()
def update(self): # set the status image if self.status == self.STATUS_STOPPED: self.status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.status_image_stopped)) elif self.status == self.STATUS_WORKING: self.status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.status_image_working)) elif self.status == self.STATUS_STARTED: self.status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.status_image_started)) # set the URL fields if self.status == self.STATUS_STARTED: self.url_label.setText('http://{0}/ {1}'.format(self.app.onion_host, self.web.slug)) self.url_label.show() self.copy_url_button.show() else: self.url_label.hide() self.copy_url_button.hide() # button if self.file_selection.get_num_files() == 0: self.server_button.setEnabled(False) self.server_button.setText(strings._('gui_start_server', True)) else: if self.status == self.STATUS_STOPPED: self.server_button.setEnabled(True) self.server_button.setText(strings._('gui_start_server', True)) elif self.status == self.STATUS_STARTED: self.server_button.setEnabled(True) self.server_button.setText(strings._('gui_stop_server', True)) else: self.server_button.setEnabled(False) self.server_button.setText(strings._('gui_please_wait'))
def check_for_requests(self): self.update() # only check for requests if the server is running if self.server_status.status != self.server_status.STATUS_STARTED: return events = [] done = False while not done: try: r = web.q.get(False) events.append(r) except web.Queue.Empty: done = True for event in events: if event["type"] == web.REQUEST_LOAD: self.status_bar.showMessage(strings._('download_page_loaded', True)) elif event["type"] == web.REQUEST_DOWNLOAD: self.downloads.add_download(event["data"]["id"], web.zip_filesize) elif event["type"] == web.REQUEST_PROGRESS: self.downloads.update_download(event["data"]["id"], web.zip_filesize, event["data"]["bytes"]) # is the download complete? if event["data"]["bytes"] == web.zip_filesize: # close on finish? if not web.get_stay_open(): self.server_status.stop_server() elif event["path"] != '/favicon.ico': self.status_bar.showMessage('{0}: {1}'.format(strings._('other_page_loaded', True), event["path"]))
def test_load_partial_strings( self, locale_ru, sys_onionshare_dev_mode): strings.load_strings(common) assert strings._("give_this_url") == ( "Отправьте эту ссылку тому человеку, " "которому вы хотите передать файл:") assert strings._('wait_for_hs') == "Waiting for HS to be ready:"
def start_server_step2(self): self.status_bar.showMessage(strings._('gui_starting_server3', True)) # warn about sending large files over Tor if web.zip_filesize >= 157286400: # 150mb self.filesize_warning.setText(strings._("large_filesize", True)) self.filesize_warning.show()
def __init__(self): super(FileSelection, self).__init__() self.server_on = False # file list self.file_list = FileList() self.file_list.currentItemChanged.connect(self.update) self.file_list.files_dropped.connect(self.update) # buttons self.add_files_button = QtGui.QPushButton(strings._('gui_add_files', True)) self.add_files_button.clicked.connect(self.add_files) self.add_dir_button = QtGui.QPushButton(strings._('gui_add_folder', True)) self.add_dir_button.clicked.connect(self.add_dir) self.delete_button = QtGui.QPushButton(strings._('gui_delete', True)) self.delete_button.clicked.connect(self.delete_file) button_layout = QtGui.QHBoxLayout() button_layout.addWidget(self.add_files_button) button_layout.addWidget(self.add_dir_button) button_layout.addWidget(self.delete_button) # add the widgets self.addWidget(self.file_list) self.addLayout(button_layout) self.update()
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 = 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 start_server_step3(self): """ Step 3 in starting the onionshare server. This displays the large filesize warning, if applicable. """ 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 web.zip_filesize >= 157286400: # 150mb self.filesize_warning.setText(strings._("large_filesize", True)) self.filesize_warning.show() if self.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 = common.close_after_seconds(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 copy_url(self): """ When the URL gets copied to the clipboard, display this in the status bar. """ common.log('OnionShareGui', 'copy_url') if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'): self.systemTray.showMessage(strings._('gui_copied_url_title', True), strings._('gui_copied_url', True))
def closeEvent(self, e): self.common.log('OnionShareGui', 'closeEvent') try: if self.mode == OnionShareGui.MODE_SHARE: server_status = self.share_mode.server_status else: server_status = self.receive_mode.server_status if server_status.status != server_status.STATUS_STOPPED: self.common.log('OnionShareGui', 'closeEvent, opening warning dialog') dialog = QtWidgets.QMessageBox() dialog.setWindowTitle(strings._('gui_quit_title')) if self.mode == OnionShareGui.MODE_SHARE: 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 update(self, downloaded_bytes): self.downloaded_bytes = downloaded_bytes 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)) # Change the label self.label.setText(self.get_finished_label_text(self.started_dt)) self.status = HistoryItem.STATUS_FINISHED else: elapsed = time.time() - self.started if elapsed < 10: # 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)) else: pb_fmt = strings._('gui_all_modes_progress_eta').format( self.common.human_readable_filesize(downloaded_bytes), self.estimated_time_remaining) self.progress_bar.setFormat(pb_fmt)
def main(): """ The main() function implements all of the logic that the GUI version of onionshare uses. """ strings.load_strings() # start the Qt app global qtapp qtapp = Application() # parse arguments parser = argparse.ArgumentParser() parser.add_argument('--local-only', action='store_true', dest='local_only', help=strings._("help_local_only")) parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=strings._("help_stay_open")) parser.add_argument('--debug', action='store_true', dest='debug', help=strings._("help_debug")) parser.add_argument('--transparent', action='store_true', dest='transparent_torification', help=strings._("help_transparent_torification")) parser.add_argument('--filenames', metavar='filenames', nargs='+', help=strings._('help_filename')) args = parser.parse_args() filenames = args.filenames if filenames: for i in range(len(filenames)): filenames[i] = os.path.abspath(filenames[i]) local_only = bool(args.local_only) stay_open = bool(args.stay_open) debug = bool(args.debug) transparent_torification = bool(args.transparent_torification) # create the onionshare icon global window_icon window_icon = QtGui.QIcon(common.get_image_path('logo.png')) # validation if filenames: valid = True for filename in filenames: if not os.path.exists(filename): alert(strings._("not_a_file", True).format(filename)) valid = False if not valid: sys.exit() # start the onionshare app web.set_stay_open(stay_open) web.set_transparent_torification(transparent_torification) app = onionshare.OnionShare(debug, local_only, stay_open, transparent_torification) # clean up when app quits def shutdown(): app.cleanup() qtapp.connect(qtapp, QtCore.SIGNAL("aboutToQuit()"), shutdown) # launch the gui gui = OnionShareGui(qtapp, app) gui.send_files(filenames) # all done sys.exit(qtapp.exec_())
def _update_autoupdate_timestamp(self, autoupdate_timestamp): common.log('SettingsDialog', '_update_autoupdate_timestamp') if autoupdate_timestamp: dt = datetime.datetime.fromtimestamp(autoupdate_timestamp) last_checked = dt.strftime('%B %d, %Y %H:%M') else: last_checked = strings._('gui_settings_autoupdate_timestamp_never', True) self.autoupdate_timestamp.setText(strings._('gui_settings_autoupdate_timestamp', True).format(last_checked))
def server_status_indicator_says_closed(self, mode, stay_open): '''Test that the Server Status indicator shows we closed''' if type(mode) == ReceiveMode: self.assertEqual(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped')) if type(mode) == ShareMode: if stay_open: self.assertEqual(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_stopped')) else: self.assertEqual(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically'))
def init(self): """ Custom initialization for ReceiveMode. """ # Create the Web object self.web = Web(self.common, True, 'receive') # Server status 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) # Tell server_status about web, then update self.server_status.web = self.web self.server_status.update() # 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') ) 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')) ) # Receive mode warning receive_warning = QtWidgets.QLabel(strings._('gui_receive_mode_warning')) receive_warning.setMinimumHeight(80) receive_warning.setWordWrap(True) # Top bar top_bar_layout = QtWidgets.QHBoxLayout() top_bar_layout.addStretch() top_bar_layout.addWidget(self.toggle_history) # Main layout self.main_layout = QtWidgets.QVBoxLayout() self.main_layout.addLayout(top_bar_layout) self.main_layout.addWidget(receive_warning) self.main_layout.addWidget(self.primary_action) self.main_layout.addStretch() self.main_layout.addWidget(self.min_width_widget) # Wrapper layout self.wrapper_layout = QtWidgets.QHBoxLayout() self.wrapper_layout.addLayout(self.main_layout) self.wrapper_layout.addWidget(self.history, stretch=1) self.setLayout(self.wrapper_layout)
def update(self): """ Update the GUI elements based on the current state. """ # set the status image if self.status == self.STATUS_STOPPED: self.status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.status_image_stopped)) elif self.status == self.STATUS_WORKING: self.status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.status_image_working)) elif self.status == self.STATUS_STARTED: self.status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.status_image_started)) # set the URL fields if self.status == self.STATUS_STARTED: self.url_label.setText('http://{0:s}/{1:s}'.format(self.app.onion_host, self.web.slug)) self.url_label.show() self.copy_url_button.show() if self.app.stealth: self.copy_hidservauth_button.show() else: self.copy_hidservauth_button.hide() # resize parent widget p = self.parentWidget() p.resize(p.sizeHint()) else: self.url_label.hide() self.copy_url_button.hide() self.copy_hidservauth_button.hide() # button if self.file_selection.get_num_files() == 0: self.server_button.setEnabled(False) self.server_button.setText(strings._('gui_start_server', True)) else: if self.status == self.STATUS_STOPPED: self.server_button.setEnabled(True) self.server_button.setText(strings._('gui_start_server', True)) self.server_shutdown_timeout.setEnabled(True) self.server_shutdown_timeout_checkbox.setEnabled(True) elif self.status == self.STATUS_STARTED: self.server_button.setEnabled(True) self.server_button.setText(strings._('gui_stop_server', True)) self.server_shutdown_timeout.setEnabled(False) self.server_shutdown_timeout_checkbox.setEnabled(False) elif self.status == self.STATUS_WORKING: self.server_button.setEnabled(False) self.server_button.setText(strings._('gui_please_wait')) self.server_shutdown_timeout.setEnabled(False) self.server_shutdown_timeout_checkbox.setEnabled(False) else: self.server_button.setEnabled(False) self.server_button.setText(strings._('gui_please_wait')) self.server_shutdown_timeout.setEnabled(False) self.server_shutdown_timeout_checkbox.setEnabled(False)
def check_for_requests(self): """ Check for messages communicated from the web app, and update the GUI accordingly. """ self.update() # scroll to the bottom of the dl progress bar log pane # if a new download has been added if self.new_download: self.vbar.setValue(self.vbar.maximum()) self.new_download = False # only check for requests if the server is running if self.server_status.status != self.server_status.STATUS_STARTED: return events = [] done = False while not done: try: r = web.q.get(False) events.append(r) except web.queue.Empty: done = True for event in events: if event["type"] == web.REQUEST_LOAD: self.status_bar.showMessage(strings._("download_page_loaded", True)) elif event["type"] == web.REQUEST_DOWNLOAD: self.downloads_container.show() # show the downloads layout self.downloads.add_download(event["data"]["id"], web.zip_filesize) self.new_download = True elif event["type"] == web.REQUEST_RATE_LIMIT: self.stop_server() Alert(strings._("error_rate_limit"), QtWidgets.QMessageBox.Critical) elif event["type"] == web.REQUEST_PROGRESS: self.downloads.update_download(event["data"]["id"], event["data"]["bytes"]) # is the download complete? if event["data"]["bytes"] == web.zip_filesize: # close on finish? if not web.get_stay_open(): self.server_status.stop_server() elif event["type"] == web.REQUEST_CANCELED: self.downloads.cancel_download(event["data"]["id"]) elif event["path"] != "/favicon.ico": self.status_bar.showMessage( "[#{0:d}] {1:s}: {2:s}".format( web.error404_count, strings._("other_page_loaded", True), event["path"] ) )
def handle_request_started(self, event): """ Handle REQUEST_STARTED event. """ 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'))
def update_server_status_indicator(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 check_for_requests(self): """ Check for messages communicated from the web app, and update the GUI accordingly. """ self.update() # only check for requests if the server is running if self.server_status.status != self.server_status.STATUS_STARTED: return events = [] done = False while not done: try: r = web.q.get(False) events.append(r) except web.queue.Empty: done = True for event in events: if event["type"] == web.REQUEST_LOAD: self.status_bar.showMessage( strings._('download_page_loaded', True)) elif event["type"] == web.REQUEST_DOWNLOAD: self.downloads.add_download(event["data"]["id"], web.zip_filesize) elif event["type"] == web.REQUEST_RATE_LIMIT: self.stop_server() alert(strings._('error_rate_limit'), QtWidgets.QMessageBox.Critical) elif event["type"] == web.REQUEST_PROGRESS: self.downloads.update_download(event["data"]["id"], event["data"]["bytes"]) # is the download complete? if event["data"]["bytes"] == web.zip_filesize: # close on finish? if not web.get_stay_open(): self.server_status.stop_server() elif event["type"] == web.REQUEST_CANCELED: self.downloads.cancel_download(event["data"]["id"]) elif event["path"] != '/favicon.ico': self.status_bar.showMessage('[#{0:d}] {1:s}: {2:s}'.format( web.error404_count, strings._('other_page_loaded', True), event["path"]))
def update_server_status_indicator(self): # Set the status image 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')) 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')) 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 handle_request_started(self, event): """ Handle REQUEST_STARTED event. """ 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'))
def server_button_clicked(self): """ Toggle starting or stopping the server. """ if self.status == self.STATUS_STOPPED: can_start = True if self.common.settings.get('autostart_timer'): if self.local_only: 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) # 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: can_start = False 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() 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) # 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: can_start = False 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) can_start = False if can_start: self.start_server() elif self.status == self.STATUS_STARTED: self.stop_server() elif self.status == self.STATUS_WORKING: self.cancel_server() self.button_clicked.emit()
def server_status_indicator_says_closed(self, mode, stay_open): '''Test that the Server Status indicator shows we closed''' if type(mode) == ReceiveMode: self.assertEqual(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped')) if type(mode) == ShareMode: if stay_open: self.assertEqual( self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_stopped')) else: self.assertEqual( self.gui.share_mode.server_status_label.text(), strings._('closing_automatically'))
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.upload_count == 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')) 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.web.receive_mode.can_upload = False return False
def update(self): """ Update the GUI elements based on the current state. """ # set the status image if self.status == self.STATUS_STOPPED: self.status_image_label.setPixmap( QtGui.QPixmap.fromImage(self.status_image_stopped)) elif self.status == self.STATUS_WORKING: self.status_image_label.setPixmap( QtGui.QPixmap.fromImage(self.status_image_working)) elif self.status == self.STATUS_STARTED: self.status_image_label.setPixmap( QtGui.QPixmap.fromImage(self.status_image_started)) # set the URL fields if self.status == self.STATUS_STARTED: self.url_label.setText('http://{0:s}/{1:s}'.format( self.app.onion_host, self.web.slug)) self.url_label.show() self.copy_url_button.show() if self.app.stealth: self.copy_hidservauth_button.show() else: self.copy_hidservauth_button.hide() # resize parent widget p = self.parentWidget() p.resize(p.sizeHint()) else: self.url_label.hide() self.copy_url_button.hide() self.copy_hidservauth_button.hide() # button if self.file_selection.get_num_files() == 0: self.server_button.setEnabled(False) self.server_button.setText(strings._('gui_start_server', True)) else: if self.status == self.STATUS_STOPPED: self.server_button.setEnabled(True) self.server_button.setText(strings._('gui_start_server', True)) elif self.status == self.STATUS_STARTED: self.server_button.setEnabled(True) self.server_button.setText(strings._('gui_stop_server', True)) else: self.server_button.setEnabled(False) self.server_button.setText(strings._('gui_please_wait'))
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 download the share, or all downloads are done, we can stop if self.web.share_mode.download_count == 0 or self.web.done: self.server_status.stop_server() 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')) return False
def timeout_finished_should_stop_server(self): """ The shutdown 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.upload_count == 0 or not self.web.receive_mode.uploads_in_progress: self.server_status.stop_server() self.server_status_label.setText(strings._('close_on_timeout')) 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_timeout_waiting')) self.web.receive_mode.can_upload = False return False
def start_server(self): """ Start the onionshare server. This uses multiple threads to start the Tor hidden server and the web app. """ # Reset web counters web.download_count = 0 web.error404_count = 0 # start the hidden service self.status_bar.showMessage(strings._('gui_starting_server1', True)) self.app.choose_port() try: self.app.start_hidden_service(gui=True) except onionshare.hs.NoTor as e: alert(e.args[0], QtWidgets.QMessageBox.Warning) self.server_status.stop_server() self.status_bar.clearMessage() return # start onionshare service in new thread t = threading.Thread(target=web.start, args=(self.app.port, self.app.stay_open, self.app.transparent_torification)) t.daemon = True t.start() # prepare the files for sending in a new thread def finish_starting_server(self): # prepare files to share web.set_file_info(self.file_selection.file_list.filenames) self.app.cleanup_filenames.append(web.zip_filename) self.starting_server_step2.emit() # wait for hs if not self.app.local_only: self.status_bar.showMessage( strings._('gui_starting_server3', True)) self.app.hs.wait_for_hs(self.app.onion_host) # done self.start_server_finished.emit() self.status_bar.showMessage(strings._('gui_starting_server2', True)) t = threading.Thread(target=finish_starting_server, kwargs={'self': self}) t.daemon = True t.start()
def add_dir(self): filename = QtGui.QFileDialog.getExistingDirectory( caption=strings._('gui_choose_folder', True), options=QtGui.QFileDialog.ReadOnly) if filename: self.file_list.add_file(str(filename)) self.update()
def test_tor_clicked(self): """ Test Tor Settings button clicked. With the given settings, see if we can successfully connect and authenticate to Tor. """ common.log('SettingsDialog', 'test_tor_clicked') settings = self.settings_from_fields() try: # Show Tor connection status if connection type is bundled tor if settings.get('connection_type') == 'bundled': self.tor_status.show() self._disable_buttons() def tor_status_update_func(progress, summary): self._tor_status_update(progress, summary) return True else: tor_status_update_func = None onion = Onion() onion.connect(settings=settings, config=self.config, tor_status_update_func=tor_status_update_func) # If an exception hasn't been raised yet, the Tor settings work Alert(strings._('settings_test_success', True).format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth)) # Clean up onion.cleanup() except (TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e: Alert(e.args[0], QtWidgets.QMessageBox.Warning) if settings.get('connection_type') == 'bundled': self.tor_status.hide() self._enable_buttons()
def __init__(self, total_files_size): super(ZipProgressBar, self).__init__() self.setMaximumHeight(20) self.setMinimumWidth(200) self.setValue(0) self.setFormat(strings._('zip_progress_bar_format')) cssStyleData =""" QProgressBar { border: 1px solid #4e064f; background-color: #ffffff !important; text-align: center; color: #9b9b9b; } QProgressBar::chunk { border: 0px; background-color: #4e064f; width: 10px; }""" self.setStyleSheet(cssStyleData) self._total_files_size = total_files_size self._processed_size = 0 self.update_processed_size_signal.connect(self.update_processed_size)
def __init__(self, common, id, total_bytes): super(ShareHistoryItem, self).__init__() self.common = common self.id = id self.total_bytes = total_bytes self.downloaded_bytes = 0 self.started = time.time() self.started_dt = datetime.fromtimestamp(self.started) 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"))) # Progress bar self.progress_bar = QtWidgets.QProgressBar() self.progress_bar.setTextVisible(True) self.progress_bar.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter) 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.total_bytes = total_bytes # Layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.progress_bar) self.setLayout(layout) # Start at 0 self.update(0)
def handle_request_started(self, event): """ Handle REQUEST_STARTED event. """ if event["data"]["use_gzip"]: filesize = self.web.share_mode.gzip_filesize else: filesize = self.web.share_mode.download_filesize item = ShareHistoryItem(self.common, event["data"]["id"], filesize) 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_share_started_title'), strings._('systray_share_started_message'))
def copy_hidservauth(self): """ When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar. """ common.log('OnionShareGui', 'copy_hidservauth') self.status_bar.showMessage(strings._('gui_copied_hidservauth', True), 2000)
def add_file(self, filename): """ Add a file or directory to this widget. """ if filename not in self.filenames: if not os.access(filename, os.R_OK): Alert(strings._("not_a_readable_file", True).format(filename)) return self.filenames.append(filename) fileinfo = QtCore.QFileInfo(filename) basename = os.path.basename(filename.rstrip('/')) ip = QtWidgets.QFileIconProvider() icon = ip.icon(fileinfo) if os.path.isfile(filename): size = common.human_readable_filesize(fileinfo.size()) else: size = common.human_readable_filesize( common.dir_size(filename)) item_name = '{0:s} ({1:s})'.format(basename, size) item = QtWidgets.QListWidgetItem(item_name) item.setToolTip(size) item.setIcon(icon) self.addItem(item) self.files_updated.emit()
def __init__(self, total_files_size): super(ZipProgressBar, self).__init__() self.setMaximumHeight(20) self.setMinimumWidth(200) self.setValue(0) self.setFormat(strings._('zip_progress_bar_format')) cssStyleData = """ QProgressBar { border: 1px solid #4e064f; background-color: #ffffff !important; text-align: center; color: #9b9b9b; } QProgressBar::chunk { border: 0px; background-color: #4e064f; width: 10px; }""" self.setStyleSheet(cssStyleData) self._total_files_size = total_files_size self._processed_size = 0 self.update_processed_size_signal.connect(self.update_processed_size)
def chat_mode_clicked(self): self.common.log("Tab", "chat_mode_clicked") self.mode = self.common.gui.MODE_CHAT self.new_tab.hide() self.chat_mode = ChatMode(self) self.chat_mode.change_persistent.connect(self.change_persistent) self.layout.addWidget(self.chat_mode) self.chat_mode.show() self.chat_mode.init() self.chat_mode.server_status.server_started.connect( self.update_server_status_indicator ) self.chat_mode.server_status.server_stopped.connect( self.update_server_status_indicator ) self.chat_mode.start_server_finished.connect( self.update_server_status_indicator ) self.chat_mode.stop_server_finished.connect(self.update_server_status_indicator) self.chat_mode.stop_server_finished.connect(self.stop_server_finished) self.chat_mode.start_server_finished.connect(self.clear_message) self.chat_mode.server_status.button_clicked.connect(self.clear_message) self.chat_mode.server_status.url_copied.connect(self.copy_url) self.chat_mode.server_status.hidservauth_copied.connect(self.copy_hidservauth) self.change_title.emit(self.tab_id, strings._("gui_tab_name_chat")) self.update_server_status_indicator() self.timer.start(500)
def __init__(self, common, qtapp, onion, custom_settings=False): super(TorConnectionDialog, self).__init__(None) self.common = common if custom_settings: self.settings = custom_settings else: self.settings = self.common.settings 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.setModal(True) self.setFixedSize(400, 150) # Label self.setLabelText(strings._('connecting_to_tor')) # Progress bar ticks from 0 to 100 self.setRange(0, 100) # Don't show if connection takes less than 100ms (for non-bundled tor) self.setMinimumDuration(100) # Start displaying the status at 0 self._tor_status_update(0, '')
def __init__(self, common, image_filename, header_text, w, h, parent): super(DropHereWidget, self).__init__(parent) self.common = common self.setAcceptDrops(True) self.image_label = QtWidgets.QLabel(parent=self) self.image_label.setPixmap( QtGui.QPixmap.fromImage( QtGui.QImage(self.common.get_resource_path(image_filename)) ) ) self.image_label.setAlignment(QtCore.Qt.AlignCenter) self.image_label.show() self.header_label = QtWidgets.QLabel(parent=self) self.header_label.setText(header_text) self.header_label.setStyleSheet( self.common.gui.css["share_file_selection_drop_here_header_label"] ) self.header_label.setAlignment(QtCore.Qt.AlignCenter) self.header_label.show() self.text_label = QtWidgets.QLabel(parent=self) self.text_label.setText(strings._("gui_drag_and_drop")) self.text_label.setStyleSheet( self.common.gui.css["share_file_selection_drop_here_label"] ) self.text_label.setAlignment(QtCore.Qt.AlignCenter) self.text_label.show() self.resize(w, h) self.hide()
def test_load_strings_loads_other_languages(self, common_obj, locale_fr, sys_onionshare_dev_mode): """ load_strings() loads other languages in different locales """ common_obj.settings = Settings(common_obj) common_obj.settings.set("locale", "fr") strings.load_strings(common_obj) assert strings._("preparing_files") == "Compression des fichiers."
def open_folder(self): """ Open the downloads folder, with the file selected, in a cross-platform manner """ 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") return abs_filename = os.path.join(self.dir, self.filename) # Linux if self.common.platform == 'Linux' or self.common.platform == 'BSD': try: # If nautilus is available, open it subprocess.Popen(['nautilus', abs_filename]) except: Alert(self.common, strings._('gui_open_folder_error_nautilus').format(abs_filename)) # macOS elif self.common.platform == 'Darwin': subprocess.call(['open', '-R', abs_filename]) # Windows elif self.common.platform == 'Windows': subprocess.Popen(['explorer', '/select,{}'.format(abs_filename)])
def update_error(): Alert( self.common, strings._("update_error_check_error"), QtWidgets.QMessageBox.Warning, ) close_forced_update_thread()
def open_folder(self): """ Open the downloads folder, with the file selected, in a cross-platform manner """ 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") return abs_filename = os.path.join(self.dir, self.filename) # Linux if self.common.platform == 'Linux' or self.common.platform == 'BSD': try: # If nautilus is available, open it subprocess.Popen(['nautilus', abs_filename]) except: Alert( self.common, strings._('gui_open_folder_error_nautilus').format( abs_filename)) # macOS elif self.common.platform == 'Darwin': subprocess.call(['open', '-R', abs_filename]) # Windows elif self.common.platform == 'Windows': subprocess.Popen(['explorer', '/select,{}'.format(abs_filename)])
def open_folder(self): """ Open the downloads folder, with the file selected, in a cross-platform manner """ 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", ) return abs_filename = os.path.join(self.dir, self.filename) # Linux if self.common.platform == "Linux" or self.common.platform == "BSD": try: # If nautilus is available, open it subprocess.Popen(["xdg-open", self.dir]) except: Alert( self.common, strings._("gui_open_folder_error").format(abs_filename), ) # macOS elif self.common.platform == "Darwin": subprocess.call(["open", "-R", abs_filename]) # Windows elif self.common.platform == "Windows": subprocess.Popen(["explorer", f"/select,{abs_filename}"])
def add_files(self): filenames = QtGui.QFileDialog.getOpenFileNames( caption=strings._('gui_choose_files', True), options=QtGui.QFileDialog.ReadOnly) if filenames: for filename in filenames: self.file_list.add_file(str(filename)) self.update()
def test_load_strings_loads_other_languages( self, common_obj, locale_fr, sys_onionshare_dev_mode): """ load_strings() loads other languages in different locales """ common_obj.settings = Settings(common_obj) common_obj.settings.set('locale', 'fr') strings.load_strings(common_obj) assert strings._('preparing_files') == "Compression des fichiers."
def start_onion_service(self): try: # Show Tor connection status if connection type is bundled tor if settings.get('connection_type') == 'bundled': def bundled_tor_func(message): self.status_bar.showMessage(message) if 'Done' in message: self.status_bar.showMessage( strings._('gui_starting_server1', True)) else: self.status_bar.showMessage( strings._('gui_starting_server1', True)) bundled_tor_func = None self.app.start_onion_service(bundled_tor_func) self.starting_server_step2.emit() except (onionshare.onion.TorTooOld, onionshare.onion.TorErrorInvalidSetting, onionshare.onion.TorErrorAutomatic, onionshare.onion.TorErrorSocketPort, onionshare.onion.TorErrorSocketFile, onionshare.onion.TorErrorMissingPassword, onionshare.onion.TorErrorUnreadableCookieFile, onionshare.onion.TorErrorAuthError, onionshare.onion.TorErrorProtocolError, onionshare.onion.BundledTorTimeout) as e: self.starting_server_error.emit(e.args[0]) return
def add_tab(self, mode_settings=None): tab = Tab(self.common, self.current_tab_id, self.system_tray, self.status_bar) tab.change_title.connect(self.change_title) tab.change_icon.connect(self.change_icon) tab.change_persistent.connect(self.change_persistent) self.tabs[self.current_tab_id] = tab self.current_tab_id += 1 index = self.addTab(tab, strings._("gui_new_tab")) self.setCurrentIndex(index) # Create a close button def close_tab(): self.tabBar().tabCloseRequested.emit(self.indexOf(tab)) close_button = QtWidgets.QPushButton() close_button.setFlat(True) close_button.setFixedWidth(40) close_button.setIcon( QtGui.QIcon(self.common.get_resource_path("images/close_tab.png"))) close_button.clicked.connect(close_tab) self.tabBar().setTabButton(index, QtWidgets.QTabBar.RightSide, close_button) tab.init(mode_settings) # If it's persistent, set the persistent image in the tab self.change_persistent(tab.tab_id, tab.settings.get("persistent", "enabled")) # Bring the window to front, in case this is being added by an event self.bring_to_front.emit()
def copy_hidservauth(self): """ When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar. """ common.log('OnionShareGui', 'copy_hidservauth') if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'): self.systemTray.showMessage(strings._('gui_copied_hidservauth_title', True), strings._('gui_copied_hidservauth', True))
def add_file(self, filename): """ Add a file or directory to this widget. """ if filename not in self.filenames: if not os.access(filename, os.R_OK): Alert(strings._("not_a_readable_file", True).format(filename)) return self.filenames.append(filename) # Re-sort the list internally self.filenames.sort() fileinfo = QtCore.QFileInfo(filename) basename = os.path.basename(filename.rstrip('/')) ip = QtWidgets.QFileIconProvider() icon = ip.icon(fileinfo) if os.path.isfile(filename): size = common.human_readable_filesize(fileinfo.size()) else: size = common.human_readable_filesize(common.dir_size(filename)) item_name = '{0:s} ({1:s})'.format(basename, size) item = QtWidgets.QListWidgetItem(item_name) item.setToolTip(size) item.setIcon(icon) self.addItem(item) self.files_updated.emit()
def _tor_status_update(self, progress, summary): self.tor_status.setText('<strong>{}</strong><br>{}% {}'.format( strings._('connecting_to_tor', True), progress, summary)) self.qtapp.processEvents() if 'Done' in summary: self.tor_status.hide() self._enable_buttons()
def human_friendly_time(self, secs): """ 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 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')) return result
def update_available(update_url, installed_version, latest_version): Alert( self.common, strings._("update_available").format( update_url, installed_version, latest_version), )
def test_load_strings_defaults_to_english(self, common_obj, locale_en, sys_onionshare_dev_mode): """ load_strings() loads English by default """ common_obj.settings = Settings(common_obj) strings.load_strings(common_obj) assert strings._( "not_a_readable_file") == "{0:s} is not a readable file."
def _tor_status_update(self, message): self.tor_status.setText('<strong>{}</strong><br>{}'.format( strings._('connecting_to_tor', True), message)) self.qtapp.processEvents() if 'Done' in message: self.tor_status.hide() self._enable_buttons()
def start_server_step2(self): """ Step 2 in starting the onionshare server. Prepare files for serving. """ # prepare the files for sending in a new thread def finish_starting_server(self): # prepare files to share web.set_file_info(self.file_selection.file_list.filenames) self.app.cleanup_filenames.append(web.zip_filename) self.starting_server_step3.emit() # wait for hs if not self.app.local_only and not self.app.onion.supports_ephemeral: self.status_bar.showMessage( strings._('gui_starting_server3', True)) self.app.onion.wait_for_hs(self.app.onion_host) # done self.start_server_finished.emit() self.status_bar.showMessage(strings._('gui_starting_server2', True)) t = threading.Thread(target=finish_starting_server, kwargs={'self': self}) t.daemon = True t.start()