summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/gui
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2013-10-04 12:09:58 -0300
committerTomás Touceda <chiiph@leap.se>2013-10-04 12:09:58 -0300
commit584866689560bd2ebea01ecc5e6ae5e79ce7fc81 (patch)
tree4fe300c3c105e17721f79eeece9bbd3745b43d78 /src/leap/bitmask/gui
parent1f0f8efc4cb985c082b3b8fe7b3dc45aed047a47 (diff)
parent759d73ae0728f074e0fb0740269249d0e5066574 (diff)
Merge branch 'release-0.3.4'0.3.4
Diffstat (limited to 'src/leap/bitmask/gui')
-rw-r--r--src/leap/bitmask/gui/clickablelabel.py28
-rw-r--r--src/leap/bitmask/gui/eip_preferenceswindow.py218
-rw-r--r--src/leap/bitmask/gui/eip_status.py435
-rw-r--r--src/leap/bitmask/gui/login.py131
-rw-r--r--src/leap/bitmask/gui/mail_status.py408
-rw-r--r--src/leap/bitmask/gui/mainwindow.py389
-rw-r--r--src/leap/bitmask/gui/preferenceswindow.py122
-rw-r--r--src/leap/bitmask/gui/statemachines.py16
-rw-r--r--src/leap/bitmask/gui/statuspanel.py710
-rw-r--r--src/leap/bitmask/gui/ui/eip_status.ui287
-rw-r--r--src/leap/bitmask/gui/ui/eippreferences.ui183
-rw-r--r--src/leap/bitmask/gui/ui/login.ui302
-rw-r--r--src/leap/bitmask/gui/ui/mail_status.ui98
-rw-r--r--src/leap/bitmask/gui/ui/mainwindow.ui437
-rw-r--r--src/leap/bitmask/gui/ui/preferences.ui175
-rw-r--r--src/leap/bitmask/gui/ui/statuspanel.ui393
-rw-r--r--src/leap/bitmask/gui/ui/wizard.ui186
-rw-r--r--src/leap/bitmask/gui/wizard.py79
18 files changed, 2763 insertions, 1834 deletions
diff --git a/src/leap/bitmask/gui/clickablelabel.py b/src/leap/bitmask/gui/clickablelabel.py
new file mode 100644
index 00000000..2808a601
--- /dev/null
+++ b/src/leap/bitmask/gui/clickablelabel.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# clickablelabel.py
+# Copyright (C) 2013 LEAP
+#
+# 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/>.
+
+"""
+Clickable label
+"""
+from PySide import QtCore, QtGui
+
+
+class ClickableLabel(QtGui.QLabel):
+ clicked = QtCore.Signal()
+
+ def mousePressEvent(self, event):
+ self.clicked.emit()
diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py
new file mode 100644
index 00000000..9f8c4ff4
--- /dev/null
+++ b/src/leap/bitmask/gui/eip_preferenceswindow.py
@@ -0,0 +1,218 @@
+# -*- coding: utf-8 -*-
+# eip_preferenceswindow.py
+# Copyright (C) 2013 LEAP
+#
+# 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/>.
+
+"""
+EIP Preferences window
+"""
+import os
+import logging
+
+from functools import partial
+from PySide import QtGui
+
+from leap.bitmask.config.leapsettings import LeapSettings
+from leap.bitmask.config.providerconfig import ProviderConfig
+from leap.bitmask.gui.ui_eippreferences import Ui_EIPPreferences
+from leap.bitmask.services.eip.eipconfig import EIPConfig, VPNGatewaySelector
+
+logger = logging.getLogger(__name__)
+
+
+class EIPPreferencesWindow(QtGui.QDialog):
+ """
+ Window that displays the EIP preferences.
+ """
+ def __init__(self, parent):
+ """
+ :param parent: parent object of the EIPPreferencesWindow.
+ :parent type: QWidget
+ """
+ QtGui.QDialog.__init__(self, parent)
+ self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic")
+
+ self._settings = LeapSettings()
+
+ # Load UI
+ self.ui = Ui_EIPPreferences()
+ self.ui.setupUi(self)
+ self.ui.lblProvidersGatewayStatus.setVisible(False)
+ self.ui.lblAutoStartEIPStatus.setVisible(False)
+
+ # Connections
+ self.ui.cbProvidersGateway.currentIndexChanged[unicode].connect(
+ self._populate_gateways)
+
+ self.ui.cbGateways.currentIndexChanged[unicode].connect(
+ lambda x: self.ui.lblProvidersGatewayStatus.setVisible(False))
+
+ self.ui.cbProvidersEIP.currentIndexChanged[unicode].connect(
+ lambda x: self.ui.lblAutoStartEIPStatus.setVisible(False))
+
+ self.ui.cbAutoStartEIP.toggled.connect(
+ lambda x: self.ui.lblAutoStartEIPStatus.setVisible(False))
+
+ self.ui.pbSaveAutoStartEIP.clicked.connect(self._save_auto_start_eip)
+
+ self._add_configured_providers()
+
+ # Load auto start EIP settings
+ self.ui.cbAutoStartEIP.setChecked(self._settings.get_autostart_eip())
+ default_provider = self._settings.get_defaultprovider()
+ idx = self.ui.cbProvidersEIP.findText(default_provider)
+ self.ui.cbProvidersEIP.setCurrentIndex(idx)
+
+ def _save_auto_start_eip(self):
+ """
+ SLOT
+ TRIGGER:
+ self.ui.cbAutoStartEIP.toggled
+
+ Saves the automatic start of EIP user preference.
+ """
+ default_provider = self.ui.cbProvidersEIP.currentText()
+ enabled = self.ui.cbAutoStartEIP.isChecked()
+
+ self._settings.set_autostart_eip(enabled)
+ self._settings.set_defaultprovider(default_provider)
+
+ self.ui.lblAutoStartEIPStatus.show()
+ logger.debug('Auto start EIP saved: {0} {1}.'.format(
+ default_provider, enabled))
+
+ def _set_providers_gateway_status(self, status, success=False,
+ error=False):
+ """
+ Sets the status label for the gateway change.
+
+ :param status: status message to display, can be HTML
+ :type status: str
+ :param success: is set to True if we should display the
+ message as green
+ :type success: bool
+ :param error: is set to True if we should display the
+ message as red
+ :type error: bool
+ """
+ if success:
+ status = "<font color='green'><b>%s</b></font>" % (status,)
+ elif error:
+ status = "<font color='red'><b>%s</b></font>" % (status,)
+
+ self.ui.lblProvidersGatewayStatus.setVisible(True)
+ self.ui.lblProvidersGatewayStatus.setText(status)
+
+ def _add_configured_providers(self):
+ """
+ Add the client's configured providers to the providers combo boxes.
+ """
+ self.ui.cbProvidersGateway.clear()
+ self.ui.cbProvidersEIP.clear()
+ providers = self._settings.get_configured_providers()
+ if not providers:
+ self.ui.gbAutomaticEIP.setEnabled(False)
+ self.ui.gbGatewaySelector.setEnabled(False)
+ return
+
+ for provider in providers:
+ self.ui.cbProvidersGateway.addItem(provider)
+ self.ui.cbProvidersEIP.addItem(provider)
+
+ def _save_selected_gateway(self, provider):
+ """
+ SLOT
+ TRIGGERS:
+ self.ui.pbSaveGateway.clicked
+
+ Saves the new gateway setting to the configuration file.
+
+ :param provider: the provider config that we need to save.
+ :type provider: str
+ """
+ gateway = self.ui.cbGateways.currentText()
+
+ if gateway == self.AUTOMATIC_GATEWAY_LABEL:
+ gateway = self._settings.GATEWAY_AUTOMATIC
+ else:
+ idx = self.ui.cbGateways.currentIndex()
+ gateway = self.ui.cbGateways.itemData(idx)
+
+ self._settings.set_selected_gateway(provider, gateway)
+
+ msg = self.tr(
+ "Gateway settings for provider '{0}' saved.").format(provider)
+ self._set_providers_gateway_status(msg, success=True)
+
+ def _populate_gateways(self, domain):
+ """
+ SLOT
+ TRIGGERS:
+ self.ui.cbProvidersGateway.currentIndexChanged[unicode]
+
+ Loads the gateways that the provider provides into the UI for
+ the user to select.
+
+ :param domain: the domain of the provider to load gateways from.
+ :type domain: str
+ """
+ # We hide the maybe-visible status label after a change
+ self.ui.lblProvidersGatewayStatus.setVisible(False)
+
+ if not domain:
+ return
+
+ try:
+ # disconnect previously connected save method
+ self.ui.pbSaveGateway.clicked.disconnect()
+ except RuntimeError:
+ pass # Signal was not connected
+
+ # set the proper connection for the 'save' button
+ save_gateway = partial(self._save_selected_gateway, domain)
+ self.ui.pbSaveGateway.clicked.connect(save_gateway)
+
+ eip_config = EIPConfig()
+ provider_config = ProviderConfig.get_provider_config(domain)
+
+ eip_config_path = os.path.join("leap", "providers",
+ domain, "eip-service.json")
+ api_version = provider_config.get_api_version()
+ eip_config.set_api_version(api_version)
+ eip_loaded = eip_config.load(eip_config_path)
+
+ if not eip_loaded or provider_config is None:
+ self._set_providers_gateway_status(
+ self.tr("There was a problem with configuration files."),
+ error=True)
+ return
+
+ gateways = VPNGatewaySelector(eip_config).get_gateways_list()
+ logger.debug(gateways)
+
+ self.ui.cbGateways.clear()
+ self.ui.cbGateways.addItem(self.AUTOMATIC_GATEWAY_LABEL)
+
+ # Add the available gateways and
+ # select the one stored in configuration file.
+ selected_gateway = self._settings.get_selected_gateway(domain)
+ index = 0
+ for idx, (gw_name, gw_ip) in enumerate(gateways):
+ gateway = "{0} ({1})".format(gw_name, gw_ip)
+ self.ui.cbGateways.addItem(gateway, gw_ip)
+ if gw_ip == selected_gateway:
+ index = idx + 1
+
+ self.ui.cbGateways.setCurrentIndex(index)
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
new file mode 100644
index 00000000..946eaa4e
--- /dev/null
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -0,0 +1,435 @@
+# -*- coding: utf-8 -*-
+# eip_status.py
+# Copyright (C) 2013 LEAP
+#
+# 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/>.
+"""
+EIP Status Panel widget implementation
+"""
+import logging
+
+from datetime import datetime
+from functools import partial
+
+from PySide import QtCore, QtGui
+
+from leap.bitmask.services.eip.connection import EIPConnection
+from leap.bitmask.services.eip.vpnprocess import VPNManager
+from leap.bitmask.platform_init import IS_LINUX
+from leap.bitmask.util.averages import RateMovingAverage
+from leap.common.check import leap_assert_type
+
+from ui_eip_status import Ui_EIPStatus
+
+logger = logging.getLogger(__name__)
+
+
+class EIPStatusWidget(QtGui.QWidget):
+ """
+ EIP Status widget that displays the current state of the EIP service
+ """
+ DISPLAY_TRAFFIC_RATES = True
+ RATE_STR = "%14.2f KB/s"
+ TOTAL_STR = "%14.2f Kb"
+
+ eip_connection_connected = QtCore.Signal()
+
+ def __init__(self, parent=None):
+ QtGui.QWidget.__init__(self, parent)
+
+ self._systray = None
+ self._eip_status_menu = None
+
+ self.ui = Ui_EIPStatus()
+ self.ui.setupUi(self)
+
+ self.eipconnection = EIPConnection()
+
+ # set systray tooltip status
+ self._eip_status = ""
+
+ self.ui.eip_bandwidth.hide()
+
+ # Set the EIP status icons
+ self.CONNECTING_ICON = None
+ self.CONNECTED_ICON = None
+ self.ERROR_ICON = None
+ self.CONNECTING_ICON_TRAY = None
+ self.CONNECTED_ICON_TRAY = None
+ self.ERROR_ICON_TRAY = None
+ self._set_eip_icons()
+
+ self._set_traffic_rates()
+ self._make_status_clickable()
+
+ self._provider = ""
+
+ def _make_status_clickable(self):
+ """
+ Makes upload and download figures clickable.
+ """
+ onclicked = self._on_VPN_status_clicked
+ self.ui.btnUpload.clicked.connect(onclicked)
+ self.ui.btnDownload.clicked.connect(onclicked)
+
+ def _on_VPN_status_clicked(self):
+ """
+ SLOT
+ TRIGGER: self.ui.btnUpload.clicked
+ self.ui.btnDownload.clicked
+
+ Toggles between rate and total throughput display for vpn
+ status figures.
+ """
+ self.DISPLAY_TRAFFIC_RATES = not self.DISPLAY_TRAFFIC_RATES
+ self.update_vpn_status(None) # refresh
+
+ def _set_traffic_rates(self):
+ """
+ Initializes up and download rates.
+ """
+ self._up_rate = RateMovingAverage()
+ self._down_rate = RateMovingAverage()
+
+ self.ui.btnUpload.setText(self.RATE_STR % (0,))
+ self.ui.btnDownload.setText(self.RATE_STR % (0,))
+
+ def _reset_traffic_rates(self):
+ """
+ Resets up and download rates, and cleans up the labels.
+ """
+ self._up_rate.reset()
+ self._down_rate.reset()
+ self.update_vpn_status(None)
+
+ def _update_traffic_rates(self, up, down):
+ """
+ Updates up and download rates.
+
+ :param up: upload total.
+ :type up: int
+ :param down: download total.
+ :type down: int
+ """
+ ts = datetime.now()
+ self._up_rate.append((ts, up))
+ self._down_rate.append((ts, down))
+
+ def _get_traffic_rates(self):
+ """
+ Gets the traffic rates (in KB/s).
+
+ :returns: a tuple with the (up, down) rates
+ :rtype: tuple
+ """
+ up = self._up_rate
+ down = self._down_rate
+
+ return (up.get_average(), down.get_average())
+
+ def _get_traffic_totals(self):
+ """
+ Gets the traffic total throughput (in Kb).
+
+ :returns: a tuple with the (up, down) totals
+ :rtype: tuple
+ """
+ up = self._up_rate
+ down = self._down_rate
+
+ return (up.get_total(), down.get_total())
+
+ def _set_eip_icons(self):
+ """
+ Sets the EIP status icons for the main window and for the tray
+
+ MAC : dark icons
+ LINUX : dark icons in window, light icons in tray
+ WIN : light icons
+ """
+ EIP_ICONS = EIP_ICONS_TRAY = (
+ ":/images/black/32/wait.png",
+ ":/images/black/32/on.png",
+ ":/images/black/32/off.png")
+
+ if IS_LINUX:
+ EIP_ICONS_TRAY = (
+ ":/images/white/32/wait.png",
+ ":/images/white/32/on.png",
+ ":/images/white/32/off.png")
+
+ self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0])
+ self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1])
+ self.ERROR_ICON = QtGui.QPixmap(EIP_ICONS[2])
+
+ self.CONNECTING_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[0])
+ self.CONNECTED_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[1])
+ self.ERROR_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[2])
+
+ # Systray and actions
+
+ def set_systray(self, systray):
+ """
+ Sets the systray object to use.
+
+ :param systray: Systray object
+ :type systray: QtGui.QSystemTrayIcon
+ """
+ leap_assert_type(systray, QtGui.QSystemTrayIcon)
+ self._systray = systray
+ self._systray.setToolTip(self.tr("All services are OFF"))
+
+ def _update_systray_tooltip(self):
+ """
+ Updates the system tray icon tooltip using the eip and mx status.
+ """
+ status = self.tr("Encrypted Internet: {0}").format(self._eip_status)
+ self._systray.setToolTip(status)
+
+ def set_action_eip_startstop(self, action_eip_startstop):
+ """
+ Sets the action_eip_startstop to use.
+
+ :param action_eip_startstop: action_eip_status to be used
+ :type action_eip_startstop: QtGui.QAction
+ """
+ self._action_eip_startstop = action_eip_startstop
+
+ def set_eip_status_menu(self, eip_status_menu):
+ """
+ Sets the eip_status_menu to use.
+
+ :param eip_status_menu: eip_status_menu to be used
+ :type eip_status_menu: QtGui.QMenu
+ """
+ leap_assert_type(eip_status_menu, QtGui.QMenu)
+ self._eip_status_menu = eip_status_menu
+
+ # EIP status ---
+
+ @property
+ def eip_button(self):
+ return self.ui.btnEipStartStop
+
+ @property
+ def eip_label(self):
+ return self.ui.lblEIPStatus
+
+ def eip_pre_up(self):
+ """
+ Triggered when the app activates eip.
+ Hides the status box and disables the start/stop button.
+ """
+ self.set_startstop_enabled(False)
+
+ @QtCore.Slot()
+ def disable_eip_start(self):
+ """
+ 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')
+ # 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 transitional
+ # transition there, but that's more involved.
+ self.eip_button.hide()
+ msg = self.tr("You must login to use Encrypted Internet")
+ self.eip_label.setText(msg)
+
+ @QtCore.Slot()
+ def enable_eip_start(self):
+ """
+ Triggered after a successful login.
+ Enables the start button.
+ """
+ logger.debug('Showing EIP start button')
+ self.eip_button.show()
+
+ # XXX disable (later) --------------------------
+ def set_eip_status(self, status, error=False):
+ """
+ Sets the status label at the VPN stage to status
+
+ :param status: status message
+ :type status: str or unicode
+ :param error: if the status is an erroneous one, then set this
+ to True
+ :type error: bool
+ """
+ leap_assert_type(error, bool)
+ self._eip_status = status
+ if error:
+ status = "<font color='red'>%s</font>" % (status,)
+ self.ui.lblEIPStatus.setText(status)
+ self.ui.lblEIPStatus.show()
+ self._update_systray_tooltip()
+
+ # XXX disable ---------------------------------
+ def set_startstop_enabled(self, value):
+ """
+ Enable or disable btnEipStartStop and _action_eip_startstop
+ based on value
+
+ :param value: True for enabled, False otherwise
+ :type value: bool
+ """
+ # TODO use disable_eip_start instead
+ # this should be handled by the state machine
+ leap_assert_type(value, bool)
+ self.ui.btnEipStartStop.setEnabled(value)
+ self._action_eip_startstop.setEnabled(value)
+
+ # XXX disable -----------------------------
+ def eip_started(self):
+ """
+ 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):
+ """
+ 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"))
+ self.ui.lblEIPStatus.show()
+
+ def update_vpn_status(self, data):
+ """
+ SLOT
+ TRIGGER: VPN.status_changed
+
+ Updates the download/upload labels based on the data provided
+ by the VPN thread.
+
+ :param data: a dictionary with the tcp/udp write and read totals.
+ If data is None, we just will refresh the display based
+ on the previous data.
+ :type data: dict
+ """
+ if data:
+ upload = float(data[VPNManager.TCPUDP_WRITE_KEY] or "0")
+ download = float(data[VPNManager.TCPUDP_READ_KEY] or "0")
+ self._update_traffic_rates(upload, download)
+
+ if self.DISPLAY_TRAFFIC_RATES:
+ uprate, downrate = self._get_traffic_rates()
+ upload_str = self.RATE_STR % (uprate,)
+ download_str = self.RATE_STR % (downrate,)
+
+ else: # display total throughput
+ uptotal, downtotal = self._get_traffic_totals()
+ upload_str = self.TOTAL_STR % (uptotal,)
+ download_str = self.TOTAL_STR % (downtotal,)
+
+ self.ui.btnUpload.setText(upload_str)
+ self.ui.btnDownload.setText(download_str)
+
+ def update_vpn_state(self, data):
+ """
+ SLOT
+ TRIGGER: VPN.state_changed
+
+ Updates the displayed VPN state based on the data provided by
+ the VPN thread.
+
+ Emits:
+ If the status is connected, we emit EIPConnection.qtsigs.
+ connected_signal
+ """
+ status = data[VPNManager.STATUS_STEP_KEY]
+ self.set_eip_status_icon(status)
+ if status == "CONNECTED":
+ self.ui.eip_bandwidth.show()
+ self.ui.lblEIPStatus.hide()
+
+ # XXX should be handled by the state machine too.
+ self.eip_connection_connected.emit()
+
+ # XXX should lookup status map in EIPConnection
+ elif status == "AUTH":
+ self.set_eip_status(self.tr("Authenticating..."))
+ elif status == "GET_CONFIG":
+ self.set_eip_status(self.tr("Retrieving configuration..."))
+ elif status == "WAIT":
+ self.set_eip_status(self.tr("Waiting to start..."))
+ elif status == "ASSIGN_IP":
+ self.set_eip_status(self.tr("Assigning IP"))
+ elif status == "RECONNECTING":
+ self.set_eip_status(self.tr("Reconnecting..."))
+ elif status == "ALREADYRUNNING":
+ # Put the following calls in Qt's event queue, otherwise
+ # the UI won't update properly
+ QtCore.QTimer.singleShot(
+ 0, self.eipconnection.qtsigs.do_disconnect_signal)
+ QtCore.QTimer.singleShot(0, partial(self.set_eip_status,
+ self.tr("Unable to start VPN, "
+ "it's already "
+ "running.")))
+ else:
+ self.set_eip_status(status)
+
+ def set_eip_icon(self, icon):
+ """
+ Sets the icon to display for EIP
+
+ :param icon: icon to display
+ :type icon: QPixmap
+ """
+ self.ui.lblVPNStatusIcon.setPixmap(icon)
+
+ def set_eip_status_icon(self, status):
+ """
+ Given a status step from the VPN thread, set the icon properly
+
+ :param status: status step
+ :type status: str
+ """
+ selected_pixmap = self.ERROR_ICON
+ selected_pixmap_tray = self.ERROR_ICON_TRAY
+ tray_message = self.tr("Encrypted Internet: OFF")
+ if status in ("WAIT", "AUTH", "GET_CONFIG",
+ "RECONNECTING", "ASSIGN_IP"):
+ selected_pixmap = self.CONNECTING_ICON
+ selected_pixmap_tray = self.CONNECTING_ICON_TRAY
+ tray_message = self.tr("Encrypted Internet: Starting...")
+ elif status in ("CONNECTED"):
+ tray_message = self.tr("Encrypted Internet: ON")
+ selected_pixmap = self.CONNECTED_ICON
+ selected_pixmap_tray = self.CONNECTED_ICON_TRAY
+
+ self.set_eip_icon(selected_pixmap)
+ self._systray.setIcon(QtGui.QIcon(selected_pixmap_tray))
+ self._eip_status_menu.setTitle(tray_message)
+
+ def set_provider(self, provider):
+ self._provider = provider
+ self.ui.lblEIPMessage.setText(
+ self.tr("Route traffic through: {0}").format(self._provider))
diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py
index db7b8e2a..582f26be 100644
--- a/src/leap/bitmask/gui/login.py
+++ b/src/leap/bitmask/gui/login.py
@@ -14,16 +14,18 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
"""
Login widget implementation
"""
import logging
+import keyring
+
from PySide import QtCore, QtGui
from ui_login import Ui_LoginWidget
from leap.bitmask.util.keyring_helpers import has_keyring
+from leap.common.check import leap_assert_type
logger = logging.getLogger(__name__)
@@ -33,10 +35,11 @@ class LoginWidget(QtGui.QWidget):
Login widget that emits signals to display the wizard or to
perform login.
"""
-
# Emitted when the login button is clicked
login = QtCore.Signal()
+ logged_in_signal = QtCore.Signal()
cancel_login = QtCore.Signal()
+ logout = QtCore.Signal()
# Emitted when the user selects "Other..." in the provider
# combobox or click "Create Account"
@@ -76,13 +79,21 @@ class LoginWidget(QtGui.QWidget):
self.ui.cmbProviders.currentIndexChanged.connect(
self._current_provider_changed)
- self.ui.btnCreateAccount.clicked.connect(
- self.show_wizard)
+
+ self.ui.btnLogout.clicked.connect(
+ self.logout)
username_re = QtCore.QRegExp(self.BARE_USERNAME_REGEX)
self.ui.lnUser.setValidator(
QtGui.QRegExpValidator(username_re, self))
+ self.logged_out()
+
+ self.ui.btnLogout.clicked.connect(self.start_logout)
+
+ self.ui.clblErrorMsg.hide()
+ self.ui.clblErrorMsg.clicked.connect(self.ui.clblErrorMsg.hide)
+
def _remember_state_changed(self, state):
"""
Saves the remember state in the LeapSettings
@@ -185,8 +196,10 @@ class LoginWidget(QtGui.QWidget):
if len(status) > self.MAX_STATUS_WIDTH:
status = status[:self.MAX_STATUS_WIDTH] + "..."
if error:
- status = "<font color='red'><b>%s</b></font>" % (status,)
- self.ui.lblStatus.setText(status)
+ self.ui.clblErrorMsg.show()
+ self.ui.clblErrorMsg.setText(status)
+ else:
+ self.ui.lblStatus.setText(status)
def set_enabled(self, enabled=False):
"""
@@ -211,6 +224,7 @@ class LoginWidget(QtGui.QWidget):
"""
text = self.tr("Cancel")
login_or_cancel = self.cancel_login
+ hide_remember = enabled
if not enabled:
text = self.tr("Log In")
@@ -220,6 +234,8 @@ class LoginWidget(QtGui.QWidget):
self.ui.btnLogin.clicked.disconnect()
self.ui.btnLogin.clicked.connect(login_or_cancel)
+ self.ui.chkRemember.setVisible(not hide_remember)
+ self.ui.lblStatus.setVisible(hide_remember)
def _focus_password(self):
"""
@@ -243,3 +259,106 @@ class LoginWidget(QtGui.QWidget):
self.ui.cmbProviders.blockSignals(False)
else:
self._selected_provider_index = param
+
+ def start_login(self):
+ """
+ Setups the login widgets for actually performing the login and
+ performs some basic checks.
+
+ :returns: True if everything's good to go, False otherwise
+ :rtype: bool
+ """
+ username = self.get_user()
+ password = self.get_password()
+ provider = self.get_selected_provider()
+
+ self._enabled_services = self._settings.get_enabled_services(
+ self.get_selected_provider())
+
+ if len(provider) == 0:
+ self.set_status(
+ self.tr("Please select a valid provider"))
+ return False
+
+ if len(username) == 0:
+ self.set_status(
+ self.tr("Please provide a valid username"))
+ return False
+
+ if len(password) == 0:
+ self.set_status(
+ self.tr("Please provide a valid password"))
+ return False
+
+ self.set_status(self.tr("Logging in..."), error=False)
+ self.set_enabled(False)
+ self.ui.clblErrorMsg.hide()
+
+ if self.get_remember() and has_keyring():
+ # in the keyring and in the settings
+ # we store the value 'usename@provider'
+ username_domain = (username + '@' + provider).encode("utf8")
+ try:
+ keyring.set_password(self.KEYRING_KEY,
+ username_domain,
+ password.encode("utf8"))
+ # Only save the username if it was saved correctly in
+ # the keyring
+ self._settings.set_user(username_domain)
+ except Exception as e:
+ logger.exception("Problem saving data to keyring. %r"
+ % (e,))
+ return True
+
+ def logged_in(self):
+ """
+ Sets the widgets to the logged in state
+ """
+ self.ui.login_widget.hide()
+ self.ui.logged_widget.show()
+ self.ui.lblUser.setText("%s@%s" % (self.get_user(),
+ self.get_selected_provider()))
+ self.set_login_status("")
+ self.logged_in_signal.emit()
+
+ def logged_out(self):
+ """
+ Sets the widgets to the logged out state
+ """
+ self.ui.login_widget.show()
+ self.ui.logged_widget.hide()
+
+ self.set_password("")
+ self.set_enabled(True)
+ self.set_status("", error=False)
+
+ def set_login_status(self, msg, error=False):
+ """
+ Sets the status label for the logged in state.
+
+ :param msg: status message
+ :type msg: str or unicode
+ :param error: if the status is an erroneous one, then set this
+ to True
+ :type error: bool
+ """
+ leap_assert_type(error, bool)
+ if error:
+ msg = "<font color='red'><b>%s</b></font>" % (msg,)
+ self.ui.lblLoginStatus.setText(msg)
+ self.ui.lblLoginStatus.show()
+
+ def start_logout(self):
+ """
+ Sets the widgets to the logging out state
+ """
+ self.ui.btnLogout.setText(self.tr("Loggin out..."))
+ self.ui.btnLogout.setEnabled(False)
+
+ def done_logout(self):
+ """
+ Sets the widgets to the logged out state
+ """
+ self.ui.btnLogout.setText(self.tr("Logout"))
+ self.ui.btnLogout.setEnabled(True)
+ self.ui.clblErrorMsg.hide()
diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py
new file mode 100644
index 00000000..ab9052d7
--- /dev/null
+++ b/src/leap/bitmask/gui/mail_status.py
@@ -0,0 +1,408 @@
+# -*- coding: utf-8 -*-
+# mail_status.py
+# Copyright (C) 2013 LEAP
+#
+# 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/>.
+"""
+Mail Status Panel widget implementation
+"""
+import logging
+
+from PySide import QtCore, QtGui
+
+from leap.bitmask.platform_init import IS_LINUX
+from leap.common.check import leap_assert, leap_assert_type
+from leap.common.events import register
+from leap.common.events import events_pb2 as proto
+
+from ui_mail_status import Ui_MailStatusWidget
+
+logger = logging.getLogger(__name__)
+
+
+class MailStatusWidget(QtGui.QWidget):
+ """
+ Status widget that displays the state of the LEAP Mail service
+ """
+ eip_connection_connected = QtCore.Signal()
+ _soledad_event = QtCore.Signal(object)
+ _smtp_event = QtCore.Signal(object)
+ _imap_event = QtCore.Signal(object)
+ _keymanager_event = QtCore.Signal(object)
+
+ def __init__(self, parent=None):
+ """
+ Constructor for MailStatusWidget
+
+ :param parent: parent widget for this one.
+ :type parent: QtGui.QWidget
+ """
+ QtGui.QWidget.__init__(self, parent)
+
+ self._systray = None
+
+ self.ui = Ui_MailStatusWidget()
+ self.ui.setupUi(self)
+
+ # set systray tooltip status
+ self._mx_status = ""
+
+ # Set the Mail status icons
+ self.CONNECTING_ICON = None
+ self.CONNECTED_ICON = None
+ self.ERROR_ICON = None
+ self.CONNECTING_ICON_TRAY = None
+ self.CONNECTED_ICON_TRAY = None
+ self.ERROR_ICON_TRAY = None
+ self._set_mail_icons()
+
+ register(signal=proto.KEYMANAGER_LOOKING_FOR_KEY,
+ callback=self._mail_handle_keymanager_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.KEYMANAGER_KEY_FOUND,
+ callback=self._mail_handle_keymanager_events,
+ reqcbk=lambda req, resp: None)
+
+ # register(signal=proto.KEYMANAGER_KEY_NOT_FOUND,
+ # callback=self._mail_handle_keymanager_events,
+ # reqcbk=lambda req, resp: None)
+
+ register(signal=proto.KEYMANAGER_STARTED_KEY_GENERATION,
+ callback=self._mail_handle_keymanager_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.KEYMANAGER_FINISHED_KEY_GENERATION,
+ callback=self._mail_handle_keymanager_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.KEYMANAGER_DONE_UPLOADING_KEYS,
+ callback=self._mail_handle_keymanager_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.SOLEDAD_DONE_DOWNLOADING_KEYS,
+ callback=self._mail_handle_soledad_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.SOLEDAD_DONE_UPLOADING_KEYS,
+ callback=self._mail_handle_soledad_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.SMTP_SERVICE_STARTED,
+ callback=self._mail_handle_smtp_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.SMTP_SERVICE_FAILED_TO_START,
+ callback=self._mail_handle_smtp_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.IMAP_SERVICE_STARTED,
+ callback=self._mail_handle_imap_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.IMAP_SERVICE_FAILED_TO_START,
+ callback=self._mail_handle_imap_events,
+ reqcbk=lambda req, resp: None)
+
+ register(signal=proto.IMAP_UNREAD_MAIL,
+ callback=self._mail_handle_imap_events,
+ reqcbk=lambda req, resp: None)
+
+ self._smtp_started = False
+ self._imap_started = False
+
+ self._soledad_event.connect(
+ self._mail_handle_soledad_events_slot)
+ self._imap_event.connect(
+ self._mail_handle_imap_events_slot)
+ self._smtp_event.connect(
+ self._mail_handle_smtp_events_slot)
+ self._keymanager_event.connect(
+ self._mail_handle_keymanager_events_slot)
+
+ def _set_mail_icons(self):
+ """
+ Sets the Mail status icons for the main window and for the tray
+
+ MAC : dark icons
+ LINUX : dark icons in window, light icons in tray
+ WIN : light icons
+ """
+ EIP_ICONS = EIP_ICONS_TRAY = (
+ ":/images/black/32/wait.png",
+ ":/images/black/32/on.png",
+ ":/images/black/32/off.png")
+
+ if IS_LINUX:
+ EIP_ICONS_TRAY = (
+ ":/images/white/32/wait.png",
+ ":/images/white/32/on.png",
+ ":/images/white/32/off.png")
+
+ self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0])
+ self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1])
+ self.ERROR_ICON = QtGui.QPixmap(EIP_ICONS[2])
+
+ self.CONNECTING_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[0])
+ self.CONNECTED_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[1])
+ self.ERROR_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[2])
+
+ # Systray and actions
+
+ def set_systray(self, systray):
+ """
+ Sets the systray object to use.
+
+ :param systray: Systray object
+ :type systray: QtGui.QSystemTrayIcon
+ """
+ leap_assert_type(systray, QtGui.QSystemTrayIcon)
+ self._systray = systray
+ self._systray.setToolTip(self.tr("All services are OFF"))
+
+ def _update_systray_tooltip(self):
+ """
+ Updates the system tray icon tooltip using the eip and mx status.
+ """
+ # TODO: Figure out how to handle this with the two status in different
+ # classes
+ # status = self.tr("Encrypted Internet: {0}").format(self._eip_status)
+ # status += '\n'
+ # status += self.tr("Mail is {0}").format(self._mx_status)
+ # self._systray.setToolTip(status)
+ pass
+
+ def set_action_mail_status(self, action_mail_status):
+ """
+ Sets the action_mail_status to use.
+
+ :param action_mail_status: action_mail_status to be used
+ :type action_mail_status: QtGui.QAction
+ """
+ leap_assert_type(action_mail_status, QtGui.QAction)
+ self._action_mail_status = action_mail_status
+
+ def _set_mail_status(self, status, ready=0):
+ """
+ Sets the Mail status in the label and in the tray icon.
+
+ :param status: the status text to display
+ :type status: unicode
+ :param ready: 2 or >2 if mx is ready, 0 if stopped, 1 if it's
+ starting, < 0 if disabled.
+ :type ready: int
+ """
+ self.ui.lblMailStatus.setText(status)
+
+ self._mx_status = self.tr('OFF')
+ tray_status = self.tr('Mail is OFF')
+
+ icon = self.ERROR_ICON
+ if ready == 0:
+ self.ui.lblMailStatus.setText(
+ self.tr("You must be logged in to use encrypted email."))
+ elif ready == 1:
+ icon = self.CONNECTING_ICON
+ self._mx_status = self.tr('Starting..')
+ tray_status = self.tr('Mail is starting')
+ elif ready >= 2:
+ icon = self.CONNECTED_ICON
+ self._mx_status = self.tr('ON')
+ tray_status = self.tr('Mail is ON')
+ elif ready < 0:
+ tray_status = self.tr("Mail is disabled")
+
+ self.ui.lblMailStatusIcon.setPixmap(icon)
+ self._action_mail_status.setText(tray_status)
+ self._update_systray_tooltip()
+
+ def _mail_handle_soledad_events(self, req):
+ """
+ Callback for handling events that are emitted from Soledad
+
+ :param req: Request type
+ :type req: leap.common.events.events_pb2.SignalRequest
+ """
+ self._soledad_event.emit(req)
+
+ def _mail_handle_soledad_events_slot(self, req):
+ """
+ SLOT
+ TRIGGER: _mail_handle_soledad_events
+
+ Reacts to an Soledad event
+
+ :param req: Request type
+ :type req: leap.common.events.events_pb2.SignalRequest
+ """
+ self._set_mail_status(self.tr("Starting..."), ready=1)
+
+ ext_status = ""
+
+ if req.event == proto.SOLEDAD_DONE_UPLOADING_KEYS:
+ ext_status = self.tr("Soledad has started...")
+ elif req.event == proto.SOLEDAD_DONE_DOWNLOADING_KEYS:
+ ext_status = self.tr("Soledad is starting, please wait...")
+ else:
+ leap_assert(False,
+ "Don't know how to handle this state: %s"
+ % (req.event))
+
+ self._set_mail_status(ext_status, ready=1)
+
+ def _mail_handle_keymanager_events(self, req):
+ """
+ Callback for the KeyManager events
+
+ :param req: Request type
+ :type req: leap.common.events.events_pb2.SignalRequest
+ """
+ self._keymanager_event.emit(req)
+
+ def _mail_handle_keymanager_events_slot(self, req):
+ """
+ SLOT
+ TRIGGER: _mail_handle_keymanager_events
+
+ Reacts to an KeyManager event
+
+ :param req: Request type
+ :type req: leap.common.events.events_pb2.SignalRequest
+ """
+ # We want to ignore this kind of events once everything has
+ # started
+ if self._smtp_started and self._imap_started:
+ return
+
+ self._set_mail_status(self.tr("Starting..."), ready=1)
+
+ ext_status = ""
+
+ if req.event == proto.KEYMANAGER_LOOKING_FOR_KEY:
+ ext_status = self.tr("Looking for key for this user")
+ elif req.event == proto.KEYMANAGER_KEY_FOUND:
+ ext_status = self.tr("Found key! Starting mail...")
+ # elif req.event == proto.KEYMANAGER_KEY_NOT_FOUND:
+ # ext_status = self.tr("Key not found!")
+ elif req.event == proto.KEYMANAGER_STARTED_KEY_GENERATION:
+ ext_status = self.tr("Generating new key, please wait...")
+ elif req.event == proto.KEYMANAGER_FINISHED_KEY_GENERATION:
+ ext_status = self.tr("Finished generating key!")
+ elif req.event == proto.KEYMANAGER_DONE_UPLOADING_KEYS:
+ ext_status = self.tr("Starting mail...")
+ else:
+ leap_assert(False,
+ "Don't know how to handle this state: %s"
+ % (req.event))
+
+ self._set_mail_status(ext_status, ready=1)
+
+ def _mail_handle_smtp_events(self, req):
+ """
+ Callback for the SMTP events
+
+ :param req: Request type
+ :type req: leap.common.events.events_pb2.SignalRequest
+ """
+ self._smtp_event.emit(req)
+
+ def _mail_handle_smtp_events_slot(self, req):
+ """
+ SLOT
+ TRIGGER: _mail_handle_smtp_events
+
+ Reacts to an SMTP event
+
+ :param req: Request type
+ :type req: leap.common.events.events_pb2.SignalRequest
+ """
+ ext_status = ""
+
+ if req.event == proto.SMTP_SERVICE_STARTED:
+ ext_status = self.tr("SMTP has started...")
+ self._smtp_started = True
+ if self._smtp_started and self._imap_started:
+ self._set_mail_status(self.tr("ON"), ready=2)
+ ext_status = ""
+ elif req.event == proto.SMTP_SERVICE_FAILED_TO_START:
+ ext_status = self.tr("SMTP failed to start, check the logs.")
+ self._set_mail_status(self.tr("Failed"))
+ else:
+ leap_assert(False,
+ "Don't know how to handle this state: %s"
+ % (req.event))
+
+ self._set_mail_status(ext_status, ready=2)
+
+ def _mail_handle_imap_events(self, req):
+ """
+ Callback for the IMAP events
+
+ :param req: Request type
+ :type req: leap.common.events.events_pb2.SignalRequest
+ """
+ self._imap_event.emit(req)
+
+ def _mail_handle_imap_events_slot(self, req):
+ """
+ SLOT
+ TRIGGER: _mail_handle_imap_events
+
+ Reacts to an IMAP event
+
+ :param req: Request type
+ :type req: leap.common.events.events_pb2.SignalRequest
+ """
+ ext_status = None
+
+ if req.event == proto.IMAP_SERVICE_STARTED:
+ ext_status = self.tr("IMAP has started...")
+ self._imap_started = True
+ if self._smtp_started and self._imap_started:
+ self._set_mail_status(self.tr("ON"), ready=2)
+ ext_status = ""
+ elif req.event == proto.IMAP_SERVICE_FAILED_TO_START:
+ ext_status = self.tr("IMAP failed to start, check the logs.")
+ self._set_mail_status(self.tr("Failed"))
+ elif req.event == proto.IMAP_UNREAD_MAIL:
+ if self._smtp_started and self._imap_started:
+ self._set_mail_status(self.tr("%s Unread Emails") %
+ (req.content), ready=2)
+ else:
+ leap_assert(False, # XXX ???
+ "Don't know how to handle this state: %s"
+ % (req.event))
+
+ if ext_status is not None:
+ self._set_mail_status(ext_status, ready=1)
+
+ def about_to_start(self):
+ """
+ Displays the correct UI for the point where mail components
+ haven't really started, but they are about to in a second.
+ """
+ self._set_mail_status(self.tr("About to start, please wait..."),
+ ready=1)
+
+ def set_disabled(self):
+ """
+ Displays the correct UI for disabled mail.
+ """
+ self._set_mail_status(self.tr("Disabled"), -1)
+
+ def stopped_mail(self):
+ """
+ Displayes the correct UI for the stopped state.
+ """
+ self._set_mail_status(self.tr("OFF"))
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 200d68aa..84f09fd9 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -32,13 +32,16 @@ from leap.bitmask.crypto.srpauth import SRPAuth
from leap.bitmask.gui.loggerwindow import LoggerWindow
from leap.bitmask.gui.login import LoginWidget
from leap.bitmask.gui.preferenceswindow import PreferencesWindow
+from leap.bitmask.gui.eip_preferenceswindow import EIPPreferencesWindow
from leap.bitmask.gui import statemachines
-from leap.bitmask.gui.statuspanel import StatusPanelWidget
+from leap.bitmask.gui.eip_status import EIPStatusWidget
+from leap.bitmask.gui.mail_status import MailStatusWidget
from leap.bitmask.gui.wizard import Wizard
+from leap.bitmask import provider
+from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper
from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper
-from leap.bitmask.services.eip.eipconfig import EIPConfig
-from leap.bitmask.services.eip.providerbootstrapper import ProviderBootstrapper
+from leap.bitmask.services.eip import eipconfig
# XXX: Soledad might not work out of the box in Windows, issue #2932
from leap.bitmask.services.soledad.soledadbootstrapper import \
SoledadBootstrapper
@@ -53,12 +56,12 @@ from leap.bitmask.services.eip.vpnprocess import VPN
from leap.bitmask.services.eip.vpnprocess import OpenVPNAlreadyRunning
from leap.bitmask.services.eip.vpnprocess import AlienOpenVPNAlreadyRunning
-from leap.bitmask.services.eip.vpnlaunchers import VPNLauncherException
-from leap.bitmask.services.eip.vpnlaunchers import OpenVPNNotFoundException
-from leap.bitmask.services.eip.vpnlaunchers import EIPNoPkexecAvailable
-from leap.bitmask.services.eip.vpnlaunchers import \
+from leap.bitmask.services.eip.vpnlauncher import VPNLauncherException
+from leap.bitmask.services.eip.vpnlauncher import OpenVPNNotFoundException
+from leap.bitmask.services.eip.linuxvpnlauncher import EIPNoPkexecAvailable
+from leap.bitmask.services.eip.linuxvpnlauncher import \
EIPNoPolkitAuthAgentAvailable
-from leap.bitmask.services.eip.vpnlaunchers import EIPNoTunKextLoaded
+from leap.bitmask.services.eip.darwinvpnlauncher import EIPNoTunKextLoaded
from leap.bitmask.util.keyring_helpers import has_keyring
from leap.bitmask.util.leap_log_handler import LeapLogHandler
@@ -98,6 +101,7 @@ class MainWindow(QtGui.QMainWindow):
MX_SERVICE = "mx"
# Signals
+ eip_needs_login = QtCore.Signal([])
new_updates = QtCore.Signal(object)
raise_window = QtCore.Signal([])
soledad_ready = QtCore.Signal([])
@@ -147,7 +151,7 @@ class MainWindow(QtGui.QMainWindow):
self._login_widget = LoginWidget(
self._settings,
- self.ui.stackedWidget.widget(self.LOGIN_INDEX))
+ self)
self.ui.loginLayout.addWidget(self._login_widget)
# Qt Signal Connections #####################################
@@ -155,17 +159,18 @@ class MainWindow(QtGui.QMainWindow):
self._login_widget.login.connect(self._login)
self._login_widget.cancel_login.connect(self._cancel_login)
- self._login_widget.show_wizard.connect(
- self._launch_wizard)
-
- self.ui.btnShowLog.clicked.connect(self._show_logger_window)
- self.ui.btnPreferences.clicked.connect(self._show_preferences)
+ self._login_widget.show_wizard.connect(self._launch_wizard)
+ self._login_widget.logout.connect(self._logout)
- self._status_panel = StatusPanelWidget(
- self.ui.stackedWidget.widget(self.EIP_STATUS_INDEX))
- self.ui.statusLayout.addWidget(self._status_panel)
+ 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)
- self.ui.stackedWidget.setCurrentIndex(self.LOGIN_INDEX)
+ self._mail_status = MailStatusWidget(self)
+ self.ui.mailLayout.addWidget(self._mail_status)
self._eip_connection = EIPConnection()
@@ -173,15 +178,19 @@ class MainWindow(QtGui.QMainWindow):
self._start_eip)
self._eip_connection.qtsigs.disconnecting_signal.connect(
self._stop_eip)
- self._status_panel.eip_connection_connected.connect(
+ self._eip_status.eip_connection_connected.connect(
self._on_eip_connected)
+ self.eip_needs_login.connect(
+ self._eip_status.disable_eip_start)
+ self.eip_needs_login.connect(
+ self._disable_eip_start_action)
# This is loaded only once, there's a bug when doing that more
# than once
self._provider_config = ProviderConfig()
# Used for automatic start of EIP
self._provisional_provider_config = ProviderConfig()
- self._eip_config = EIPConfig()
+ self._eip_config = eipconfig.EIPConfig()
self._already_started_eip = False
@@ -221,9 +230,9 @@ class MainWindow(QtGui.QMainWindow):
self._finish_eip_bootstrap)
self._vpn = VPN(openvpn_verb=openvpn_verb)
self._vpn.qtsigs.state_changed.connect(
- self._status_panel.update_vpn_state)
+ self._eip_status.update_vpn_state)
self._vpn.qtsigs.status_changed.connect(
- self._status_panel.update_vpn_status)
+ self._eip_status.update_vpn_status)
self._vpn.qtsigs.process_finished.connect(
self._eip_finished)
@@ -234,17 +243,23 @@ class MainWindow(QtGui.QMainWindow):
self._soledad_bootstrapped_stage)
self._soledad_bootstrapper.soledad_timeout.connect(
self._retry_soledad_connection)
+ # XXX missing connect to soledad_failed (signal unrecoverable to user)
+ # TODO wait until chiiph ui refactor.
self._smtp_bootstrapper = SMTPBootstrapper()
self._smtp_bootstrapper.download_config.connect(
self._smtp_bootstrapped_stage)
- self.ui.action_log_out.setEnabled(False)
- self.ui.action_log_out.triggered.connect(self._logout)
self.ui.action_about_leap.triggered.connect(self._about)
self.ui.action_quit.triggered.connect(self.quit)
self.ui.action_wizard.triggered.connect(self._launch_wizard)
self.ui.action_show_logs.triggered.connect(self._show_logger_window)
+ self.ui.action_create_new_account.triggered.connect(
+ self._launch_wizard)
+
+ if IS_MAC:
+ self.ui.menuFile.menuAction().setText(self.tr("Util"))
+
self.raise_window.connect(self._do_raise_mainwindow)
# Used to differentiate between real quits and close to tray
@@ -254,17 +269,17 @@ class MainWindow(QtGui.QMainWindow):
self._action_mail_status = QtGui.QAction(self.tr("Mail is OFF"), self)
self._action_mail_status.setEnabled(False)
- self._status_panel.set_action_mail_status(self._action_mail_status)
+ self._mail_status.set_action_mail_status(self._action_mail_status)
self._action_eip_startstop = QtGui.QAction("", self)
- self._status_panel.set_action_eip_startstop(self._action_eip_startstop)
-
- self._action_preferences = QtGui.QAction(self.tr("Preferences"), self)
- self._action_preferences.triggered.connect(self._show_preferences)
+ self._eip_status.set_action_eip_startstop(self._action_eip_startstop)
self._action_visible = QtGui.QAction(self.tr("Hide Main Window"), self)
self._action_visible.triggered.connect(self._toggle_visible)
+ self.ui.btnPreferences.clicked.connect(self._show_preferences)
+ self.ui.btnEIPPreferences.clicked.connect(self._show_eip_preferences)
+
self._enabled_services = []
self._center_window()
@@ -280,6 +295,7 @@ class MainWindow(QtGui.QMainWindow):
self.mail_client_logged_in.connect(self._fetch_incoming_mail)
self.logout.connect(self._stop_imap_service)
self.logout.connect(self._stop_smtp_service)
+ self.logout.connect(self._mail_status.stopped_mail)
################################# end Qt Signals connection ########
@@ -296,6 +312,7 @@ class MainWindow(QtGui.QMainWindow):
self._soledad_ready = False
self._keymanager = None
self._smtp_service = None
+ self._smtp_port = None
self._imap_service = None
self._login_defer = None
@@ -303,27 +320,29 @@ class MainWindow(QtGui.QMainWindow):
self._smtp_config = SMTPConfig()
- if self._first_run():
- self._wizard_firstrun = True
- self._wizard = Wizard(bypass_checks=bypass_checks)
- # Give this window time to finish init and then show the wizard
- QtCore.QTimer.singleShot(1, self._launch_wizard)
- self._wizard.accepted.connect(self._finish_init)
- self._wizard.rejected.connect(self._rejected_wizard)
- else:
- self._finish_init()
-
# Eip machine is a public attribute where the state machine for
# the eip connection will be available to the different components.
# Remember that this will not live in the +1600LOC mainwindow for
# all the eternity, so at some point we will be moving this to
# the EIPConductor or some other clever component that we will
# instantiate from here.
- self.eip_machine = None
+ self.eip_machine = None
# start event machines
self.start_eip_machine()
+ if self._first_run():
+ self._wizard_firstrun = True
+ self._wizard = Wizard(bypass_checks=bypass_checks)
+ # Give this window time to finish init and then show the wizard
+ QtCore.QTimer.singleShot(1, self._launch_wizard)
+ self._wizard.accepted.connect(self._finish_init)
+ self._wizard.rejected.connect(self._rejected_wizard)
+ else:
+ # during finish_init, we disable the eip start button
+ # so this has to be done after eip_machine is started
+ self._finish_init()
+
def _rejected_wizard(self):
"""
SLOT
@@ -391,7 +410,6 @@ class MainWindow(QtGui.QMainWindow):
SLOT
TRIGGERS:
self.ui.action_show_logs.triggered
- self.ui.btnShowLog.clicked
Displays the window with the history of messages logged until now
and displays the new ones on arrival.
@@ -405,18 +423,13 @@ class MainWindow(QtGui.QMainWindow):
self._logger_window = LoggerWindow(handler=leap_log_handler)
self._logger_window.setVisible(
not self._logger_window.isVisible())
- self.ui.btnShowLog.setChecked(self._logger_window.isVisible())
else:
self._logger_window.setVisible(not self._logger_window.isVisible())
- self.ui.btnShowLog.setChecked(self._logger_window.isVisible())
-
- self._logger_window.finished.connect(self._uncheck_logger_button)
def _show_preferences(self):
"""
SLOT
TRIGGERS:
- self.ui.action_show_preferences.triggered
self.ui.btnPreferences.clicked
Displays the preferences window.
@@ -431,22 +444,25 @@ class MainWindow(QtGui.QMainWindow):
preferences_window.show()
- def _set_soledad_ready(self):
+ def _show_eip_preferences(self):
"""
SLOT
TRIGGERS:
- self.soledad_ready
+ self.ui.btnEIPPreferences.clicked
- It sets the soledad object as ready to use.
+ Displays the EIP preferences window.
"""
- self._soledad_ready = True
+ EIPPreferencesWindow(self).show()
- def _uncheck_logger_button(self):
+ def _set_soledad_ready(self):
"""
SLOT
- Sets the checked state of the loggerwindow button to false.
+ TRIGGERS:
+ self.soledad_ready
+
+ It sets the soledad object as ready to use.
"""
- self.ui.btnShowLog.setChecked(False)
+ self._soledad_ready = True
def _new_updates_available(self, req):
"""
@@ -579,21 +595,29 @@ class MainWindow(QtGui.QMainWindow):
"""
Tries to autostart EIP
"""
- default_provider = self._settings.get_defaultprovider()
+ settings = self._settings
+
+ should_autostart = settings.get_autostart_eip()
+ if not should_autostart:
+ logger.debug('Will not autostart EIP since it is setup '
+ 'to not to do it')
+ self.eip_needs_login.emit()
+ return
+
+ default_provider = settings.get_defaultprovider()
if default_provider is None:
logger.info("Cannot autostart Encrypted Internet because there is "
"no default provider configured")
+ self.eip_needs_login.emit()
return
- self._enabled_services = self._settings.get_enabled_services(
+ self._enabled_services = settings.get_enabled_services(
default_provider)
- if self._provisional_provider_config.load(
- os.path.join("leap",
- "providers",
- default_provider,
- "provider.json")):
+ loaded = self._provisional_provider_config.load(
+ provider.get_provider_path(default_provider))
+ if loaded:
# XXX I think we should not try to re-download config every time,
# it adds some delay.
# Maybe if it's the first run in a session,
@@ -601,6 +625,7 @@ class MainWindow(QtGui.QMainWindow):
self._download_eip_config()
else:
# XXX: Display a proper message to the user
+ self.eip_needs_login.emit()
logger.error("Unable to load %s config, cannot autostart." %
(default_provider,))
@@ -621,24 +646,20 @@ class MainWindow(QtGui.QMainWindow):
systrayMenu.addAction(self._action_visible)
systrayMenu.addSeparator()
- eip_menu = systrayMenu.addMenu(self.tr("Encrypted Internet is OFF"))
+ eip_menu = systrayMenu.addMenu(self.tr("Encrypted Internet: OFF"))
eip_menu.addAction(self._action_eip_startstop)
- self._status_panel.set_eip_status_menu(eip_menu)
+ self._eip_status.set_eip_status_menu(eip_menu)
systrayMenu.addAction(self._action_mail_status)
systrayMenu.addSeparator()
- systrayMenu.addAction(self._action_preferences)
- systrayMenu.addAction(help_action)
- systrayMenu.addSeparator()
- systrayMenu.addAction(self.ui.action_log_out)
systrayMenu.addAction(self.ui.action_quit)
self._systray = QtGui.QSystemTrayIcon(self)
self._systray.setContextMenu(systrayMenu)
- self._systray.setIcon(self._status_panel.ERROR_ICON_TRAY)
+ self._systray.setIcon(self._eip_status.ERROR_ICON_TRAY)
self._systray.setVisible(True)
self._systray.activated.connect(self._tray_activated)
- self._status_panel.set_systray(self._systray)
+ self._eip_status.set_systray(self._systray)
def _tray_activated(self, reason=None):
"""
@@ -746,9 +767,10 @@ class MainWindow(QtGui.QMainWindow):
"""
Reimplements the changeEvent method to minimize to tray
"""
- if QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \
- e.type() == QtCore.QEvent.WindowStateChange and \
- self.isMinimized():
+ if not IS_MAC and \
+ QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \
+ e.type() == QtCore.QEvent.WindowStateChange and \
+ self.isMinimized():
self._toggle_visible()
e.accept()
return
@@ -844,47 +866,8 @@ class MainWindow(QtGui.QMainWindow):
"""
leap_assert(self._provider_config, "We need a provider config")
- username = self._login_widget.get_user()
- password = self._login_widget.get_password()
- provider = self._login_widget.get_selected_provider()
-
- self._enabled_services = self._settings.get_enabled_services(
- self._login_widget.get_selected_provider())
-
- if len(provider) == 0:
- self._login_widget.set_status(
- self.tr("Please select a valid provider"))
- return
-
- if len(username) == 0:
- self._login_widget.set_status(
- self.tr("Please provide a valid username"))
- return
-
- if len(password) == 0:
- self._login_widget.set_status(
- self.tr("Please provide a valid Password"))
- return
-
- self._login_widget.set_status(self.tr("Logging in..."), error=False)
- self._login_widget.set_enabled(False)
-
- if self._login_widget.get_remember() and has_keyring():
- # in the keyring and in the settings
- # we store the value 'usename@provider'
- username_domain = (username + '@' + provider).encode("utf8")
- try:
- keyring.set_password(self.KEYRING_KEY,
- username_domain,
- password.encode("utf8"))
- # Only save the username if it was saved correctly in
- # the keyring
- self._settings.set_user(username_domain)
- except Exception as e:
- logger.error("Problem saving data to keyring. %r"
- % (e,))
-
- self._download_provider_config()
+ if self._login_widget.start_login():
+ self._download_provider_config()
def _cancel_login(self):
"""
@@ -952,7 +935,6 @@ class MainWindow(QtGui.QMainWindow):
if ok:
self._logged_user = self._login_widget.get_user()
- self.ui.action_log_out.setEnabled(True)
# We leave a bit of room for the user to see the
# "Succeeded" message and then we switch to the EIP status
# panel
@@ -967,20 +949,25 @@ class MainWindow(QtGui.QMainWindow):
Changes the stackedWidget index to the EIP status one and
triggers the eip bootstrapping
"""
- if not self._already_started_eip:
- self._status_panel.set_provider(
- "%s@%s" % (self._login_widget.get_user(),
- self._get_best_provider_config().get_domain()))
- self.ui.stackedWidget.setCurrentIndex(self.EIP_STATUS_INDEX)
+ self._login_widget.logged_in()
+
+ self._enabled_services = self._settings.get_enabled_services(
+ self._provider_config.get_domain())
# TODO separate UI from logic.
# TODO soledad should check if we want to run only over EIP.
- self._soledad_bootstrapper.run_soledad_setup_checks(
- self._provider_config,
- self._login_widget.get_user(),
- self._login_widget.get_password(),
- download_if_needed=True)
+ if self._provider_config.provides_mx() and \
+ self._enabled_services.count(self.MX_SERVICE) > 0:
+ self._mail_status.about_to_start()
+
+ self._soledad_bootstrapper.run_soledad_setup_checks(
+ self._provider_config,
+ self._login_widget.get_user(),
+ self._login_widget.get_password(),
+ download_if_needed=True)
+ else:
+ self._mail_status.set_disabled()
self._download_eip_config()
@@ -1007,6 +994,7 @@ class MainWindow(QtGui.QMainWindow):
"""
Retries soledad connection.
"""
+ # XXX should move logic to soledad boostrapper itself
logger.debug("Retrying soledad connection.")
if self._soledad_bootstrapper.should_retry_initialization():
self._soledad_bootstrapper.increment_retries_count()
@@ -1031,8 +1019,9 @@ class MainWindow(QtGui.QMainWindow):
"""
passed = data[self._soledad_bootstrapper.PASSED_KEY]
if not passed:
+ # TODO should actually *display* on the panel.
logger.debug("ERROR on soledad bootstrapping:")
- logger.error(data[self._soledad_bootstrapper.ERROR_KEY])
+ logger.error("%r" % data[self._soledad_bootstrapper.ERROR_KEY])
return
else:
logger.debug("Done bootstrapping Soledad")
@@ -1116,7 +1105,7 @@ class MainWindow(QtGui.QMainWindow):
# the specific default.
from leap.mail.smtp import setup_smtp_relay
- self._smtp_service = setup_smtp_relay(
+ self._smtp_service, self._smtp_port = setup_smtp_relay(
port=2013,
keymanager=self._keymanager,
smtp_host=host,
@@ -1136,6 +1125,7 @@ class MainWindow(QtGui.QMainWindow):
# but in the imap case we are just stopping the fetcher.
if self._smtp_service is not None:
logger.debug('Stopping smtp service.')
+ self._smtp_port.stopListening()
self._smtp_service.doStop()
###################################################################
@@ -1195,22 +1185,37 @@ class MainWindow(QtGui.QMainWindow):
"""
Initializes and starts the EIP state machine
"""
- button = self._status_panel.eip_button
+ button = self._eip_status.eip_button
action = self._action_eip_startstop
- label = self._status_panel.eip_label
+ 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):
+ """
+ Disables the EIP start action in the systray menu.
+ """
+ self._action_eip_startstop.setEnabled(False)
+
+ @QtCore.Slot()
+ def _enable_eip_start_action(self):
+ """
+ Enables the EIP start action in the systray menu.
+ """
+ self._action_eip_startstop.setEnabled(True)
@QtCore.Slot()
def _on_eip_connected(self):
"""
SLOT
TRIGGERS:
- self._status_panel.eip_connection_connected
+ self._eip_status.eip_connection_connected
Emits the EIPConnection.qtsigs.connected_signal
This is a little workaround for connecting the vpn-connected
@@ -1225,7 +1230,7 @@ class MainWindow(QtGui.QMainWindow):
"""
SLOT
TRIGGERS:
- self._status_panel.start_eip
+ self._eip_status.start_eip
self._action_eip_startstop.triggered
or called from _finish_eip_bootstrap
@@ -1233,9 +1238,30 @@ class MainWindow(QtGui.QMainWindow):
"""
provider_config = self._get_best_provider_config()
provider = provider_config.get_domain()
- self._status_panel.eip_pre_up()
+ 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)
+
+ loaded = eipconfig.load_eipconfig_if_needed(
+ provider_config, self._eip_config, provider)
+
+ if not loaded:
+ self._eip_status.set_eip_status(
+ self.tr("Could not load Encrypted Internet "
+ "Configuration."),
+ error=True)
+ # signal connection aborted to state machine
+ qtsigs = self._eip_connection.qtsigs
+ qtsigs.connection_aborted_signal.emit()
+ logger.error("Tried to start EIP but cannot find any "
+ "available provider!")
+ return
+
try:
# XXX move this to EIPConductor
host, port = get_openvpn_management()
@@ -1244,16 +1270,14 @@ class MainWindow(QtGui.QMainWindow):
socket_host=host,
socket_port=port)
self._settings.set_defaultprovider(provider)
- if self._logged_user is not None:
- provider = "%s@%s" % (self._logged_user, provider)
# XXX move to the state machine too
- self._status_panel.set_provider(provider)
+ self._eip_status.set_provider(provider)
# TODO refactor exceptions so they provide translatable
# usef-facing messages.
except EIPNoPolkitAuthAgentAvailable:
- self._status_panel.set_global_status(
+ self._eip_status.set_eip_status(
# XXX this should change to polkit-kde where
# applicable.
self.tr("We could not find any "
@@ -1266,30 +1290,30 @@ class MainWindow(QtGui.QMainWindow):
error=True)
self._set_eipstatus_off()
except EIPNoTunKextLoaded:
- self._status_panel.set_global_status(
+ self._eip_status.set_eip_status(
self.tr("Encrypted Internet cannot be started because "
"the tuntap extension is not installed properly "
"in your system."))
self._set_eipstatus_off()
except EIPNoPkexecAvailable:
- self._status_panel.set_global_status(
+ self._eip_status.set_eip_status(
self.tr("We could not find <b>pkexec</b> "
"in your system."),
error=True)
self._set_eipstatus_off()
except OpenVPNNotFoundException:
- self._status_panel.set_global_status(
+ self._eip_status.set_eip_status(
self.tr("We could not find openvpn binary."),
error=True)
self._set_eipstatus_off()
except OpenVPNAlreadyRunning as e:
- self._status_panel.set_global_status(
+ 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()
except AlienOpenVPNAlreadyRunning as e:
- self._status_panel.set_global_status(
+ 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."),
@@ -1298,17 +1322,17 @@ class MainWindow(QtGui.QMainWindow):
except VPNLauncherException as e:
# XXX We should implement again translatable exceptions so
# we can pass a translatable string to the panel (usermessage attr)
- self._status_panel.set_global_status("%s" % (e,), error=True)
+ self._eip_status.set_eip_status("%s" % (e,), error=True)
self._set_eipstatus_off()
else:
self._already_started_eip = True
@QtCore.Slot()
- def _stop_eip(self, abnormal=False):
+ def _stop_eip(self):
"""
SLOT
TRIGGERS:
- self._status_panel.stop_eip
+ self._eip_status.stop_eip
self._action_eip_startstop.triggered
or called from _eip_finished
@@ -1318,29 +1342,28 @@ class MainWindow(QtGui.QMainWindow):
:param abnormal: whether this was an abnormal termination.
:type abnormal: bool
"""
- if abnormal:
- logger.warning("Abnormal EIP termination.")
-
self.user_stopped_eip = True
self._vpn.terminate()
- self._set_eipstatus_off()
-
+ self._set_eipstatus_off(False)
self._already_started_eip = False
- # XXX do via signal
- self._settings.set_defaultprovider(None)
+ logger.debug('Setting autostart to: False')
+ self._settings.set_autostart_eip(False)
+
if self._logged_user:
- self._status_panel.set_provider(
+ self._eip_status.set_provider(
"%s@%s" % (self._logged_user,
self._get_best_provider_config().get_domain()))
+ self._eip_status.eip_stopped()
- def _set_eipstatus_off(self):
+ def _set_eipstatus_off(self, error=True):
"""
Sets eip status to off
"""
- self._status_panel.set_eip_status(self.tr("OFF"), error=True)
- self._status_panel.set_eip_status_icon("error")
+ self._eip_status.set_eip_status(self.tr("EIP has stopped"),
+ error=error)
+ self._eip_status.set_eip_status_icon("error")
def _download_eip_config(self):
"""
@@ -1355,7 +1378,7 @@ class MainWindow(QtGui.QMainWindow):
not self._already_started_eip:
# XXX this should be handled by the state machine.
- self._status_panel.set_eip_status(
+ self._eip_status.set_eip_status(
self.tr("Starting..."))
self._eip_bootstrapper.run_eip_setup_checks(
provider_config,
@@ -1363,11 +1386,11 @@ class MainWindow(QtGui.QMainWindow):
self._already_started_eip = True
elif not self._already_started_eip:
if self._enabled_services.count(self.OPENVPN_SERVICE) > 0:
- self._status_panel.set_eip_status(
+ self._eip_status.set_eip_status(
self.tr("Not supported"),
error=True)
else:
- self._status_panel.set_eip_status(self.tr("Disabled"))
+ self._eip_status.set_eip_status(self.tr("Disabled"))
def _finish_eip_bootstrap(self, data):
"""
@@ -1382,7 +1405,7 @@ class MainWindow(QtGui.QMainWindow):
if not passed:
error_msg = self.tr("There was a problem with the provider")
- self._status_panel.set_eip_status(error_msg, error=True)
+ self._eip_status.set_eip_status(error_msg, error=True)
logger.error(data[self._eip_bootstrapper.ERROR_KEY])
self._already_started_eip = False
return
@@ -1390,19 +1413,15 @@ class MainWindow(QtGui.QMainWindow):
provider_config = self._get_best_provider_config()
domain = provider_config.get_domain()
- loaded = self._eip_config.loaded()
- if not loaded:
- eip_config_path = os.path.join("leap", "providers",
- domain, "eip-service.json")
- api_version = provider_config.get_api_version()
- self._eip_config.set_api_version(api_version)
- loaded = self._eip_config.load(eip_config_path)
+ # XXX move check to _start_eip ?
+ loaded = eipconfig.load_eipconfig_if_needed(
+ provider_config, self._eip_config, domain)
if loaded:
# DO START EIP Connection!
self._eip_connection.qtsigs.do_connect_signal.emit()
else:
- self._status_panel.set_eip_status(
+ self._eip_status.set_eip_status(
self.tr("Could not load Encrypted Internet "
"Configuration."),
error=True)
@@ -1437,7 +1456,7 @@ class MainWindow(QtGui.QMainWindow):
def _logout(self):
"""
SLOT
- TRIGGER: self.ui.action_log_out.triggered
+ TRIGGER: self._login_widget.logout
Starts the logout sequence
"""
@@ -1457,16 +1476,17 @@ class MainWindow(QtGui.QMainWindow):
Switches the stackedWidget back to the login stage after
logging out
"""
+ self._login_widget.done_logout()
+
if ok:
self._logged_user = None
- self.ui.action_log_out.setEnabled(False)
- self.ui.stackedWidget.setCurrentIndex(self.LOGIN_INDEX)
- self._login_widget.set_password("")
- self._login_widget.set_enabled(True)
- self._login_widget.set_status("")
+
+ self._login_widget.logged_out()
+
else:
- status_text = self.tr("Something went wrong with the logout.")
- self._status_panel.set_global_status(status_text, error=True)
+ self._login_widget.set_login_status(
+ self.tr("Something went wrong with the logout."),
+ error=True)
def _intermediate_stage(self, data):
"""
@@ -1531,37 +1551,36 @@ class MainWindow(QtGui.QMainWindow):
# TODO we should have a way of parsing the latest lines in the vpn
# log buffer so we can have a more precise idea of which type
# of error did we have (server side, local problem, etc)
- abnormal = True
+
+ qtsigs = self._eip_connection.qtsigs
+ signal = qtsigs.disconnected_signal
# XXX check if these exitCodes are pkexec/cocoasudo specific
if exitCode in (126, 127):
- self._status_panel.set_global_status(
+ self._eip_status.set_eip_status(
self.tr("Encrypted Internet could not be launched "
"because you did not authenticate properly."),
error=True)
self._vpn.killit()
+ signal = qtsigs.connection_aborted_signal
+
elif exitCode != 0 or not self.user_stopped_eip:
- self._status_panel.set_global_status(
+ self._eip_status.set_eip_status(
self.tr("Encrypted Internet finished in an "
"unexpected manner!"), error=True)
- else:
- abnormal = False
+ 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:
- qtsigs = self._eip_connection.qtsigs
- if abnormal:
- signal = qtsigs.connection_died_signal
- else:
- signal = qtsigs.disconnected_signal
-
# XXX verify that the logic kees the same w/o the abnormal flag
# after the refactor to EIPConnection has been completed
# (eipconductor taking the most of the logic under transitions
# that right now are handled under status_panel)
#self._stop_eip(abnormal)
+
+ # We emit signals to trigger transitions in the state machine:
signal.emit()
def _on_raise_window_event(self, req):
diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py
index 2d17f6c2..58cb05ba 100644
--- a/src/leap/bitmask/gui/preferenceswindow.py
+++ b/src/leap/bitmask/gui/preferenceswindow.py
@@ -27,11 +27,10 @@ from PySide import QtCore, QtGui
from leap.bitmask.config.leapsettings import LeapSettings
from leap.bitmask.gui.ui_preferences import Ui_Preferences
from leap.soledad.client import NoStorageSecret
-from leap.bitmask.crypto.srpauth import SRPAuthBadPassword
+from leap.bitmask.crypto.srpauth import SRPAuthBadUserOrPassword
from leap.bitmask.util.password import basic_password_checks
from leap.bitmask.services import get_supported
from leap.bitmask.config.providerconfig import ProviderConfig
-from leap.bitmask.services.eip.eipconfig import EIPConfig, VPNGatewaySelector
from leap.bitmask.services import get_service_display_name
logger = logging.getLogger(__name__)
@@ -60,7 +59,6 @@ class PreferencesWindow(QtGui.QDialog):
self.ui.setupUi(self)
self.ui.lblPasswordChangeStatus.setVisible(False)
self.ui.lblProvidersServicesStatus.setVisible(False)
- self.ui.lblProvidersGatewayStatus.setVisible(False)
self._selected_services = set()
@@ -68,11 +66,6 @@ class PreferencesWindow(QtGui.QDialog):
self.ui.pbChangePassword.clicked.connect(self._change_password)
self.ui.cbProvidersServices.currentIndexChanged[unicode].connect(
self._populate_services)
- self.ui.cbProvidersGateway.currentIndexChanged[unicode].connect(
- self._populate_gateways)
-
- self.ui.cbGateways.currentIndexChanged[unicode].connect(
- lambda x: self.ui.lblProvidersGatewayStatus.setVisible(False))
if not self._settings.get_configured_providers():
self.ui.gbEnabledServices.setEnabled(False)
@@ -185,7 +178,7 @@ class PreferencesWindow(QtGui.QDialog):
logger.error("Error changing password: %s", (failure, ))
problem = self.tr("There was a problem changing the password.")
- if failure.check(SRPAuthBadPassword):
+ if failure.check(SRPAuthBadUserOrPassword):
problem = self.tr("You did not enter a correct current password.")
self._set_password_change_status(problem, error=True)
@@ -217,37 +210,13 @@ class PreferencesWindow(QtGui.QDialog):
self.ui.lblProvidersServicesStatus.setVisible(True)
self.ui.lblProvidersServicesStatus.setText(status)
- def _set_providers_gateway_status(self, status, success=False,
- error=False):
- """
- Sets the status label for the gateway change.
-
- :param status: status message to display, can be HTML
- :type status: str
- :param success: is set to True if we should display the
- message as green
- :type success: bool
- :param error: is set to True if we should display the
- message as red
- :type error: bool
- """
- if success:
- status = "<font color='green'><b>%s</b></font>" % (status,)
- elif error:
- status = "<font color='red'><b>%s</b></font>" % (status,)
-
- self.ui.lblProvidersGatewayStatus.setVisible(True)
- self.ui.lblProvidersGatewayStatus.setText(status)
-
def _add_configured_providers(self):
"""
Add the client's configured providers to the providers combo boxes.
"""
self.ui.cbProvidersServices.clear()
- self.ui.cbProvidersGateway.clear()
for provider in self._settings.get_configured_providers():
self.ui.cbProvidersServices.addItem(provider)
- self.ui.cbProvidersGateway.addItem(provider)
def _service_selection_changed(self, service, state):
"""
@@ -366,90 +335,3 @@ class PreferencesWindow(QtGui.QDialog):
provider_config = None
return provider_config
-
- def _save_selected_gateway(self, provider):
- """
- SLOT
- TRIGGERS:
- self.ui.pbSaveGateway.clicked
-
- Saves the new gateway setting to the configuration file.
-
- :param provider: the provider config that we need to save.
- :type provider: str
- """
- gateway = self.ui.cbGateways.currentText()
-
- if gateway == self.AUTOMATIC_GATEWAY_LABEL:
- gateway = self._settings.GATEWAY_AUTOMATIC
- else:
- idx = self.ui.cbGateways.currentIndex()
- gateway = self.ui.cbGateways.itemData(idx)
-
- self._settings.set_selected_gateway(provider, gateway)
-
- msg = self.tr(
- "Gateway settings for provider '{0}' saved.".format(provider))
- logger.debug(msg)
- self._set_providers_gateway_status(msg, success=True)
-
- def _populate_gateways(self, domain):
- """
- SLOT
- TRIGGERS:
- self.ui.cbProvidersGateway.currentIndexChanged[unicode]
-
- Loads the gateways that the provider provides into the UI for
- the user to select.
-
- :param domain: the domain of the provider to load gateways from.
- :type domain: str
- """
- # We hide the maybe-visible status label after a change
- self.ui.lblProvidersGatewayStatus.setVisible(False)
-
- if not domain:
- return
-
- try:
- # disconnect prevoiusly connected save method
- self.ui.pbSaveGateway.clicked.disconnect()
- except RuntimeError:
- pass # Signal was not connected
-
- # set the proper connection for the 'save' button
- save_gateway = partial(self._save_selected_gateway, domain)
- self.ui.pbSaveGateway.clicked.connect(save_gateway)
-
- eip_config = EIPConfig()
- provider_config = self._get_provider_config(domain)
-
- eip_config_path = os.path.join("leap", "providers",
- domain, "eip-service.json")
- api_version = provider_config.get_api_version()
- eip_config.set_api_version(api_version)
- eip_loaded = eip_config.load(eip_config_path)
-
- if not eip_loaded or provider_config is None:
- self._set_providers_gateway_status(
- self.tr("There was a problem with configuration files."),
- error=True)
- return
-
- gateways = VPNGatewaySelector(eip_config).get_gateways_list()
- logger.debug(gateways)
-
- self.ui.cbGateways.clear()
- self.ui.cbGateways.addItem(self.AUTOMATIC_GATEWAY_LABEL)
-
- # Add the available gateways and
- # select the one stored in configuration file.
- selected_gateway = self._settings.get_selected_gateway(domain)
- index = 0
- for idx, (gw_name, gw_ip) in enumerate(gateways):
- gateway = "{0} ({1})".format(gw_name, gw_ip)
- self.ui.cbGateways.addItem(gateway, gw_ip)
- if gw_ip == selected_gateway:
- index = idx + 1
-
- self.ui.cbGateways.setCurrentIndex(index)
diff --git a/src/leap/bitmask/gui/statemachines.py b/src/leap/bitmask/gui/statemachines.py
index c3dd5ed3..94726720 100644
--- a/src/leap/bitmask/gui/statemachines.py
+++ b/src/leap/bitmask/gui/statemachines.py
@@ -128,11 +128,25 @@ class ConnectionMachineBuilder(object):
states[_OFF])
# * If we receive the connection_died, we transition
- # to the off state
+ # from on directly to the off state
states[_ON].addTransition(
conn.qtsigs.connection_died_signal,
states[_OFF])
+ # * If we receive the connection_aborted, we transition
+ # from connecting to the off state
+ states[_CON].addTransition(
+ conn.qtsigs.connection_aborted_signal,
+ states[_OFF])
+ # * Connection died can in some cases also be
+ # triggered while we are in CONNECTING
+ # state. I should be avoided, since connection_aborted
+ # is clearer (and reserve connection_died
+ # for transitions from on->off
+ states[_CON].addTransition(
+ conn.qtsigs.connection_died_signal,
+ states[_OFF])
+
# adding states to the machine
for state in states.itervalues():
machine.addState(state)
diff --git a/src/leap/bitmask/gui/statuspanel.py b/src/leap/bitmask/gui/statuspanel.py
deleted file mode 100644
index 679f00b1..00000000
--- a/src/leap/bitmask/gui/statuspanel.py
+++ /dev/null
@@ -1,710 +0,0 @@
-# -*- coding: utf-8 -*-
-# statuspanel.py
-# Copyright (C) 2013 LEAP
-#
-# 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/>.
-"""
-Status Panel widget implementation
-"""
-import logging
-
-from datetime import datetime
-from functools import partial
-
-from PySide import QtCore, QtGui
-
-from leap.bitmask.services.eip.connection import EIPConnection
-from leap.bitmask.services.eip.vpnprocess import VPNManager
-from leap.bitmask.platform_init import IS_WIN, IS_LINUX
-from leap.bitmask.util.averages import RateMovingAverage
-from leap.common.check import leap_assert, leap_assert_type
-from leap.common.events import register
-from leap.common.events import events_pb2 as proto
-
-from ui_statuspanel import Ui_StatusPanel
-
-logger = logging.getLogger(__name__)
-
-
-class StatusPanelWidget(QtGui.QWidget):
- """
- Status widget that displays the current state of the LEAP services
- """
- DISPLAY_TRAFFIC_RATES = True
- RATE_STR = "%14.2f KB/s"
- TOTAL_STR = "%14.2f Kb"
-
- MAIL_OFF_ICON = ":/images/mail-unlocked.png"
- MAIL_ON_ICON = ":/images/mail-locked.png"
-
- eip_connection_connected = QtCore.Signal()
- _soledad_event = QtCore.Signal(object)
- _smtp_event = QtCore.Signal(object)
- _imap_event = QtCore.Signal(object)
- _keymanager_event = QtCore.Signal(object)
-
- def __init__(self, parent=None):
- QtGui.QWidget.__init__(self, parent)
-
- self._systray = None
- self._eip_status_menu = None
-
- self.ui = Ui_StatusPanel()
- self.ui.setupUi(self)
-
- self.eipconnection = EIPConnection()
-
- self.hide_status_box()
-
- # set systray tooltip statuses
- self._eip_status = self._mx_status = ""
-
- # Set the EIP status icons
- self.CONNECTING_ICON = None
- self.CONNECTED_ICON = None
- self.ERROR_ICON = None
- self.CONNECTING_ICON_TRAY = None
- self.CONNECTED_ICON_TRAY = None
- self.ERROR_ICON_TRAY = None
- self._set_eip_icons()
-
- self._set_traffic_rates()
- self._make_status_clickable()
-
- register(signal=proto.KEYMANAGER_LOOKING_FOR_KEY,
- callback=self._mail_handle_keymanager_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.KEYMANAGER_KEY_FOUND,
- callback=self._mail_handle_keymanager_events,
- reqcbk=lambda req, resp: None)
-
- # register(signal=proto.KEYMANAGER_KEY_NOT_FOUND,
- # callback=self._mail_handle_keymanager_events,
- # reqcbk=lambda req, resp: None)
-
- register(signal=proto.KEYMANAGER_STARTED_KEY_GENERATION,
- callback=self._mail_handle_keymanager_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.KEYMANAGER_FINISHED_KEY_GENERATION,
- callback=self._mail_handle_keymanager_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.KEYMANAGER_DONE_UPLOADING_KEYS,
- callback=self._mail_handle_keymanager_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.SOLEDAD_DONE_DOWNLOADING_KEYS,
- callback=self._mail_handle_soledad_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.SOLEDAD_DONE_UPLOADING_KEYS,
- callback=self._mail_handle_soledad_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.SMTP_SERVICE_STARTED,
- callback=self._mail_handle_smtp_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.SMTP_SERVICE_FAILED_TO_START,
- callback=self._mail_handle_smtp_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.IMAP_SERVICE_STARTED,
- callback=self._mail_handle_imap_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.IMAP_SERVICE_FAILED_TO_START,
- callback=self._mail_handle_imap_events,
- reqcbk=lambda req, resp: None)
-
- register(signal=proto.IMAP_UNREAD_MAIL,
- callback=self._mail_handle_imap_events,
- reqcbk=lambda req, resp: None)
-
- self._set_long_mail_status("")
- self.ui.lblUnread.setVisible(False)
-
- self._smtp_started = False
- self._imap_started = False
-
- self._soledad_event.connect(
- self._mail_handle_soledad_events_slot)
- self._imap_event.connect(
- self._mail_handle_imap_events_slot)
- self._smtp_event.connect(
- self._mail_handle_smtp_events_slot)
- self._keymanager_event.connect(
- self._mail_handle_keymanager_events_slot)
-
- def _make_status_clickable(self):
- """
- Makes upload and download figures clickable.
- """
- onclicked = self._on_VPN_status_clicked
- self.ui.btnUpload.clicked.connect(onclicked)
- self.ui.btnDownload.clicked.connect(onclicked)
-
- def _on_VPN_status_clicked(self):
- """
- SLOT
- TRIGGER: self.ui.btnUpload.clicked
- self.ui.btnDownload.clicked
-
- Toggles between rate and total throughput display for vpn
- status figures.
- """
- self.DISPLAY_TRAFFIC_RATES = not self.DISPLAY_TRAFFIC_RATES
- self.update_vpn_status(None) # refresh
-
- def _set_traffic_rates(self):
- """
- Initializes up and download rates.
- """
- self._up_rate = RateMovingAverage()
- self._down_rate = RateMovingAverage()
-
- self.ui.btnUpload.setText(self.RATE_STR % (0,))
- self.ui.btnDownload.setText(self.RATE_STR % (0,))
-
- def _reset_traffic_rates(self):
- """
- Resets up and download rates, and cleans up the labels.
- """
- self._up_rate.reset()
- self._down_rate.reset()
- self.update_vpn_status(None)
-
- def _update_traffic_rates(self, up, down):
- """
- Updates up and download rates.
-
- :param up: upload total.
- :type up: int
- :param down: download total.
- :type down: int
- """
- ts = datetime.now()
- self._up_rate.append((ts, up))
- self._down_rate.append((ts, down))
-
- def _get_traffic_rates(self):
- """
- Gets the traffic rates (in KB/s).
-
- :returns: a tuple with the (up, down) rates
- :rtype: tuple
- """
- up = self._up_rate
- down = self._down_rate
-
- return (up.get_average(), down.get_average())
-
- def _get_traffic_totals(self):
- """
- Gets the traffic total throughput (in Kb).
-
- :returns: a tuple with the (up, down) totals
- :rtype: tuple
- """
- up = self._up_rate
- down = self._down_rate
-
- return (up.get_total(), down.get_total())
-
- def _set_eip_icons(self):
- """
- Sets the EIP status icons for the main window and for the tray
-
- MAC : dark icons
- LINUX : dark icons in window, light icons in tray
- WIN : light icons
- """
- EIP_ICONS = EIP_ICONS_TRAY = (
- ":/images/conn_connecting-light.png",
- ":/images/conn_connected-light.png",
- ":/images/conn_error-light.png")
-
- if IS_LINUX:
- EIP_ICONS_TRAY = (
- ":/images/conn_connecting.png",
- ":/images/conn_connected.png",
- ":/images/conn_error.png")
- elif IS_WIN:
- EIP_ICONS = EIP_ICONS_TRAY = (
- ":/images/conn_connecting.png",
- ":/images/conn_connected.png",
- ":/images/conn_error.png")
-
- self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0])
- self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1])
- self.ERROR_ICON = QtGui.QPixmap(EIP_ICONS[2])
-
- self.CONNECTING_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[0])
- self.CONNECTED_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[1])
- self.ERROR_ICON_TRAY = QtGui.QPixmap(EIP_ICONS_TRAY[2])
-
- # Systray and actions
-
- def set_systray(self, systray):
- """
- Sets the systray object to use.
-
- :param systray: Systray object
- :type systray: QtGui.QSystemTrayIcon
- """
- leap_assert_type(systray, QtGui.QSystemTrayIcon)
- self._systray = systray
- self._systray.setToolTip(self.tr("All services are OFF"))
-
- def _update_systray_tooltip(self):
- """
- Updates the system tray icon tooltip using the eip and mx statuses.
- """
- status = self.tr("Encrypted Internet is {0}").format(self._eip_status)
- status += '\n'
- status += self.tr("Mail is {0}").format(self._mx_status)
- self._systray.setToolTip(status)
-
- def set_action_eip_startstop(self, action_eip_startstop):
- """
- Sets the action_eip_startstop to use.
-
- :param action_eip_startstop: action_eip_status to be used
- :type action_eip_startstop: QtGui.QAction
- """
- self._action_eip_startstop = action_eip_startstop
-
- def set_eip_status_menu(self, eip_status_menu):
- """
- Sets the eip_status_menu to use.
-
- :param eip_status_menu: eip_status_menu to be used
- :type eip_status_menu: QtGui.QMenu
- """
- leap_assert_type(eip_status_menu, QtGui.QMenu)
- self._eip_status_menu = eip_status_menu
-
- def set_action_mail_status(self, action_mail_status):
- """
- Sets the action_mail_status to use.
-
- :param action_mail_status: action_mail_status to be used
- :type action_mail_status: QtGui.QAction
- """
- leap_assert_type(action_mail_status, QtGui.QAction)
- self._action_mail_status = action_mail_status
-
- def set_global_status(self, status, error=False):
- """
- Sets the global status label.
-
- :param status: status message
- :type status: str or unicode
- :param error: if the status is an erroneous one, then set this
- to True
- :type error: bool
- """
- leap_assert_type(error, bool)
- if error:
- status = "<font color='red'><b>%s</b></font>" % (status,)
- self.ui.lblGlobalStatus.setText(status)
- self.ui.globalStatusBox.show()
-
- def hide_status_box(self):
- """
- Hide global status box.
- """
- self.ui.globalStatusBox.hide()
-
- # EIP status ---
-
- @property
- def eip_button(self):
- return self.ui.btnEipStartStop
-
- @property
- def eip_label(self):
- return self.ui.lblEIPStatus
-
- def eip_pre_up(self):
- """
- Triggered when the app activates eip.
- Hides the status box and disables the start/stop button.
- """
- self.hide_status_box()
- self.set_startstop_enabled(False)
-
- # XXX disable (later) --------------------------
- def set_eip_status(self, status, error=False):
- """
- Sets the status label at the VPN stage to status
-
- :param status: status message
- :type status: str or unicode
- :param error: if the status is an erroneous one, then set this
- to True
- :type error: bool
- """
- leap_assert_type(error, bool)
-
- self._eip_status = status
-
- if error:
- status = "<font color='red'>%s</font>" % (status,)
- self.ui.lblEIPStatus.setText(status)
- self._update_systray_tooltip()
-
- # XXX disable ---------------------------------
- def set_startstop_enabled(self, value):
- """
- Enable or disable btnEipStartStop and _action_eip_startstop
- based on value
-
- :param value: True for enabled, False otherwise
- :type value: bool
- """
- leap_assert_type(value, bool)
- self.ui.btnEipStartStop.setEnabled(value)
- self._action_eip_startstop.setEnabled(value)
-
- # XXX disable -----------------------------
- def eip_started(self):
- """
- 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):
- """
- 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)
-
- def update_vpn_status(self, data):
- """
- SLOT
- TRIGGER: VPN.status_changed
-
- Updates the download/upload labels based on the data provided
- by the VPN thread.
-
- :param data: a dictionary with the tcp/udp write and read totals.
- If data is None, we just will refresh the display based
- on the previous data.
- :type data: dict
- """
- if data:
- upload = float(data[VPNManager.TCPUDP_WRITE_KEY] or "0")
- download = float(data[VPNManager.TCPUDP_READ_KEY] or "0")
- self._update_traffic_rates(upload, download)
-
- if self.DISPLAY_TRAFFIC_RATES:
- uprate, downrate = self._get_traffic_rates()
- upload_str = self.RATE_STR % (uprate,)
- download_str = self.RATE_STR % (downrate,)
-
- else: # display total throughput
- uptotal, downtotal = self._get_traffic_totals()
- upload_str = self.TOTAL_STR % (uptotal,)
- download_str = self.TOTAL_STR % (downtotal,)
-
- self.ui.btnUpload.setText(upload_str)
- self.ui.btnDownload.setText(download_str)
-
- def update_vpn_state(self, data):
- """
- SLOT
- TRIGGER: VPN.state_changed
-
- Updates the displayed VPN state based on the data provided by
- the VPN thread.
-
- Emits:
- If the status is connected, we emit EIPConnection.qtsigs.
- connected_signal
- """
- status = data[VPNManager.STATUS_STEP_KEY]
- self.set_eip_status_icon(status)
- if status == "CONNECTED":
- # XXX should be handled by the state machine too.
- self.set_eip_status(self.tr("ON"))
- logger.debug("STATUS IS CONNECTED --- emitting signal")
- self.eip_connection_connected.emit()
-
- # XXX should lookup status map in EIPConnection
- elif status == "AUTH":
- self.set_eip_status(self.tr("Authenticating..."))
- elif status == "GET_CONFIG":
- self.set_eip_status(self.tr("Retrieving configuration..."))
- elif status == "WAIT":
- self.set_eip_status(self.tr("Waiting to start..."))
- elif status == "ASSIGN_IP":
- self.set_eip_status(self.tr("Assigning IP"))
- elif status == "RECONNECTING":
- self.set_eip_status(self.tr("Reconnecting..."))
- elif status == "ALREADYRUNNING":
- # Put the following calls in Qt's event queue, otherwise
- # the UI won't update properly
- QtCore.QTimer.singleShot(
- 0, self.eipconnection.qtsigs.do_disconnect_signal)
- QtCore.QTimer.singleShot(0, partial(self.set_global_status,
- self.tr("Unable to start VPN, "
- "it's already "
- "running.")))
- else:
- self.set_eip_status(status)
-
- def set_eip_icon(self, icon):
- """
- Sets the icon to display for EIP
-
- :param icon: icon to display
- :type icon: QPixmap
- """
- self.ui.lblVPNStatusIcon.setPixmap(icon)
-
- def set_eip_status_icon(self, status):
- """
- Given a status step from the VPN thread, set the icon properly
-
- :param status: status step
- :type status: str
- """
- selected_pixmap = self.ERROR_ICON
- selected_pixmap_tray = self.ERROR_ICON_TRAY
- tray_message = self.tr("Encrypted Internet is OFF")
- if status in ("WAIT", "AUTH", "GET_CONFIG",
- "RECONNECTING", "ASSIGN_IP"):
- selected_pixmap = self.CONNECTING_ICON
- selected_pixmap_tray = self.CONNECTING_ICON_TRAY
- tray_message = self.tr("Encrypted Internet is STARTING")
- elif status in ("CONNECTED"):
- tray_message = self.tr("Encrypted Internet is ON")
- selected_pixmap = self.CONNECTED_ICON
- selected_pixmap_tray = self.CONNECTED_ICON_TRAY
-
- self.set_eip_icon(selected_pixmap)
- self._systray.setIcon(QtGui.QIcon(selected_pixmap_tray))
- self._eip_status_menu.setTitle(tray_message)
-
- def set_provider(self, provider):
- self.ui.lblProvider.setText(provider)
-
- #
- # mail methods
- #
-
- def _set_mail_status(self, status, ready=False):
- """
- Sets the Mail status in the label and in the tray icon.
-
- :param status: the status text to display
- :type status: unicode
- :param ready: if mx is ready or not.
- :type ready: bool
- """
- self.ui.lblMailStatus.setText(status)
-
- self._mx_status = self.tr('OFF')
- tray_status = self.tr('Mail is OFF')
-
- icon = QtGui.QPixmap(self.MAIL_OFF_ICON)
- if ready:
- icon = QtGui.QPixmap(self.MAIL_ON_ICON)
- self._mx_status = self.tr('ON')
- tray_status = self.tr('Mail is ON')
-
- self.ui.lblMailIcon.setPixmap(icon)
- self._action_mail_status.setText(tray_status)
- self._update_systray_tooltip()
-
- def _mail_handle_soledad_events(self, req):
- """
- Callback for ...
-
- :param req: Request type
- :type req: leap.common.events.events_pb2.SignalRequest
- """
- self._soledad_event.emit(req)
-
- def _mail_handle_soledad_events_slot(self, req):
- """
- SLOT
- TRIGGER: _mail_handle_soledad_events
-
- Reacts to an Soledad event
-
- :param req: Request type
- :type req: leap.common.events.events_pb2.SignalRequest
- """
- self._set_mail_status(self.tr("Starting..."))
-
- ext_status = ""
-
- if req.event == proto.SOLEDAD_DONE_UPLOADING_KEYS:
- ext_status = self.tr("Soledad has started...")
- elif req.event == proto.SOLEDAD_DONE_DOWNLOADING_KEYS:
- ext_status = self.tr("Soledad is starting, please wait...")
- else:
- leap_assert(False,
- "Don't know how to handle this state: %s"
- % (req.event))
-
- self._set_long_mail_status(ext_status)
-
- def _mail_handle_keymanager_events(self, req):
- """
- Callback for the KeyManager events
-
- :param req: Request type
- :type req: leap.common.events.events_pb2.SignalRequest
- """
- self._keymanager_event.emit(req)
-
- def _mail_handle_keymanager_events_slot(self, req):
- """
- SLOT
- TRIGGER: _mail_handle_keymanager_events
-
- Reacts to an KeyManager event
-
- :param req: Request type
- :type req: leap.common.events.events_pb2.SignalRequest
- """
- # We want to ignore this kind of events once everything has
- # started
- if self._smtp_started and self._imap_started:
- return
-
- self._set_mail_status(self.tr("Starting..."))
-
- ext_status = ""
-
- if req.event == proto.KEYMANAGER_LOOKING_FOR_KEY:
- ext_status = self.tr("Looking for key for this user")
- elif req.event == proto.KEYMANAGER_KEY_FOUND:
- ext_status = self.tr("Found key! Starting mail...")
- # elif req.event == proto.KEYMANAGER_KEY_NOT_FOUND:
- # ext_status = self.tr("Key not found!")
- elif req.event == proto.KEYMANAGER_STARTED_KEY_GENERATION:
- ext_status = self.tr("Generating new key, please wait...")
- elif req.event == proto.KEYMANAGER_FINISHED_KEY_GENERATION:
- ext_status = self.tr("Finished generating key!")
- elif req.event == proto.KEYMANAGER_DONE_UPLOADING_KEYS:
- ext_status = self.tr("Starting mail...")
- else:
- leap_assert(False,
- "Don't know how to handle this state: %s"
- % (req.event))
-
- self._set_long_mail_status(ext_status)
-
- def _mail_handle_smtp_events(self, req):
- """
- Callback for the SMTP events
-
- :param req: Request type
- :type req: leap.common.events.events_pb2.SignalRequest
- """
- self._smtp_event.emit(req)
-
- def _mail_handle_smtp_events_slot(self, req):
- """
- SLOT
- TRIGGER: _mail_handle_smtp_events
-
- Reacts to an SMTP event
-
- :param req: Request type
- :type req: leap.common.events.events_pb2.SignalRequest
- """
- ext_status = ""
-
- if req.event == proto.SMTP_SERVICE_STARTED:
- ext_status = self.tr("SMTP has started...")
- self._smtp_started = True
- if self._smtp_started and self._imap_started:
- self._set_mail_status(self.tr("ON"), ready=True)
- ext_status = ""
- elif req.event == proto.SMTP_SERVICE_FAILED_TO_START:
- ext_status = self.tr("SMTP failed to start, check the logs.")
- self._set_mail_status(self.tr("Failed"))
- else:
- leap_assert(False,
- "Don't know how to handle this state: %s"
- % (req.event))
-
- self._set_long_mail_status(ext_status)
-
- def _mail_handle_imap_events(self, req):
- """
- Callback for the IMAP events
-
- :param req: Request type
- :type req: leap.common.events.events_pb2.SignalRequest
- """
- self._imap_event.emit(req)
-
- def _mail_handle_imap_events_slot(self, req):
- """
- SLOT
- TRIGGER: _mail_handle_imap_events
-
- Reacts to an IMAP event
-
- :param req: Request type
- :type req: leap.common.events.events_pb2.SignalRequest
- """
- ext_status = None
-
- if req.event == proto.IMAP_SERVICE_STARTED:
- ext_status = self.tr("IMAP has started...")
- self._imap_started = True
- if self._smtp_started and self._imap_started:
- self._set_mail_status(self.tr("ON"), ready=True)
- ext_status = ""
- elif req.event == proto.IMAP_SERVICE_FAILED_TO_START:
- ext_status = self.tr("IMAP failed to start, check the logs.")
- self._set_mail_status(self.tr("Failed"))
- elif req.event == proto.IMAP_UNREAD_MAIL:
- if self._smtp_started and self._imap_started:
- self.ui.lblUnread.setText(
- self.tr("%s Unread Emails") % (req.content))
- self.ui.lblUnread.setVisible(req.content != "0")
- self._set_mail_status(self.tr("ON"), ready=True)
- else:
- leap_assert(False, # XXX ???
- "Don't know how to handle this state: %s"
- % (req.event))
-
- if ext_status is not None:
- self._set_long_mail_status(ext_status)
-
- def _set_long_mail_status(self, ext_status):
- self.ui.lblLongMailStatus.setText(ext_status)
- self.ui.grpMailStatus.setVisible(len(ext_status) > 0)
diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui
new file mode 100644
index 00000000..27df3f31
--- /dev/null
+++ b/src/leap/bitmask/gui/ui/eip_status.ui
@@ -0,0 +1,287 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EIPStatus</class>
+ <widget class="QWidget" name="EIPStatus">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>470</width>
+ <height>157</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="bottomMargin">
+ <number>24</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="2">
+ <widget class="QPushButton" name="btnEipStartStop">
+ <property name="text">
+ <string>Turn On</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="maximumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/earth.png</pixmap>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="lblEIPStatus">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(80, 80, 80);</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="lblEIPMessage">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>14</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Traffic is being routed in the clear</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="lblVPNStatusIcon">
+ <property name="maximumSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/off.png</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" colspan="3">
+ <widget class="QWidget" name="eip_bandwidth" native="true">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>32</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="eip_bandwidth_layout">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="../../../../../data/resources/icons.qrc">:/images/light/16/down-arrow.png</pixmap>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnDownload">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>120</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>11</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>PointingHandCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>0.0 KB/s</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>10</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="../../../../../data/resources/icons.qrc">:/images/light/16/up-arrow.png</pixmap>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignLeft">
+ <widget class="QPushButton" name="btnUpload">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>120</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>11</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>PointingHandCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>0.0 KB/s</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../../../../../data/resources/mainwindow.qrc"/>
+ <include location="../../../../../data/resources/icons.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/leap/bitmask/gui/ui/eippreferences.ui b/src/leap/bitmask/gui/ui/eippreferences.ui
new file mode 100644
index 00000000..9493d330
--- /dev/null
+++ b/src/leap/bitmask/gui/ui/eippreferences.ui
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EIPPreferences</class>
+ <widget class="QDialog" name="EIPPreferences">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>398</width>
+ <height>262</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>EIP Preferences</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="../../../../../data/resources/mainwindow.qrc">
+ <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="1" column="0">
+ <widget class="QGroupBox" name="gbGatewaySelector">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Select gateway for provider</string>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="lblSelectProvider">
+ <property name="text">
+ <string>&amp;Select provider:</string>
+ </property>
+ <property name="buddy">
+ <cstring>cbProvidersGateway</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2">
+ <widget class="QComboBox" name="cbProvidersGateway">
+ <item>
+ <property name="text">
+ <string>&lt;Select provider&gt;</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="7" column="2">
+ <widget class="QPushButton" name="pbSaveGateway">
+ <property name="text">
+ <string>Save this provider settings</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="3">
+ <widget class="QLabel" name="lblProvidersGatewayStatus">
+ <property name="text">
+ <string>&lt; Providers Gateway Status &gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Select gateway:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QComboBox" name="cbGateways">
+ <item>
+ <property name="text">
+ <string>Automatic</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="gbAutomaticEIP">
+ <property name="title">
+ <string>Automatic EIP start</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="3" column="0">
+ <widget class="QLabel" name="lblAutoStartEIPStatus">
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="text">
+ <string>&lt;font color='green'&gt;&lt;b&gt;Automatic EIP start saved!&lt;/b&gt;&lt;/font&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QPushButton" name="pbSaveAutoStartEIP">
+ <property name="text">
+ <string>Save auto start setting</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="cbAutoStartEIP">
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string>Enable Automatic start of EIP</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="cbProvidersEIP">
+ <item>
+ <property name="text">
+ <string>&lt;Select provider&gt;</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ <zorder>cbAutoStartEIP</zorder>
+ <zorder>lblAutoStartEIPStatus</zorder>
+ <zorder>pbSaveAutoStartEIP</zorder>
+ <zorder>cbProvidersEIP</zorder>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>cbAutoStartEIP</tabstop>
+ <tabstop>cbProvidersEIP</tabstop>
+ <tabstop>pbSaveAutoStartEIP</tabstop>
+ <tabstop>cbProvidersGateway</tabstop>
+ <tabstop>cbGateways</tabstop>
+ <tabstop>pbSaveGateway</tabstop>
+ </tabstops>
+ <resources>
+ <include location="../../../../../data/resources/mainwindow.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>cbAutoStartEIP</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>cbProvidersEIP</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>180</x>
+ <y>53</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>238</x>
+ <y>53</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/leap/bitmask/gui/ui/login.ui b/src/leap/bitmask/gui/ui/login.ui
index 42a6897a..a1842608 100644
--- a/src/leap/bitmask/gui/ui/login.ui
+++ b/src/leap/bitmask/gui/ui/login.ui
@@ -6,127 +6,273 @@
<rect>
<x>0</x>
<y>0</y>
- <width>356</width>
- <height>223</height>
+ <width>468</width>
+ <height>350</height>
</rect>
</property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="windowTitle">
<string>Form</string>
</property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
<layout class="QGridLayout" name="gridLayout">
- <item row="5" column="2">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item row="2" column="2" colspan="2">
+ <widget class="QWidget" name="logged_widget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <property name="sizeHint" stdset="0">
+ <property name="minimumSize">
<size>
- <width>40</width>
- <height>20</height>
+ <width>0</width>
+ <height>0</height>
</size>
</property>
- </spacer>
- </item>
- <item row="1" column="1" colspan="2">
- <widget class="QComboBox" name="cmbProviders"/>
+ <layout class="QGridLayout" name="gridLayout_5">
+ <property name="bottomMargin">
+ <number>24</number>
+ </property>
+ <item row="0" column="0" colspan="2">
+ <widget class="QLabel" name="lblUser">
+ <property name="font">
+ <font>
+ <pointsize>15</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="btnLogout">
+ <property name="text">
+ <string>Logout</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QLabel" name="lblLoginStatus">
+ <property name="styleSheet">
+ <string notr="true">color: rgb(132, 132, 132);
+font: 75 12pt &quot;Lucida Grande&quot;;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</item>
- <item row="5" column="0">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <item row="1" column="1" rowspan="2">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <property name="sizeHint" stdset="0">
+ <property name="maximumSize">
<size>
- <width>40</width>
- <height>20</height>
+ <width>16777215</width>
+ <height>800</height>
</size>
</property>
- </spacer>
- </item>
- <item row="6" column="1">
- <widget class="QPushButton" name="btnCreateAccount">
<property name="text">
- <string>Create a new account</string>
+ <string/>
</property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>&lt;b&gt;Provider:&lt;/b&gt;</string>
+ <property name="pixmap">
+ <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/user.png</pixmap>
</property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ <property name="scaledContents">
+ <bool>false</bool>
</property>
- </widget>
- </item>
- <item row="3" column="1" colspan="2">
- <widget class="QLineEdit" name="lnPassword">
- <property name="inputMask">
- <string/>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
- </widget>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QLineEdit" name="lnUser"/>
- </item>
- <item row="4" column="1" colspan="2">
- <widget class="QCheckBox" name="chkRemember">
- <property name="text">
- <string>Remember username and password</string>
+ <property name="margin">
+ <number>0</number>
</property>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>&lt;b&gt;Username:&lt;/b&gt;</string>
+ <item row="1" column="2" colspan="2">
+ <widget class="QWidget" name="login_widget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
</property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <property name="rightMargin">
+ <number>24</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>&lt;b&gt;Provider:&lt;/b&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QPushButton" name="btnLogin">
+ <property name="text">
+ <string>Log In</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="chkRemember">
+ <property name="text">
+ <string>Remember username and password</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lblStatus">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="cmbProviders"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&lt;b&gt;Username:&lt;/b&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="lnUser"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>&lt;b&gt;Password:&lt;/b&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="lnPassword">
+ <property name="inputMask">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
</item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>&lt;b&gt;Password:&lt;/b&gt;</string>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
</property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ <property name="sizeType">
+ <enum>QSizePolicy::Maximum</enum>
</property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="QPushButton" name="btnLogin">
- <property name="text">
- <string>Log In</string>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>12</width>
+ <height>0</height>
+ </size>
</property>
- </widget>
+ </spacer>
</item>
- <item row="0" column="0" colspan="3">
- <widget class="QLabel" name="lblStatus">
+ <item row="0" column="0" colspan="4">
+ <widget class="ClickableLabel" name="clblErrorMsg">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>50</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(255, 127, 114);</string>
+ </property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
</widget>
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>ClickableLabel</class>
+ <extends>QLabel</extends>
+ <header>clickablelabel.h</header>
+ </customwidget>
+ </customwidgets>
<tabstops>
- <tabstop>cmbProviders</tabstop>
- <tabstop>lnUser</tabstop>
- <tabstop>lnPassword</tabstop>
<tabstop>chkRemember</tabstop>
- <tabstop>btnLogin</tabstop>
- <tabstop>btnCreateAccount</tabstop>
</tabstops>
- <resources/>
+ <resources>
+ <include location="../../../../../data/resources/mainwindow.qrc"/>
+ </resources>
<connections/>
</ui>
diff --git a/src/leap/bitmask/gui/ui/mail_status.ui b/src/leap/bitmask/gui/ui/mail_status.ui
new file mode 100644
index 00000000..1327f9e7
--- /dev/null
+++ b/src/leap/bitmask/gui/ui/mail_status.ui
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MailStatusWidget</class>
+ <widget class="QWidget" name="MailStatusWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>72</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1" rowspan="2">
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="1" column="0" colspan="3">
+ <widget class="QLabel" name="lblMailStatus">
+ <property name="styleSheet">
+ <string notr="true">color: rgb(80, 80, 80);</string>
+ </property>
+ <property name="text">
+ <string>You must login to use encrypted email.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Email</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="lblMailStatusIcon">
+ <property name="maximumSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/off.png</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/email.png</pixmap>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../../../../../data/resources/mainwindow.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui
index 17837642..920160b8 100644
--- a/src/leap/bitmask/gui/ui/mainwindow.ui
+++ b/src/leap/bitmask/gui/ui/mainwindow.ui
@@ -6,10 +6,28 @@
<rect>
<x>0</x>
<y>0</y>
- <width>429</width>
- <height>579</height>
+ <width>524</width>
+ <height>722</height>
</rect>
</property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>524</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>524</width>
+ <height>16777215</height>
+ </size>
+ </property>
<property name="windowTitle">
<string>Bitmask</string>
</property>
@@ -28,9 +46,222 @@
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0" colspan="5">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item row="1" column="0" colspan="2">
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>524</width>
+ <height>635</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="widget_2" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="leftMargin">
+ <number>24</number>
+ </property>
+ <property name="rightMargin">
+ <number>24</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="font">
+ <font>
+ <pointsize>16</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Encrypted Internet</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnEIPPreferences">
+ <property name="maximumSize">
+ <size>
+ <width>48</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../../../../../data/resources/mainwindow.qrc">
+ <normaloff>:/images/black/32/gear.png</normaloff>:/images/black/32/gear.png</iconset>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ <property name="default">
+ <bool>false</bool>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="eipLayout">
+ <property name="leftMargin">
+ <number>12</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>12</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="leftMargin">
+ <number>24</number>
+ </property>
+ <property name="rightMargin">
+ <number>24</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="lblLoginProvider">
+ <property name="font">
+ <font>
+ <pointsize>16</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Login</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnPreferences">
+ <property name="maximumSize">
+ <size>
+ <width>48</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../../../../../data/resources/mainwindow.qrc">
+ <normaloff>:/images/black/32/gear.png</normaloff>:/images/black/32/gear.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="loginLayout"/>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="mailLayout">
+ <property name="margin">
+ <number>12</number>
+ </property>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_4">
- <item row="2" column="0">
+ <item row="1" column="1">
+ <widget class="QLabel" name="lblNewUpdates">
+ <property name="text">
+ <string>There are new updates available, please restart.</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -43,7 +274,7 @@
</property>
</spacer>
</item>
- <item row="1" column="1">
+ <item row="0" column="1">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -56,17 +287,7 @@
</property>
</spacer>
</item>
- <item row="2" column="1">
- <widget class="QLabel" name="lblNewUpdates">
- <property name="text">
- <string>There are new updates available, please restart.</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
+ <item row="1" column="2">
<widget class="QPushButton" name="btnMore">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -82,7 +303,7 @@
</property>
</widget>
</item>
- <item row="2" column="3">
+ <item row="1" column="3">
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -97,164 +318,6 @@
</item>
</layout>
</item>
- <item row="6" column="2">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="10" column="0" colspan="5">
- <widget class="QStackedWidget" name="stackedWidget">
- <property name="currentIndex">
- <number>1</number>
- </property>
- <widget class="QWidget" name="loginPage">
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="1">
- <layout class="QHBoxLayout" name="loginLayout"/>
- </item>
- <item row="0" column="2">
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0">
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="page_2">
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="0" column="0">
- <layout class="QVBoxLayout" name="statusLayout"/>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- <item row="7" column="2">
- <widget class="QLabel" name="label">
- <property name="autoFillBackground">
- <bool>false</bool>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/mask-launcher.png</pixmap>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item row="7" column="3" colspan="2">
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="17" column="2">
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="7" column="0" colspan="2">
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="18" column="2">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QPushButton" name="btnPreferences">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="text">
- <string>Preferences</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_10">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="btnShowLog">
- <property name="text">
- <string>Show Log</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- <property name="flat">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
@@ -262,15 +325,15 @@
<rect>
<x>0</x>
<y>0</y>
- <width>429</width>
- <height>21</height>
+ <width>524</width>
+ <height>22</height>
</rect>
</property>
- <widget class="QMenu" name="menuSession">
+ <widget class="QMenu" name="menuFile">
<property name="title">
- <string>&amp;Session</string>
+ <string>&amp;Bitmask</string>
</property>
- <addaction name="action_log_out"/>
+ <addaction name="action_create_new_account"/>
<addaction name="separator"/>
<addaction name="action_quit"/>
</widget>
@@ -279,16 +342,17 @@
<string>Help</string>
</property>
<addaction name="action_help"/>
+ <addaction name="action_show_logs"/>
<addaction name="separator"/>
<addaction name="action_about_leap"/>
</widget>
- <addaction name="menuSession"/>
+ <addaction name="menuFile"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
- <action name="action_log_out">
+ <action name="action_preferences">
<property name="text">
- <string>Log &amp;out</string>
+ <string>Preferences...</string>
</property>
</action>
<action name="action_quit">
@@ -313,7 +377,12 @@
</action>
<action name="action_show_logs">
<property name="text">
- <string>Show &amp;logs</string>
+ <string>Show &amp;Log</string>
+ </property>
+ </action>
+ <action name="action_create_new_account">
+ <property name="text">
+ <string>Create a new account...</string>
</property>
</action>
</widget>
diff --git a/src/leap/bitmask/gui/ui/preferences.ui b/src/leap/bitmask/gui/ui/preferences.ui
index e66a2d68..e187c016 100644
--- a/src/leap/bitmask/gui/ui/preferences.ui
+++ b/src/leap/bitmask/gui/ui/preferences.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>503</width>
- <height>529</height>
+ <height>401</height>
</rect>
</property>
<property name="windowTitle">
@@ -18,7 +18,7 @@
<normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout_3">
- <item row="5" column="0">
+ <item row="4" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -31,64 +31,80 @@
</property>
</spacer>
</item>
- <item row="1" column="0">
- <widget class="QGroupBox" name="gbGatewaySelector">
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="gbPasswordChange">
<property name="enabled">
- <bool>true</bool>
+ <bool>false</bool>
</property>
<property name="title">
- <string>Select gateway for provider</string>
- </property>
- <property name="checkable">
- <bool>false</bool>
+ <string>Password Change</string>
</property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="1" colspan="2">
- <widget class="QComboBox" name="cbProvidersGateway">
- <item>
- <property name="text">
- <string>&lt;Select provider&gt;</string>
- </property>
- </item>
- </widget>
- </item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
<item row="0" column="0">
- <widget class="QLabel" name="lblSelectProvider">
+ <widget class="QLabel" name="lblCurrentPassword">
<property name="text">
- <string>&amp;Select provider:</string>
+ <string>&amp;Current password:</string>
</property>
<property name="buddy">
- <cstring>cbProvidersGateway</cstring>
+ <cstring>leCurrentPassword</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="leCurrentPassword">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="label">
+ <widget class="QLabel" name="lblNewPassword">
<property name="text">
- <string>Select gateway:</string>
+ <string>&amp;New password:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leNewPassword</cstring>
</property>
</widget>
</item>
- <item row="1" column="1" colspan="2">
- <widget class="QComboBox" name="cbGateways">
- <item>
- <property name="text">
- <string>Automatic</string>
- </property>
- </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="leNewPassword">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
</widget>
</item>
- <item row="5" column="2">
- <widget class="QPushButton" name="pbSaveGateway">
+ <item row="2" column="0">
+ <widget class="QLabel" name="lblNewPassword2">
<property name="text">
- <string>Save this provider settings</string>
+ <string>&amp;Re-enter new password:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leNewPassword2</cstring>
</property>
</widget>
</item>
- <item row="2" column="0" colspan="3">
- <widget class="QLabel" name="lblProvidersGatewayStatus">
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="leNewPassword2">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QPushButton" name="pbChangePassword">
<property name="text">
- <string>&lt; Providers Gateway Status &gt;</string>
+ <string>Change</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QLabel" name="lblPasswordChangeStatus">
+ <property name="text">
+ <string>&lt;Password change status&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -98,7 +114,7 @@
</layout>
</widget>
</item>
- <item row="4" column="0">
+ <item row="3" column="0">
<widget class="QGroupBox" name="gbEnabledServices">
<property name="title">
<string>Enabled services</string>
@@ -155,89 +171,6 @@
</layout>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QGroupBox" name="gbPasswordChange">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="title">
- <string>Password Change</string>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::ExpandingFieldsGrow</enum>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="lblCurrentPassword">
- <property name="text">
- <string>&amp;Current password:</string>
- </property>
- <property name="buddy">
- <cstring>leCurrentPassword</cstring>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="leCurrentPassword">
- <property name="echoMode">
- <enum>QLineEdit::Password</enum>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="lblNewPassword">
- <property name="text">
- <string>&amp;New password:</string>
- </property>
- <property name="buddy">
- <cstring>leNewPassword</cstring>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="leNewPassword">
- <property name="echoMode">
- <enum>QLineEdit::Password</enum>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="lblNewPassword2">
- <property name="text">
- <string>&amp;Re-enter new password:</string>
- </property>
- <property name="buddy">
- <cstring>leNewPassword2</cstring>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLineEdit" name="leNewPassword2">
- <property name="echoMode">
- <enum>QLineEdit::Password</enum>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QPushButton" name="pbChangePassword">
- <property name="text">
- <string>Change</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0" colspan="2">
- <widget class="QLabel" name="lblPasswordChangeStatus">
- <property name="text">
- <string>&lt;Password change status&gt;</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
</layout>
</widget>
<resources>
diff --git a/src/leap/bitmask/gui/ui/statuspanel.ui b/src/leap/bitmask/gui/ui/statuspanel.ui
deleted file mode 100644
index d77af1da..00000000
--- a/src/leap/bitmask/gui/ui/statuspanel.ui
+++ /dev/null
@@ -1,393 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>StatusPanel</class>
- <widget class="QWidget" name="StatusPanel">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>470</width>
- <height>477</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QLabel" name="lblProvider">
- <property name="styleSheet">
- <string notr="true">font: bold;</string>
- </property>
- <property name="text">
- <string>user@domain.org</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QWidget" name="status_rows" native="true">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="styleSheet">
- <string notr="true"/>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="5" column="1">
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="1" column="0" colspan="3">
- <widget class="QLabel" name="lblUnread">
- <property name="text">
- <string>0 Unread Emails</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="lblMailStatus">
- <property name="styleSheet">
- <string notr="true">font: bold;</string>
- </property>
- <property name="text">
- <string>Disabled</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_4">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Encrypted Mail:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <spacer name="horizontalSpacer_4">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="2" column="0" colspan="3">
- <spacer name="verticalSpacer_3">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>1</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="1" column="1">
- <layout class="QHBoxLayout" name="eip_bandwidth">
- <property name="spacing">
- <number>4</number>
- </property>
- <property name="sizeConstraint">
- <enum>QLayout::SetDefaultConstraint</enum>
- </property>
- <item>
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="../../../../../data/resources/icons.qrc">:/images/light/16/down-arrow.png</pixmap>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="btnDownload">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>100</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>120</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="cursor">
- <cursorShape>PointingHandCursor</cursorShape>
- </property>
- <property name="text">
- <string>0.0 KB/s</string>
- </property>
- <property name="flat">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="../../../../../data/resources/icons.qrc">:/images/light/16/up-arrow.png</pixmap>
- </property>
- </widget>
- </item>
- <item alignment="Qt::AlignLeft">
- <widget class="QPushButton" name="btnUpload">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>100</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>120</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="cursor">
- <cursorShape>PointingHandCursor</cursorShape>
- </property>
- <property name="text">
- <string>0.0 KB/s</string>
- </property>
- <property name="flat">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="2" column="0">
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Preferred</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>11</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="0" column="0" rowspan="2">
- <widget class="QLabel" name="lblVPNStatusIcon">
- <property name="maximumSize">
- <size>
- <width>64</width>
- <height>64</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="../../../../../data/resources/icons.qrc">:/images/light/64/network-eip-down.png</pixmap>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item row="4" column="0" rowspan="2">
- <widget class="QLabel" name="lblMailIcon">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>64</width>
- <height>64</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>64</width>
- <height>999</height>
- </size>
- </property>
- <property name="text">
- <string/>
- </property>
- <property name="pixmap">
- <pixmap resource="../../../../../data/resources/icons.qrc">:/images/mail-unlocked.png</pixmap>
- </property>
- </widget>
- </item>
- <item row="7" column="0" colspan="2">
- <widget class="QGroupBox" name="grpMailStatus">
- <property name="title">
- <string/>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QLabel" name="lblLongMailStatus">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="3" column="0" colspan="2">
- <widget class="QGroupBox" name="globalStatusBox">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="lblGlobalStatus">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>...</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item row="0" column="1">
- <layout class="QHBoxLayout" name="eip_controls">
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Encrypted Internet: </string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="lblEIPStatus">
- <property name="styleSheet">
- <string notr="true">font: bold;</string>
- </property>
- <property name="text">
- <string>Off</string>
- </property>
- <property name="textFormat">
- <enum>Qt::AutoText</enum>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="btnEipStartStop">
- <property name="text">
- <string>Turn On</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
- <resources>
- <include location="../../../../../data/resources/icons.qrc"/>
- </resources>
- <connections/>
-</ui>
diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui
index 2a412784..0f6eef6e 100644
--- a/src/leap/bitmask/gui/ui/wizard.ui
+++ b/src/leap/bitmask/gui/ui/wizard.ui
@@ -134,17 +134,7 @@
</property>
</spacer>
</item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="lnProvider"/>
- </item>
- <item row="1" column="2">
- <widget class="QPushButton" name="btnCheck">
- <property name="text">
- <string>Check</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
+ <item row="5" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -157,17 +147,7 @@
</property>
</spacer>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>https://</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="4" column="0" colspan="3">
+ <item row="6" column="0" colspan="3">
<widget class="QGroupBox" name="grpCheckProvider">
<property name="title">
<string>Checking for a valid provider</string>
@@ -276,13 +256,76 @@
</layout>
</widget>
</item>
- <item row="2" column="1" colspan="2">
+ <item row="4" column="1" colspan="2">
<widget class="QLabel" name="lblProviderSelectStatus">
<property name="text">
<string/>
</property>
</widget>
</item>
+ <item row="1" column="0" colspan="3">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Configure or select a provider</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_5">
+ <item row="0" column="0">
+ <widget class="QRadioButton" name="rbNewProvider">
+ <property name="text">
+ <string>Configure new provider:</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QRadioButton" name="rbExistingProvider">
+ <property name="text">
+ <string>Use existing one:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>https://</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="lnProvider"/>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="btnCheck">
+ <property name="text">
+ <string>Check</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>https://</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QComboBox" name="cbProviders">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
</layout>
</widget>
<widget class="QWizardPage" name="provider_info_page">
@@ -626,10 +669,18 @@
</widget>
</item>
<item row="3" column="1" colspan="2">
- <widget class="QLineEdit" name="lblPassword"/>
+ <widget class="QLineEdit" name="lblPassword">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
</item>
<item row="4" column="1" colspan="2">
- <widget class="QLineEdit" name="lblPassword2"/>
+ <widget class="QLineEdit" name="lblPassword2">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLineEdit" name="lblUser"/>
@@ -756,12 +807,91 @@
<tabstop>btnRegister</tabstop>
<tabstop>rdoRegister</tabstop>
<tabstop>rdoLogin</tabstop>
- <tabstop>lnProvider</tabstop>
- <tabstop>btnCheck</tabstop>
</tabstops>
<resources>
<include location="../../../../../data/resources/mainwindow.qrc"/>
<include location="../../../../../data/resources/locale.qrc"/>
</resources>
- <connections/>
+ <connections>
+ <connection>
+ <sender>rbExistingProvider</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>cbProviders</receiver>
+ <slot>setFocus()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>167</x>
+ <y>192</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>265</x>
+ <y>191</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>rbNewProvider</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lnProvider</receiver>
+ <slot>setFocus()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>171</x>
+ <y>164</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>246</x>
+ <y>164</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>rbExistingProvider</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lnProvider</receiver>
+ <slot>setDisabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>169</x>
+ <y>196</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>327</x>
+ <y>163</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>rbNewProvider</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>cbProviders</receiver>
+ <slot>setDisabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>169</x>
+ <y>162</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>269</x>
+ <y>193</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>rbExistingProvider</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>btnCheck</receiver>
+ <slot>setDisabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>154</x>
+ <y>193</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>498</x>
+ <y>170</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
</ui>
diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py
index 45734b81..e3f5904e 100644
--- a/src/leap/bitmask/gui/wizard.py
+++ b/src/leap/bitmask/gui/wizard.py
@@ -14,28 +14,27 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
"""
First run wizard
"""
import os
import logging
import json
+import random
from functools import partial
from PySide import QtCore, QtGui
from twisted.internet import threads
-from leap.bitmask.config import flags
+from leap.bitmask.config.leapsettings import LeapSettings
from leap.bitmask.config.providerconfig import ProviderConfig
from leap.bitmask.crypto.srpregister import SRPRegister
-from leap.bitmask.util.privilege_policies import is_missing_policy_permissions
+from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper
+from leap.bitmask.services import get_service_display_name, get_supported
from leap.bitmask.util.request_helpers import get_content
from leap.bitmask.util.keyring_helpers import has_keyring
from leap.bitmask.util.password import basic_password_checks
-from leap.bitmask.services.eip.providerbootstrapper import ProviderBootstrapper
-from leap.bitmask.services import get_service_display_name, get_supported
from ui_wizard import Ui_Wizard
@@ -84,6 +83,8 @@ class Wizard(QtGui.QWizard):
self._show_register = False
+ self._use_existing_provider = False
+
self.ui.grpCheckProvider.setVisible(False)
self.ui.btnCheck.clicked.connect(self._check_provider)
self.ui.lnProvider.returnPressed.connect(self._check_provider)
@@ -113,9 +114,6 @@ class Wizard(QtGui.QWizard):
self.currentIdChanged.connect(self._current_id_changed)
- self.ui.lblPassword.setEchoMode(QtGui.QLineEdit.Password)
- self.ui.lblPassword2.setEchoMode(QtGui.QLineEdit.Password)
-
self.ui.lnProvider.textChanged.connect(
self._enable_check)
@@ -128,6 +126,8 @@ class Wizard(QtGui.QWizard):
self.ui.btnRegister.clicked.connect(
self._register)
+ self.ui.rbExistingProvider.toggled.connect(self._skip_provider_checks)
+
usernameRe = QtCore.QRegExp(self.BARE_USERNAME_REGEX)
self.ui.lblUser.setValidator(
QtGui.QRegExpValidator(usernameRe, self))
@@ -147,6 +147,40 @@ class Wizard(QtGui.QWizard):
self.ui.label_12.setVisible(False)
self.ui.lblProviderPolicy.setVisible(False)
+ self._load_configured_providers()
+
+ def _load_configured_providers(self):
+ """
+ Loads the configured providers into the wizard providers combo box.
+ """
+ ls = LeapSettings()
+ providers = ls.get_configured_providers()
+ if not providers:
+ self.ui.rbExistingProvider.setEnabled(False)
+ self.ui.label_8.setEnabled(False) # 'https://' label
+ self.ui.cbProviders.setEnabled(False)
+ return
+
+ pinned = []
+ user_added = []
+
+ # separate pinned providers from user added ones
+ for p in providers:
+ if ls.is_pinned_provider(p):
+ pinned.append(p)
+ else:
+ user_added.append(p)
+
+ if user_added:
+ self.ui.cbProviders.addItems(user_added)
+
+ if user_added and pinned:
+ self.ui.cbProviders.addItem('---')
+
+ if pinned:
+ random.shuffle(pinned) # don't prioritize alphabetically
+ self.ui.cbProviders.addItems(pinned)
+
def get_domain(self):
return self._domain
@@ -318,6 +352,25 @@ class Wizard(QtGui.QWizard):
self._provider_select_defer = self._provider_bootstrapper.\
run_provider_select_checks(self._domain)
+ def _skip_provider_checks(self, skip):
+ """
+ SLOT
+ Triggered:
+ self.ui.rbExistingProvider.toggled
+
+ Allows the user to move to the next page without make any checks,
+ used when we are selecting an already configured provider.
+
+ :param skip: if we should skip checks or not
+ :type skip: bool
+ """
+ if skip:
+ self._reset_provider_check()
+
+ self.page(self.SELECT_PROVIDER_PAGE).set_completed(skip)
+ self.button(QtGui.QWizard.NextButton).setEnabled(skip)
+ self._use_existing_provider = skip
+
def _complete_task(self, data, label, complete=False, complete_page=-1):
"""
Checks a task and completes a page if specified
@@ -564,4 +617,14 @@ class Wizard(QtGui.QWizard):
else:
return self.SERVICES_PAGE
+ if self.currentPage() == self.page(self.SELECT_PROVIDER_PAGE):
+ if self._use_existing_provider:
+ self._domain = self.ui.cbProviders.currentText()
+ self._provider_config = ProviderConfig.get_provider_config(
+ self._domain)
+ if self._show_register:
+ return self.REGISTER_USER_PAGE
+ else:
+ return self.SERVICES_PAGE
+
return QtGui.QWizard.nextId(self)