diff options
author | Tomás Touceda <chiiph@leap.se> | 2014-05-29 16:23:23 -0300 |
---|---|---|
committer | Tomás Touceda <chiiph@leap.se> | 2014-05-29 16:23:23 -0300 |
commit | 5eba0d4173ef352ad30d3f04e7d103bce2c202ed (patch) | |
tree | bd5ddcec4ed93c79a8b40942151ea672db6fb9f0 /src/leap/bitmask/gui | |
parent | 7b7e1357fc1e9e64e7c2ee08f762389d7128efc3 (diff) | |
parent | efea398e18f806ad5bb7cec4aa0dcef5f94319bc (diff) |
Merge remote-tracking branch 'refs/remotes/kali/bug/eip-restarts-refactor' into develop
Diffstat (limited to 'src/leap/bitmask/gui')
-rw-r--r-- | src/leap/bitmask/gui/eip_status.py | 186 | ||||
-rw-r--r-- | src/leap/bitmask/gui/mainwindow.py | 428 | ||||
-rw-r--r-- | src/leap/bitmask/gui/statemachines.py | 13 |
3 files changed, 271 insertions, 356 deletions
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index ca28b8bf..04acc167 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -24,7 +24,6 @@ from functools import partial from PySide import QtCore, QtGui -from leap.bitmask.services.eip.connection import EIPConnection from leap.bitmask.services import get_service_display_name, EIP_SERVICE from leap.bitmask.platform_init import IS_LINUX from leap.bitmask.util.averages import RateMovingAverage @@ -43,9 +42,14 @@ class EIPStatusWidget(QtGui.QWidget): RATE_STR = "%1.2f KB/s" TOTAL_STR = "%1.2f Kb" - eip_connection_connected = QtCore.Signal() + def __init__(self, parent=None, eip_conductor=None): + """ + :param parent: the parent of the widget. + :type parent: QObject - def __init__(self, parent=None): + :param eip_conductor: an EIPConductor object. + :type eip_conductor: EIPConductor + """ QtGui.QWidget.__init__(self, parent) self._systray = None @@ -54,7 +58,8 @@ class EIPStatusWidget(QtGui.QWidget): self.ui = Ui_EIPStatus() self.ui.setupUi(self) - self.eipconnection = EIPConnection() + self.eip_conductor = eip_conductor + self.eipconnection = eip_conductor.eip_connection # set systray tooltip status self._eip_status = "" @@ -75,11 +80,36 @@ class EIPStatusWidget(QtGui.QWidget): self._make_status_clickable() self._provider = "" + self.is_restart = False # Action for the systray self._eip_disabled_action = QtGui.QAction( "{0} is {1}".format(self._service_name, self.tr("disabled")), self) + def connect_backend_signals(self): + """ + Connect backend signals. + """ + signaler = self.eip_conductor._backend.signaler + + signaler.eip_openvpn_already_running.connect( + self._on_eip_openvpn_already_running) + signaler.eip_alien_openvpn_already_running.connect( + self._on_eip_alien_openvpn_already_running) + signaler.eip_openvpn_not_found_error.connect( + self._on_eip_openvpn_not_found_error) + signaler.eip_vpn_launcher_exception.connect( + self._on_eip_vpn_launcher_exception) + signaler.eip_no_polkit_agent_error.connect( + self._on_eip_no_polkit_agent_error) + signaler.eip_no_pkexec_error.connect(self._on_eip_no_pkexec_error) + signaler.eip_no_tun_kext_error.connect(self._on_eip_no_tun_kext_error) + + signaler.eip_state_changed.connect(self.update_vpn_state) + signaler.eip_status_changed.connect(self.update_vpn_status) + signaler.eip_network_unreachable.connect( + self._on_eip_network_unreachable) + def _make_status_clickable(self): """ Makes upload and download figures clickable. @@ -238,7 +268,7 @@ class EIPStatusWidget(QtGui.QWidget): def eip_pre_up(self): """ Triggered when the app activates eip. - Hides the status box and disables the start/stop button. + Disables the start/stop button. """ self.set_startstop_enabled(False) @@ -248,7 +278,7 @@ class EIPStatusWidget(QtGui.QWidget): Triggered when a default provider_config has not been found. Disables the start button and adds instructions to the user. """ - #logger.debug('Hiding EIP start button') + logger.debug('Hiding EIP start button') # you might be tempted to change this for a .setEnabled(False). # it won't work. it's under the claws of the state machine. # probably the best thing would be to make a conditional @@ -326,30 +356,51 @@ class EIPStatusWidget(QtGui.QWidget): Sets the state of the widget to how it should look after EIP has started """ - self.ui.btnEipStartStop.setText(self.tr("Turn OFF")) self.ui.btnEipStartStop.disconnect(self) self.ui.btnEipStartStop.clicked.connect( self.eipconnection.qtsigs.do_connect_signal) - # XXX disable ----------------------------- - def eip_stopped(self): + @QtCore.Slot(dict) + def eip_stopped(self, restart=False, failed=False): """ + TRIGGERS: + EIPConductor.qtsigs.disconnected_signal + Sets the state of the widget to how it should look after EIP has stopped """ - # XXX should connect this to EIPConnection.disconnected_signal self._reset_traffic_rates() - # XXX disable ----------------------------- - self.ui.btnEipStartStop.setText(self.tr("Turn ON")) - self.ui.btnEipStartStop.disconnect(self) - self.ui.btnEipStartStop.clicked.connect( - self.eipconnection.qtsigs.do_disconnect_signal) - self.ui.eip_bandwidth.hide() - self.ui.lblEIPMessage.setText( - self.tr("Traffic is being routed in the clear")) + + # XXX FIXME ! ----------------------- this needs to + # accomodate the messages about firewall status. Right now + # we're assuming it works correctly, but we should test fw + # status positively. + # Or better call it from the conductor... + + clear_traffic = self.tr("Traffic is being routed in the clear.") + unreachable_net = self.tr("Network is unreachable.") + failed_msg = self.tr("Cannot start Encrypted Proxy.") + + if restart: + msg = unreachable_net + elif failed: + msg = failed_msg + else: + msg = clear_traffic + self.ui.lblEIPMessage.setText(msg) self.ui.lblEIPStatus.show() + def eip_failed_to_restart(self): + """ + Update EIP messages. + """ + msg = self.tr("Could not restart Encrypted Proxy") + self.ui.lblEIPMessage.setText(msg) + self.ui.lblEIPStatus.show() + + self.set_eip_status(self.tr("You can start the service manually.")) + @QtCore.Slot(dict) def update_vpn_status(self, data=None): """ @@ -407,7 +458,8 @@ class EIPStatusWidget(QtGui.QWidget): self.ui.lblEIPStatus.hide() # XXX should be handled by the state machine too. - self.eip_connection_connected.emit() + # --- is this currently being sent? + self.eipconnection.qtsigs.connected_signal.emit() # XXX should lookup vpn_state map in EIPConnection elif vpn_state == "AUTH": @@ -423,8 +475,9 @@ class EIPStatusWidget(QtGui.QWidget): elif vpn_state == "ALREADYRUNNING": # Put the following calls in Qt's event queue, otherwise # the UI won't update properly + #self.send_disconnect_signal() QtCore.QTimer.singleShot( - 0, self.eipconnection.qtsigs.do_disconnect_signal) + 0, self.eipconnection.qtsigns.do_disconnect_signal.emit) msg = self.tr("Unable to start VPN, it's already running.") QtCore.QTimer.singleShot(0, partial(self.set_eip_status, msg)) else: @@ -470,3 +523,96 @@ class EIPStatusWidget(QtGui.QWidget): self._provider = provider self.ui.lblEIPMessage.setText( self.tr("Route traffic through: {0}").format(self._provider)) + + # + # Slots for signals + # + + @QtCore.Slot() + def _on_eip_connection_aborted(self): + """ + TRIGGERS: + Signaler.eip_connection_aborted + """ + logger.error("Tried to start EIP but cannot find any " + "available provider!") + + eip_status_label = self.tr("Could not load {0} configuration.") + eip_status_label = eip_status_label.format( + self._eip_conductor.eip_name) + self.set_eip_status(eip_status_label, error=True) + + # signal connection_aborted to state machine: + qtsigs = self._eipconnection.qtsigs + qtsigs.connection_aborted_signal.emit() + + def _on_eip_openvpn_already_running(self): + self.set_eip_status( + self.tr("Another openvpn instance is already running, and " + "could not be stopped."), + error=True) + self.set_eipstatus_off() + + def _on_eip_alien_openvpn_already_running(self): + self.set_eip_status( + self.tr("Another openvpn instance is already running, and " + "could not be stopped because it was not launched by " + "Bitmask. Please stop it and try again."), + error=True) + self.set_eipstatus_off() + + def _on_eip_openvpn_not_found_error(self): + self.set_eip_status( + self.tr("We could not find openvpn binary."), + error=True) + self.set_eipstatus_off() + + def _on_eip_vpn_launcher_exception(self): + # XXX We should implement again translatable exceptions so + # we can pass a translatable string to the panel (usermessage attr) + self.set_eip_status("VPN Launcher error.", error=True) + self.set_eipstatus_off() + + def _on_eip_no_polkit_agent_error(self): + self.set_eip_status( + # XXX this should change to polkit-kde where + # applicable. + self.tr("We could not find any authentication agent in your " + "system.<br/>Make sure you have" + "<b>polkit-gnome-authentication-agent-1</b> running and" + "try again."), + error=True) + self.set_eipstatus_off() + + def _on_eip_no_pkexec_error(self): + self.set_eip_status( + self.tr("We could not find <b>pkexec</b> in your system."), + error=True) + self.set_eipstatus_off() + + def _on_eip_no_tun_kext_error(self): + self.set_eip_status( + self.tr("{0} cannot be started because the tuntap extension is " + "not installed properly in your " + "system.").format(self._eip_conductor.eip_name)) + self.set_eipstatus_off() + + @QtCore.Slot() + def _on_eip_network_unreachable(self): + """ + TRIGGERS: + self._eip_connection.qtsigs.network_unreachable + + Displays a "network unreachable" error in the EIP status panel. + """ + self.set_eip_status(self.tr("Network is unreachable"), + error=True) + self.set_eip_status_icon("error") + + def set_eipstatus_off(self, error=True): + # XXX this should be handled by the state machine. + """ + Sets eip status to off + """ + self.set_eip_status("", error=error) + self.set_eip_status_icon("error") diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index fd9a70ac..1d467e60 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -30,7 +30,6 @@ from leap.bitmask import __version_hash__ as VERSION_HASH from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings -from leap.bitmask.gui import statemachines from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement from leap.bitmask.gui.eip_preferenceswindow import EIPPreferencesWindow from leap.bitmask.gui.eip_status import EIPStatusWidget @@ -46,12 +45,10 @@ from leap.bitmask.platform_init.initializers import init_platform from leap.bitmask import backend -from leap.bitmask.services import get_service_display_name - +from leap.bitmask.services.eip import conductor as eip_conductor from leap.bitmask.services.mail import conductor as mail_conductor from leap.bitmask.services import EIP_SERVICE, MX_SERVICE -from leap.bitmask.services.eip.connection import EIPConnection from leap.bitmask.util import make_address from leap.bitmask.util.keyring_helpers import has_keyring @@ -68,6 +65,7 @@ from leap.mail.imap.service.imap import IMAP_PORT from ui_mainwindow import Ui_MainWindow +QtDelayedCall = QtCore.QTimer.singleShot logger = logging.getLogger(__name__) @@ -131,11 +129,16 @@ class MainWindow(QtGui.QMainWindow): self._settings = LeapSettings() + # Login Widget self._login_widget = LoginWidget( self._settings, self) self.ui.loginLayout.addWidget(self._login_widget) + # Mail Widget + self._mail_status = MailStatusWidget(self) + self.ui.mailLayout.addWidget(self._mail_status) + # Qt Signal Connections ##################################### # TODO separate logic from ui signals. @@ -144,34 +147,29 @@ class MainWindow(QtGui.QMainWindow): self._login_widget.show_wizard.connect(self._launch_wizard) self._login_widget.logout.connect(self._logout) - self._eip_status = EIPStatusWidget(self) - self.ui.eipLayout.addWidget(self._eip_status) - self._login_widget.logged_in_signal.connect( - self._eip_status.enable_eip_start) - self._login_widget.logged_in_signal.connect( - self._enable_eip_start_action) + # EIP Control redux ######################################### + self._eip_conductor = eip_conductor.EIPConductor( + self._settings, self._backend) + self._eip_status = EIPStatusWidget(self, self._eip_conductor) - self._mail_status = MailStatusWidget(self) - self.ui.mailLayout.addWidget(self._mail_status) - - self._eip_connection = EIPConnection() - - # XXX this should be handled by EIP Conductor - self._eip_connection.qtsigs.connecting_signal.connect( - self._start_EIP) - self._eip_connection.qtsigs.disconnecting_signal.connect( - self._stop_eip) + self.ui.eipLayout.addWidget(self._eip_status) + self._eip_conductor.add_eip_widget(self._eip_status) - self._eip_status.eip_connection_connected.connect( + self._eip_conductor.connect_signals() + self._eip_conductor.qtsigs.connected_signal.connect( self._on_eip_connection_connected) - self._eip_status.eip_connection_connected.connect( + self._eip_conductor.qtsigs.disconnected_signal.connect( + self._on_eip_connection_disconnected) + self._eip_conductor.qtsigs.connected_signal.connect( self._maybe_run_soledad_setup_checks) + self.offline_mode_bypass_login.connect( self._maybe_run_soledad_setup_checks) self.eip_needs_login.connect(self._eip_status.disable_eip_start) self.eip_needs_login.connect(self._disable_eip_start_action) + self._already_started_eip = False self._trying_to_start_eip = False self._already_started_eip = False @@ -215,8 +213,7 @@ class MainWindow(QtGui.QMainWindow): self._systray = None - # XXX separate actions into a different - # module. + # XXX separate actions into a different module. self._action_mail_status = QtGui.QAction(self.tr("Mail is OFF"), self) self._mail_status.set_action_mail_status(self._action_mail_status) @@ -280,20 +277,19 @@ class MainWindow(QtGui.QMainWindow): # the EIPConductor or some other clever component that we will # instantiate from here. - self.eip_machine = None # start event machines - self.start_eip_machine() + # TODO should encapsulate all actions into one object + self._eip_conductor.start_eip_machine( + action=self._action_eip_startstop) self._mail_conductor.start_mail_machine() - self._eip_name = get_service_display_name(EIP_SERVICE) - if self._first_run(): self._wizard_firstrun = True self._disconnect_and_untrack() self._wizard = Wizard(backend=self._backend, bypass_checks=bypass_checks) # Give this window time to finish init and then show the wizard - QtCore.QTimer.singleShot(1, self._launch_wizard) + QtDelayedCall(1, self._launch_wizard) self._wizard.accepted.connect(self._finish_init) self._wizard.rejected.connect(self._rejected_wizard) else: @@ -351,67 +347,50 @@ class MainWindow(QtGui.QMainWindow): :type only_tracked: bool """ sig = self._backend.signaler + conntrack = self._connect_and_track + auth_err = self._authentication_error - self._connect_and_track(sig.prov_name_resolution, - self._intermediate_stage) - self._connect_and_track(sig.prov_https_connection, - self._intermediate_stage) - self._connect_and_track(sig.prov_download_ca_cert, - self._intermediate_stage) - - self._connect_and_track(sig.prov_download_provider_info, - self._load_provider_config) - self._connect_and_track(sig.prov_check_api_certificate, - self._provider_config_loaded) + conntrack(sig.prov_name_resolution, self._intermediate_stage) + conntrack(sig.prov_https_connection, self._intermediate_stage) + conntrack(sig.prov_download_ca_cert, self._intermediate_stage) + conntrack(sig.prov_download_provider_info, self._load_provider_config) + conntrack(sig.prov_check_api_certificate, self._provider_config_loaded) - self._connect_and_track(sig.prov_problem_with_provider, - self._login_problem_provider) - - self._connect_and_track(sig.prov_cancelled_setup, - self._set_login_cancelled) + conntrack(sig.prov_problem_with_provider, self._login_problem_provider) + conntrack(sig.prov_cancelled_setup, self._set_login_cancelled) self._connect_and_track(sig.prov_get_details, self._provider_get_details) # Login signals - self._connect_and_track(sig.srp_auth_ok, self._authentication_finished) + conntrack(sig.srp_auth_ok, self._authentication_finished) - auth_error = ( - lambda: self._authentication_error(self.tr("Unknown error."))) - self._connect_and_track(sig.srp_auth_error, auth_error) + auth_error = lambda: auth_err(self.tr("Unknown error.")) + conntrack(sig.srp_auth_error, auth_error) - auth_server_error = ( - lambda: self._authentication_error( - self.tr("There was a server problem with authentication."))) - self._connect_and_track(sig.srp_auth_server_error, auth_server_error) + auth_server_error = lambda: auth_err(self.tr( + "There was a server problem with authentication.")) + conntrack(sig.srp_auth_server_error, auth_server_error) - auth_connection_error = ( - lambda: self._authentication_error( - self.tr("Could not establish a connection."))) - self._connect_and_track(sig.srp_auth_connection_error, - auth_connection_error) + auth_connection_error = lambda: auth_err(self.tr( + "Could not establish a connection.")) + conntrack(sig.srp_auth_connection_error, auth_connection_error) - auth_bad_user_or_password = ( - lambda: self._authentication_error( - self.tr("Invalid username or password."))) - self._connect_and_track(sig.srp_auth_bad_user_or_password, - auth_bad_user_or_password) + auth_bad_user_or_password = lambda: auth_err(self.tr( + "Invalid username or password.")) + conntrack(sig.srp_auth_bad_user_or_password, auth_bad_user_or_password) # Logout signals - self._connect_and_track(sig.srp_logout_ok, self._logout_ok) - self._connect_and_track(sig.srp_logout_error, self._logout_error) - - self._connect_and_track(sig.srp_not_logged_in_error, - self._not_logged_in_error) + conntrack(sig.srp_logout_ok, self._logout_ok) + conntrack(sig.srp_logout_error, self._logout_error) + conntrack(sig.srp_not_logged_in_error, self._not_logged_in_error) # EIP bootstrap signals - self._connect_and_track(sig.eip_config_ready, - self._eip_intermediate_stage) - self._connect_and_track(sig.eip_client_certificate_ready, - self._finish_eip_bootstrap) + conntrack(sig.eip_config_ready, self._eip_intermediate_stage) + conntrack(sig.eip_client_certificate_ready, self._finish_eip_bootstrap) ################################################### - # Add tracked signals above this, untracked bellow! + # Add tracked signals above this, untracked below! ################################################### if only_tracked: return @@ -421,38 +400,20 @@ class MainWindow(QtGui.QMainWindow): sig.backend_bad_call.connect(self._backend_bad_call) sig.prov_check_api_certificate.connect(self._get_provider_details) - sig.prov_unsupported_client.connect(self._needs_update) sig.prov_unsupported_api.connect(self._incompatible_api) + sig.prov_get_all_services.connect(self._provider_get_all_services) - sig.prov_get_all_services.connect( - self._provider_get_all_services) - - # EIP start signals - sig.eip_openvpn_already_running.connect( - self._on_eip_openvpn_already_running) - sig.eip_alien_openvpn_already_running.connect( - self._on_eip_alien_openvpn_already_running) - sig.eip_openvpn_not_found_error.connect( - self._on_eip_openvpn_not_found_error) - sig.eip_vpn_launcher_exception.connect( - self._on_eip_vpn_launcher_exception) - sig.eip_no_polkit_agent_error.connect( - self._on_eip_no_polkit_agent_error) - sig.eip_no_pkexec_error.connect(self._on_eip_no_pkexec_error) - sig.eip_no_tun_kext_error.connect(self._on_eip_no_tun_kext_error) - - sig.eip_state_changed.connect(self._eip_status.update_vpn_state) - sig.eip_status_changed.connect(self._eip_status.update_vpn_status) - sig.eip_process_finished.connect(self._eip_finished) - sig.eip_network_unreachable.connect(self._on_eip_network_unreachable) - sig.eip_process_restart_tls.connect(self._do_eip_restart) - sig.eip_process_restart_ping.connect(self._do_eip_restart) + # EIP start signals ============================================== + self._eip_conductor.connect_backend_signals() sig.eip_can_start.connect(self._backend_can_start_eip) sig.eip_cannot_start.connect(self._backend_cannot_start_eip) + # ================================================================== + # Soledad signals + # TODO delegate connection to soledad bootstrapper sig.soledad_bootstrap_failed.connect( self._mail_status.set_soledad_failed) sig.soledad_bootstrap_finished.connect(self._on_soledad_ready) @@ -919,7 +880,8 @@ class MainWindow(QtGui.QMainWindow): systrayMenu.addAction(self._action_visible) systrayMenu.addSeparator() - eip_status_label = "{0}: {1}".format(self._eip_name, self.tr("OFF")) + eip_status_label = "{0}: {1}".format( + self._eip_conductor.eip_name, self.tr("OFF")) self._eip_menu = eip_menu = systrayMenu.addMenu(eip_status_label) eip_menu.addAction(self._action_eip_startstop) self._eip_status.set_eip_status_menu(eip_menu) @@ -1001,7 +963,7 @@ class MainWindow(QtGui.QMainWindow): # Wait a bit until the window visibility has changed so # the menu is set with the correct value. - QtCore.QTimer.singleShot(500, self._update_hideshow_menu) + QtDelayedCall(500, self._update_hideshow_menu) def _center_window(self): """ @@ -1398,7 +1360,7 @@ class MainWindow(QtGui.QMainWindow): """ # TODO split. if not self._provides_mx_and_enabled() and not flags.OFFLINE: - logger.debug("Does not provides and enabled MX") + logger.debug("Provider does not offer MX, but it is enabled.") return username = self._login_widget.get_user() @@ -1473,21 +1435,6 @@ class MainWindow(QtGui.QMainWindow): ################################################################### # Service control methods: eip - def start_eip_machine(self): - """ - Initializes and starts the EIP state machine - """ - button = self._eip_status.eip_button - action = self._action_eip_startstop - label = self._eip_status.eip_label - builder = statemachines.ConnectionMachineBuilder(self._eip_connection) - eip_machine = builder.make_machine(button=button, - action=action, - label=label) - self.eip_machine = eip_machine - self.eip_machine.start() - logger.debug('eip machine started') - @QtCore.Slot() def _disable_eip_start_action(self): """ @@ -1506,17 +1453,14 @@ class MainWindow(QtGui.QMainWindow): def _on_eip_connection_connected(self): """ TRIGGERS: - self._eip_status.eip_connection_connected - - Emits the EIPConnection.qtsigs.connected_signal + self._eip_conductor.qtsigs.connected_signal This is a little workaround for connecting the vpn-connected signal that currently is beeing processed under status_panel. After the refactor to EIPConductor this should not be necessary. """ - self._eip_connection.qtsigs.connected_signal.emit() - domain = self._login_widget.get_selected_provider() + self._eip_status.set_provider(domain) self._settings.set_defaultprovider(domain) self._already_started_eip = True @@ -1524,7 +1468,29 @@ class MainWindow(QtGui.QMainWindow): # check for connectivity self._check_name_resolution(domain) + @QtCore.Slot() + def _on_eip_connection_disconnected(self): + """ + TRIGGERS: + self._eip_conductor.qtsigs.disconnected_signal + + Workaround for updating the eip_status widget with + the provider when the eip connection disconnects. + """ + # TODO + # We should move this to the conductor<->widget interface. + # To do that, we need to subscribe to logged_user, + # for example by using the observer pattern or a proxy object. + user = self._logged_user + if user: + domain = self._login_widget.get_selected_provider() + full_user_id = make_address(user, domain) + self._eip_status.set_provider(full_user_id) + def _check_name_resolution(self, domain): + # FIXME this has to be moved to backend !!! + # Should move to netchecks module. + # and separate qt from reactor... """ Check if we can resolve the given domain name. @@ -1555,7 +1521,7 @@ class MainWindow(QtGui.QMainWindow): "missing some helper files that are needed to securely use " "DNS while {1} is active. To install these helper files, quit " "this application and start it again." - ).format(domain, self._eip_name) + ).format(domain, self._eip_conductor.eip_name) show_err = lambda: QtGui.QMessageBox.critical( self, self.tr("Connection Error"), msg) @@ -1580,211 +1546,6 @@ class MainWindow(QtGui.QMainWindow): if settings.get_autostart_eip(): self._maybe_start_eip(autostart=True) - @QtCore.Slot() - def _start_EIP(self): - """ - Starts EIP - """ - self._eip_status.eip_pre_up() - self.user_stopped_eip = False - - # Until we set an option in the preferences window, we'll assume that - # by default we try to autostart. If we switch it off manually, it - # won't try the next time. - self._settings.set_autostart_eip(True) - - self._backend.eip_start() - - @QtCore.Slot() - def _on_eip_connection_aborted(self): - """ - TRIGGERS: - Signaler.eip_connection_aborted - """ - logger.error("Tried to start EIP but cannot find any " - "available provider!") - - eip_status_label = self.tr("Could not load {0} configuration.") - eip_status_label = eip_status_label.format(self._eip_name) - self._eip_status.set_eip_status(eip_status_label, error=True) - - # signal connection_aborted to state machine: - qtsigs = self._eip_connection.qtsigs - qtsigs.connection_aborted_signal.emit() - - def _on_eip_openvpn_already_running(self): - self._eip_status.set_eip_status( - self.tr("Another openvpn instance is already running, and " - "could not be stopped."), - error=True) - self._set_eipstatus_off() - - def _on_eip_alien_openvpn_already_running(self): - self._eip_status.set_eip_status( - self.tr("Another openvpn instance is already running, and " - "could not be stopped because it was not launched by " - "Bitmask. Please stop it and try again."), - error=True) - self._set_eipstatus_off() - - def _on_eip_openvpn_not_found_error(self): - self._eip_status.set_eip_status( - self.tr("We could not find openvpn binary."), - error=True) - self._set_eipstatus_off() - - def _on_eip_vpn_launcher_exception(self): - # XXX We should implement again translatable exceptions so - # we can pass a translatable string to the panel (usermessage attr) - self._eip_status.set_eip_status("VPN Launcher error.", error=True) - self._set_eipstatus_off() - - def _on_eip_no_polkit_agent_error(self): - self._eip_status.set_eip_status( - # XXX this should change to polkit-kde where - # applicable. - self.tr("We could not find any authentication agent in your " - "system.<br/>Make sure you have" - "<b>polkit-gnome-authentication-agent-1</b> running and" - "try again."), - error=True) - self._set_eipstatus_off() - - def _on_eip_no_pkexec_error(self): - self._eip_status.set_eip_status( - self.tr("We could not find <b>pkexec</b> in your system."), - error=True) - self._set_eipstatus_off() - - def _on_eip_no_tun_kext_error(self): - self._eip_status.set_eip_status( - self.tr("{0} cannot be started because the tuntap extension is " - "not installed properly in your " - "system.").format(self._eip_name)) - self._set_eipstatus_off() - - @QtCore.Slot() - def _stop_eip(self, restart=False): - """ - TRIGGERS: - self._eip_connection.qtsigs.do_disconnect_signal (via state machine) - - Stops vpn process and makes gui adjustments to reflect - the change of state. - - :param abnormal: whether this was an abnormal termination. - :type abnormal: bool - """ - self.user_stopped_eip = not restart - self._backend.eip_stop(restart=restart) - - self._set_eipstatus_off(False) - self._already_started_eip = False - - logger.debug('Setting autostart to: False') - self._settings.set_autostart_eip(False) - - user = self._logged_user - if user: - domain = self._login_widget.get_selected_provider() - full_user_id = make_address(user, domain) - self._eip_status.set_provider(full_user_id) - - self._eip_status.eip_stopped() - - @QtCore.Slot() - def _on_eip_network_unreachable(self): - # XXX Should move to EIP Conductor - """ - TRIGGERS: - self._eip_connection.qtsigs.network_unreachable - - Displays a "network unreachable" error in the EIP status panel. - """ - self._eip_status.set_eip_status(self.tr("Network is unreachable"), - error=True) - self._eip_status.set_eip_status_icon("error") - - @QtCore.Slot() - def _do_eip_restart(self): - # XXX Should move to EIP Conductor - """ - TRIGGERS: - self._eip_connection.qtsigs.process_restart - - Restart the connection. - """ - # for some reason, emitting the do_disconnect/do_connect - # signals hangs the UI. - self._stop_eip(restart=True) - QtCore.QTimer.singleShot(2000, self._start_EIP) - - def _set_eipstatus_off(self, error=True): - """ - Sets eip status to off - """ - # XXX this should be handled by the state machine. - self._eip_status.set_eip_status("", error=error) - self._eip_status.set_eip_status_icon("error") - - @QtCore.Slot(int) - def _eip_finished(self, exitCode): - """ - TRIGGERS: - Signaler.eip_process_finished - - Triggered when the EIP/VPN process finishes to set the UI - accordingly. - - Ideally we would have the right exit code here, - but the use of different wrappers (pkexec, cocoasudo) swallows - the openvpn exit code so we get zero exit in some cases where we - shouldn't. As a workaround we just use a flag to indicate - a purposeful switch off, and mark everything else as unexpected. - - In the near future we should trigger a native notification from here, - since the user really really wants to know she is unprotected asap. - And the right thing to do will be to fail-close. - - :param exitCode: the exit code of the eip process. - :type exitCode: int - """ - # TODO move to EIPConductor. - # TODO Add error catching to the openvpn log observer - # so we can have a more precise idea of which type - # of error did we have (server side, local problem, etc) - - logger.info("VPN process finished with exitCode %s..." - % (exitCode,)) - - qtsigs = self._eip_connection.qtsigs - signal = qtsigs.disconnected_signal - - # XXX check if these exitCodes are pkexec/cocoasudo specific - if exitCode in (126, 127): - eip_status_label = self.tr( - "{0} could not be launched " - "because you did not authenticate properly.") - eip_status_label = eip_status_label.format(self._eip_name) - self._eip_status.set_eip_status(eip_status_label, error=True) - signal = qtsigs.connection_aborted_signal - self._backend.eip_terminate() - - elif exitCode != 0 or not self.user_stopped_eip: - eip_status_label = self.tr("{0} finished in an unexpected manner!") - eip_status_label = eip_status_label.format(self._eip_name) - self._eip_status.eip_stopped() - self._eip_status.set_eip_status_icon("error") - self._eip_status.set_eip_status(eip_status_label, error=True) - signal = qtsigs.connection_died_signal - - if exitCode == 0 and IS_MAC: - # XXX remove this warning after I fix cocoasudo. - logger.warning("The above exit code MIGHT BE WRONG.") - - # We emit signals to trigger transitions in the state machine: - signal.emit() - # eip boostrapping, config etc... def _maybe_start_eip(self, autostart=False): @@ -1812,9 +1573,8 @@ class MainWindow(QtGui.QMainWindow): self._already_started_eip = True # we want to start soledad anyway after a certain timeout if eip # fails to come up - QtCore.QTimer.singleShot( - self.EIP_START_TIMEOUT, - self._maybe_run_soledad_setup_checks) + QtDelayedCall(self.EIP_START_TIMEOUT, + self._maybe_run_soledad_setup_checks) else: if not self._already_started_eip: if EIP_SERVICE in self._enabled_services: @@ -1833,8 +1593,8 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self._backend.signaler.eip_client_certificate_ready - Starts the VPN thread if the eip configuration is properly - loaded + Start the VPN thread if the eip configuration is properly + loaded. """ passed = data[self._backend.PASSED_KEY] @@ -1846,11 +1606,11 @@ class MainWindow(QtGui.QMainWindow): return # DO START EIP Connection! - self._eip_connection.qtsigs.do_connect_signal.emit() + self._eip_conductor.do_connect() @QtCore.Slot(dict) def _eip_intermediate_stage(self, data): - # TODO missing param + # TODO missing param documentation """ TRIGGERS: self._backend.signaler.eip_config_ready @@ -2004,7 +1764,7 @@ class MainWindow(QtGui.QMainWindow): if self._systray is not None: self._systray.showMessage( self.tr('Quitting...'), - self.tr('The app is quitting, please wait.')) + self.tr('Bitmask is quitting, please wait.')) # explicitly process events to display tooltip immediately QtCore.QCoreApplication.processEvents(0, 10) diff --git a/src/leap/bitmask/gui/statemachines.py b/src/leap/bitmask/gui/statemachines.py index 31938a70..f8e5479d 100644 --- a/src/leap/bitmask/gui/statemachines.py +++ b/src/leap/bitmask/gui/statemachines.py @@ -504,6 +504,11 @@ class ConnectionMachineBuilder(object): conn.qtsigs.connection_died_signal, states[_OFF]) + # XXX adding this--------------------- + states[_ON].addTransition( + conn.qtsigs.do_disconnect_signal, + states[_DIS]) + # * If we receive the connection_aborted, we transition # from connecting to the off state states[_CON].addTransition( @@ -551,7 +556,8 @@ class ConnectionMachineBuilder(object): # TODO add tooltip # OFF State ---------------------- - off = QState() + off = SignallingState( + None, name=conn.name) off_label = _tr("Turn {0}").format( conn.Connected.short_label) if button: @@ -587,7 +593,10 @@ class ConnectionMachineBuilder(object): states[_CON] = connecting # ON State ------------------------ - on = QState() + on = SignallingState( + None, name=conn.name) + on_label = _tr("Turn {0}").format( + conn.Disconnected.short_label) if button: on.assignProperty( button, 'text', on_label) |