diff options
Diffstat (limited to 'desktop/onionshare/tab/mode/receive_mode/__init__.py')
-rw-r--r-- | desktop/onionshare/tab/mode/receive_mode/__init__.py | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/desktop/onionshare/tab/mode/receive_mode/__init__.py b/desktop/onionshare/tab/mode/receive_mode/__init__.py new file mode 100644 index 00000000..b2b2fc5a --- /dev/null +++ b/desktop/onionshare/tab/mode/receive_mode/__init__.py @@ -0,0 +1,427 @@ +# -*- coding: utf-8 -*- +""" +OnionShare | https://onionshare.org/ + +Copyright (C) 2014-2021 Micah Lee, et al. <micah@micahflee.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +""" + +import os +from PySide2 import QtCore, QtWidgets, QtGui + +from onionshare_cli.web import Web + +from ..history import History, ToggleHistory, ReceiveHistoryItem +from .. import Mode +from .... import strings +from ....widgets import MinimumSizeWidget, Alert +from ....gui_common import GuiCommon + + +class ReceiveMode(Mode): + """ + Parts of the main window UI for receiving files. + """ + + def init(self): + """ + Custom initialization for ReceiveMode. + """ + # Create the Web object + self.web = Web(self.common, True, self.settings, "receive") + + # Receive image + self.image_label = QtWidgets.QLabel() + self.image_label.setPixmap( + QtGui.QPixmap.fromImage( + QtGui.QImage( + GuiCommon.get_resource_path( + "images/{}_mode_receive.png".format(self.common.gui.color_mode) + ) + ) + ) + ) + self.image_label.setFixedSize(250, 250) + image_layout = QtWidgets.QVBoxLayout() + image_layout.addWidget(self.image_label) + self.image = QtWidgets.QWidget() + self.image.setLayout(image_layout) + + # Settings + + # Data dir + data_dir_label = QtWidgets.QLabel( + strings._("mode_settings_receive_data_dir_label") + ) + self.data_dir_lineedit = QtWidgets.QLineEdit() + self.data_dir_lineedit.setReadOnly(True) + self.data_dir_lineedit.setText(self.settings.get("receive", "data_dir")) + data_dir_button = QtWidgets.QPushButton( + strings._("mode_settings_receive_data_dir_browse_button") + ) + data_dir_button.clicked.connect(self.data_dir_button_clicked) + data_dir_layout = QtWidgets.QHBoxLayout() + data_dir_layout.addWidget(data_dir_label) + data_dir_layout.addWidget(self.data_dir_lineedit) + data_dir_layout.addWidget(data_dir_button) + self.mode_settings_widget.mode_specific_layout.addLayout(data_dir_layout) + + # Disable text or files + self.disable_text_checkbox = self.settings.get("receive", "disable_files") + self.disable_text_checkbox = QtWidgets.QCheckBox() + self.disable_text_checkbox.clicked.connect(self.disable_text_checkbox_clicked) + self.disable_text_checkbox.setText( + strings._("mode_settings_receive_disable_text_checkbox") + ) + self.disable_files_checkbox = self.settings.get("receive", "disable_files") + self.disable_files_checkbox = QtWidgets.QCheckBox() + self.disable_files_checkbox.clicked.connect(self.disable_files_checkbox_clicked) + self.disable_files_checkbox.setText( + strings._("mode_settings_receive_disable_files_checkbox") + ) + disable_layout = QtWidgets.QHBoxLayout() + disable_layout.addWidget(self.disable_text_checkbox) + disable_layout.addWidget(self.disable_files_checkbox) + disable_layout.addStretch() + self.mode_settings_widget.mode_specific_layout.addLayout(disable_layout) + + # Webhook URL + webhook_url = self.settings.get("receive", "webhook_url") + self.webhook_url_checkbox = QtWidgets.QCheckBox() + self.webhook_url_checkbox.clicked.connect(self.webhook_url_checkbox_clicked) + self.webhook_url_checkbox.setText( + strings._("mode_settings_receive_webhook_url_checkbox") + ) + self.webhook_url_lineedit = QtWidgets.QLineEdit() + self.webhook_url_lineedit.editingFinished.connect( + self.webhook_url_editing_finished + ) + self.webhook_url_lineedit.setPlaceholderText( + "https://example.com/post-when-file-uploaded" + ) + webhook_url_layout = QtWidgets.QHBoxLayout() + webhook_url_layout.addWidget(self.webhook_url_checkbox) + webhook_url_layout.addWidget(self.webhook_url_lineedit) + if webhook_url is not None and webhook_url != "": + self.webhook_url_checkbox.setCheckState(QtCore.Qt.Checked) + self.webhook_url_lineedit.setText( + self.settings.get("receive", "webhook_url") + ) + self.show_webhook_url() + else: + self.webhook_url_checkbox.setCheckState(QtCore.Qt.Unchecked) + self.hide_webhook_url() + self.mode_settings_widget.mode_specific_layout.addLayout(webhook_url_layout) + + # Set title placeholder + self.mode_settings_widget.title_lineedit.setPlaceholderText( + strings._("gui_tab_name_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( + GuiCommon.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(GuiCommon.get_resource_path("images/receive_icon_toggle.png")), + QtGui.QIcon( + GuiCommon.get_resource_path("images/receive_icon_toggle_selected.png") + ), + ) + + # Header + header_label = QtWidgets.QLabel(strings._("gui_new_tab_receive_button")) + header_label.setStyleSheet(self.common.gui.css["mode_header_label"]) + + # 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.addWidget(header_label) + self.main_layout.addWidget(receive_warning) + self.main_layout.addWidget(self.primary_action, stretch=1) + self.main_layout.addWidget(self.server_status) + + # Row layout + content_row = QtWidgets.QHBoxLayout() + content_row.addLayout(self.main_layout, stretch=1) + content_row.addWidget(self.image) + row_layout = QtWidgets.QVBoxLayout() + row_layout.addLayout(top_bar_layout) + row_layout.addLayout(content_row, stretch=1) + + # Column layout + self.column_layout = QtWidgets.QHBoxLayout() + self.column_layout.addLayout(row_layout) + self.column_layout.addWidget(self.history, stretch=1) + + # Content layout + self.content_layout.addLayout(self.column_layout) + + def get_type(self): + """ + Returns the type of mode as a string (e.g. "share", "receive", etc.) + """ + return "receive" + + def data_dir_button_clicked(self): + """ + Browse for a new OnionShare data directory, and save to tab settings + """ + data_dir = self.data_dir_lineedit.text() + selected_dir = QtWidgets.QFileDialog.getExistingDirectory( + self, strings._("mode_settings_receive_data_dir_label"), data_dir + ) + + if selected_dir: + # If we're running inside a flatpak package, the data dir must be inside ~/OnionShare + if self.common.gui.is_flatpak: + if not selected_dir.startswith(os.path.expanduser("~/OnionShare")): + Alert(self.common, strings._("gui_receive_flatpak_data_dir")) + return + + self.common.log( + "ReceiveMode", + "data_dir_button_clicked", + f"selected dir: {selected_dir}", + ) + self.data_dir_lineedit.setText(selected_dir) + self.settings.set("receive", "data_dir", selected_dir) + + def disable_text_checkbox_clicked(self): + self.settings.set( + "receive", "disable_text", self.disable_text_checkbox.isChecked() + ) + + def disable_files_checkbox_clicked(self): + self.settings.set( + "receive", "disable_files", self.disable_files_checkbox.isChecked() + ) + + def webhook_url_checkbox_clicked(self): + if self.webhook_url_checkbox.isChecked(): + if self.settings.get("receive", "webhook_url"): + self.webhook_url_lineedit.setText( + self.settings.get("receive", "webhook_url") + ) + self.show_webhook_url() + else: + self.settings.set("receive", "webhook_url", None) + self.hide_webhook_url() + + def webhook_url_editing_finished(self): + self.settings.set("receive", "webhook_url", self.webhook_url_lineedit.text()) + + def hide_webhook_url(self): + self.webhook_url_lineedit.hide() + + def show_webhook_url(self): + self.webhook_url_lineedit.show() + + def get_stop_server_autostop_timer_text(self): + """ + Return the string to put on the stop server button, if there's an auto-stop timer + """ + return strings._("gui_receive_stop_server_autostop_timer") + + def autostop_timer_finished_should_stop_server(self): + """ + The auto-stop timer expired, should we stop the server? Returns a bool + """ + # If there were no attempts to upload files, or all uploads are done, we can stop + if ( + self.web.receive_mode.cur_history_id == 0 + or not self.web.receive_mode.uploads_in_progress + ): + 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 start_server_custom(self): + """ + Starting the server. + """ + # Reset web counters + self.web.receive_mode.cur_history_id = 0 + + # Hide and reset the uploads if we have previously shared + self.reset_info_counters() + + # Set proxies for webhook URL + if self.common.gui.local_only: + self.web.proxies = None + else: + (socks_address, socks_port) = self.common.gui.onion.get_tor_socks_port() + self.web.proxies = { + "http": f"socks5h://{socks_address}:{socks_port}", + "https": f"socks5h://{socks_address}:{socks_port}", + } + + def start_server_step2_custom(self): + """ + Step 2 in starting the server. + """ + # Continue + self.starting_server_step3.emit() + self.start_server_finished.emit() + + def handle_tor_broke_custom(self): + """ + Connection to Tor broke. + """ + self.primary_action.hide() + + def handle_request_load(self, event): + """ + Handle REQUEST_LOAD event. + """ + self.system_tray.showMessage( + strings._("systray_page_loaded_title"), + strings._("systray_page_loaded_message"), + ) + + def handle_request_started(self, event): + """ + Handle REQUEST_STARTED event. + """ + item = ReceiveHistoryItem( + self.common, + event["data"]["id"], + event["data"]["content_length"], + ) + + 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_progress(self, event): + """ + Handle REQUEST_PROGRESS event. + """ + self.history.update( + event["data"]["id"], + {"action": "progress", "progress": event["data"]["progress"]}, + ) + + def handle_request_upload_includes_message(self, event): + """ + Handle REQUEST_UPLOAD_INCLUDES_MESSAGE event. + """ + self.history.includes_message(event["data"]["id"], event["data"]["filename"]) + + def handle_request_upload_file_renamed(self, event): + """ + Handle REQUEST_UPLOAD_FILE_RENAMED event. + """ + self.history.update( + event["data"]["id"], + { + "action": "rename", + "old_filename": event["data"]["old_filename"], + "new_filename": event["data"]["new_filename"], + }, + ) + + def handle_request_upload_set_dir(self, event): + """ + Handle REQUEST_UPLOAD_SET_DIR event. + """ + self.history.update( + event["data"]["id"], + { + "action": "set_dir", + "filename": event["data"]["filename"], + "dir": event["data"]["dir"], + }, + ) + + def handle_request_upload_finished(self, event): + """ + Handle REQUEST_UPLOAD_FINISHED event. + """ + self.history.update(event["data"]["id"], {"action": "finished"}) + self.history.completed_count += 1 + self.history.in_progress_count -= 1 + self.history.update_completed() + self.history.update_in_progress() + + def handle_request_upload_canceled(self, event): + """ + Handle REQUEST_UPLOAD_CANCELED event. + """ + self.history.update(event["data"]["id"], {"action": "canceled"}) + self.history.in_progress_count -= 1 + self.history.update_in_progress() + + def on_reload_settings(self): + """ + We should be ok to re-enable the 'Start Receive Mode' button now. + """ + self.primary_action.show() + + def reset_info_counters(self): + """ + Set the info counters back to zero. + """ + self.history.reset() + self.toggle_history.indicator_count = 0 + self.toggle_history.update_indicator() + + def update_primary_action(self): + self.common.log("ReceiveMode", "update_primary_action") |