def copy_url(self): """ When the URL gets copied to the clipboard, display this in the status bar. """ self.common.log('OnionShareGui', 'copy_url') self.system_tray.showMessage(strings._('gui_copied_url_title'), strings._('gui_copied_url'))
def copy_hidservauth(self): """ When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar. """ self.common.log('OnionShareGui', 'copy_hidservauth') self.system_tray.showMessage(strings._('gui_copied_hidservauth_title'), strings._('gui_copied_hidservauth'))
def handle_request_progress(self, event): """ Handle REQUEST_PROGRESS event. """ self.history.update(event["data"]["id"], event["data"]["bytes"]) # Is the download complete? if event["data"]["bytes"] == self.web.share_mode.filesize: self.system_tray.showMessage( strings._('systray_share_completed_title'), strings._('systray_share_completed_message')) # Update completed and in progress labels self.history.completed_count += 1 self.history.in_progress_count -= 1 self.history.update_completed() self.history.update_in_progress() # Close on finish? if self.common.settings.get('close_after_first_download'): self.server_status.stop_server() self.status_bar.clearMessage() self.server_status_label.setText( strings._('closing_automatically')) else: if self.server_status.status == self.server_status.STATUS_STOPPED: self.history.cancel(event["data"]["id"]) self.history.in_progress_count = 0 self.history.update_in_progress()
def ask(): a = Alert(self.common, strings._('gui_tor_connection_ask'), QtWidgets.QMessageBox.Question, buttons=QtWidgets.QMessageBox.NoButton, autostart=False) settings_button = QtWidgets.QPushButton( strings._('gui_tor_connection_ask_open_settings')) quit_button = QtWidgets.QPushButton( strings._('gui_tor_connection_ask_quit')) a.addButton(settings_button, QtWidgets.QMessageBox.AcceptRole) a.addButton(quit_button, QtWidgets.QMessageBox.RejectRole) a.setDefaultButton(settings_button) a.exec_() if a.clickedButton() == settings_button: # Open settings self.common.log('OnionShareGui', '_tor_connection_canceled', 'Settings button clicked') self.open_settings() if a.clickedButton() == quit_button: # Quit self.common.log('OnionShareGui', '_tor_connection_canceled', 'Quit button clicked') # Wait 1ms for the event loop to finish, then quit QtCore.QTimer.singleShot(1, self.qtapp.quit)
def update_primary_action(self): self.common.log('ShareMode', 'update_primary_action') # Show or hide primary action layout file_count = self.file_selection.file_list.count() if file_count > 0: self.primary_action.show() self.info_label.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').format(file_count, total_size_readable)) else: self.info_label.setText( strings._('gui_file_info_single').format( file_count, total_size_readable)) else: self.primary_action.hide() self.info_label.hide()
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 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 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 handle_request_canceled(self, event): """ Handle REQUEST_CANCELED event. """ self.history.cancel(event["data"]["id"]) # Update in progress count self.history.in_progress_count -= 1 self.history.update_in_progress() self.system_tray.showMessage( strings._('systray_share_canceled_title'), strings._('systray_share_canceled_message'))
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 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_timeout')) return True # A download is probably still running - hold off on stopping the share else: self.server_status_label.setText( strings._('gui_share_mode_timeout_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 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 handle_request_rate_limit(self, event): """ Handle REQUEST_RATE_LIMIT event. """ self.stop_server() Alert(self.common, strings._('error_rate_limit'), QtWidgets.QMessageBox.Critical)
def server_button_clicked(self): """ Toggle starting or stopping the server. """ if self.status == self.STATUS_STOPPED: if self.common.settings.get('shutdown_timeout'): if self.local_only: self.timeout = self.shutdown_timeout.dateTime( ).toPyDateTime() else: # Get the timeout chosen, stripped of its seconds. This prevents confusion if the share stops at (say) 37 seconds past the minute chosen self.timeout = self.shutdown_timeout.dateTime( ).toPyDateTime().replace(second=0, microsecond=0) # If the timeout has actually passed already before the user hit Start, refuse to start the server. if QtCore.QDateTime.currentDateTime().toPyDateTime( ) > self.timeout: Alert(self.common, strings._('gui_server_timeout_expired'), QtWidgets.QMessageBox.Warning) else: self.start_server() else: 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 __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 add_files(self): """ Add files button clicked. """ files = QtWidgets.QFileDialog.getOpenFileNames(self.parent, caption=strings._('gui_choose_items')) filenames = files[0] for filename in filenames: self.file_list.add_file(filename)
def add_folder(self): """ Add folder button clicked. """ filename = QtWidgets.QFileDialog.getExistingDirectory(self.parent, caption=strings._('gui_choose_items'), options=QtWidgets.QFileDialog.ShowDirsOnly) self.file_list.add_file(filename)
def alert_and_open_settings(): # Display the exception in an alert box Alert( self.common, "{}\n\n{}".format( msg, strings._('gui_tor_connection_error_settings')), QtWidgets.QMessageBox.Warning) # Open settings self.open_settings.emit()
def _get_label_text(self, string_name, string_range_name, started): """ Return a string that contains a date, or date range. """ ended = datetime.now() if started.year == ended.year and started.month == ended.month and started.day == ended.day: if started.hour == ended.hour and started.minute == ended.minute: text = strings._(string_name).format( started.strftime("%b %d, %I:%M%p")) else: text = strings._(string_range_name).format( started.strftime("%b %d, %I:%M%p"), ended.strftime("%I:%M%p")) else: text = strings._(string_range_name).format( started.strftime("%b %d, %I:%M%p"), ended.strftime("%b %d, %I:%M%p")) return text
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 add(self): """ Add button clicked. """ file_dialog = AddFileDialog(self.common, caption=strings._('gui_choose_items')) if file_dialog.exec_() == QtWidgets.QDialog.Accepted: for filename in file_dialog.selectedFiles(): self.file_list.add_file(filename) self.file_list.setCurrentItem(None) self.update()
def __init__(self, common, parent): self.parent = parent super(DropCountLabel, self).__init__(parent=parent) self.common = common self.setAcceptDrops(True) self.setAlignment(QtCore.Qt.AlignCenter) self.setText(strings._('gui_drag_and_drop')) self.setStyleSheet(self.common.css['share_file_selection_drop_count_label']) self.hide()
def __init__(self, common, parent): super(FileSelection, self).__init__() self.common = common self.parent = parent self.server_on = False # File list self.file_list = FileList(self.common) self.file_list.itemSelectionChanged.connect(self.update) self.file_list.files_dropped.connect(self.update) self.file_list.files_updated.connect(self.update) # Buttons if self.common.platform == 'Darwin': # The macOS sandbox makes it so the Mac version needs separate add files # and folders buttons, in order to use native file selection dialogs self.add_files_button = QtWidgets.QPushButton(strings._('gui_add_files')) self.add_files_button.clicked.connect(self.add_files) self.add_folder_button = QtWidgets.QPushButton(strings._('gui_add_folder')) self.add_folder_button.clicked.connect(self.add_folder) else: self.add_button = QtWidgets.QPushButton(strings._('gui_add')) self.add_button.clicked.connect(self.add) self.delete_button = QtWidgets.QPushButton(strings._('gui_delete')) self.delete_button.clicked.connect(self.delete) button_layout = QtWidgets.QHBoxLayout() button_layout.addStretch() if self.common.platform == 'Darwin': button_layout.addWidget(self.add_files_button) button_layout.addWidget(self.add_folder_button) else: 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 closeEvent(self, e): self.common.log('OnionShareGui', 'closeEvent') try: if self.server.is_therapist: session.post(f"{self.server.url}/therapist_signout", data={ "username": self.server.username, "password": self.server.password }) 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 start_server_step3_custom(self): """ Step 3 in starting the server. Remove zip progess bar, and display large filesize warning, if applicable. """ # 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.share_mode.download_filesize >= 157286400: # 150mb self.filesize_warning.setText(strings._("large_filesize")) self.filesize_warning.show()
def update_completed(self): """ Update the 'completed' widget. """ if self.completed_count == 0: image = self.common.get_resource_path( 'images/share_completed_none.png') else: image = self.common.get_resource_path('images/share_completed.png') self.completed_label.setText('<img src="{0:s}" /> {1:d}'.format( image, self.completed_count)) self.completed_label.setToolTip( strings._('history_completed_tooltip').format( self.completed_count))
def __init__(self, common, total_files_size): super(ZipProgressBar, self).__init__() self.common = common self.setMaximumHeight(20) self.setMinimumWidth(200) self.setValue(0) self.setFormat(strings._('zip_progress_bar_format')) self.setStyleSheet(self.common.css['share_zip_progess_bar']) self._total_files_size = total_files_size self._processed_size = 0 self.update_processed_size_signal.connect(self.update_processed_size)
def update_in_progress(self): """ Update the 'in progress' widget. """ if self.in_progress_count == 0: image = self.common.get_resource_path( 'images/share_in_progress_none.png') else: image = self.common.get_resource_path( 'images/share_in_progress.png') self.in_progress_label.setText('<img src="{0:s}" /> {1:d}'.format( image, self.in_progress_count)) self.in_progress_label.setToolTip( strings._('history_in_progress_tooltip').format( self.in_progress_count))
def __init__(self, common, parent, image=False): self.parent = parent super(DropHereLabel, self).__init__(parent=parent) self.common = common self.setAcceptDrops(True) self.setAlignment(QtCore.Qt.AlignCenter) if image: self.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/logo_transparent.png')))) else: self.setText(strings._('gui_drag_and_drop')) self.setStyleSheet(self.common.css['share_file_selection_drop_here_label']) self.hide()
def __init__(self, common, id, content_length): super(ReceiveHistoryItem, self).__init__() self.common = common self.id = id self.content_length = content_length self.started = datetime.now() self.status = HistoryItem.STATUS_STARTED # Label self.label = QtWidgets.QLabel( strings._('gui_all_modes_transfer_started').format( self.started.strftime("%b %d, %I:%M%p"))) # 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.setValue(0) self.progress_bar.setStyleSheet( self.common.css['downloads_uploads_progress_bar']) # This layout contains file widgets self.files_layout = QtWidgets.QVBoxLayout() self.files_layout.setContentsMargins(0, 0, 0, 0) files_widget = QtWidgets.QWidget() files_widget.setStyleSheet(self.common.css['receive_file']) files_widget.setLayout(self.files_layout) # Layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.progress_bar) layout.addWidget(files_widget) layout.addStretch() self.setLayout(layout) # We're also making a dictionary of file widgets, to make them easier to access self.files = {}