diff options
author | Kali Kaneko <kali@leap.se> | 2015-08-31 14:54:52 -0400 |
---|---|---|
committer | Kali Kaneko <kali@leap.se> | 2015-08-31 14:54:52 -0400 |
commit | f4547479fc050f338845f4f546d8dd7c0e4512eb (patch) | |
tree | 0f737c7f102674230f5467ecaf17720e1d28f6eb /src/leap/bitmask/gui | |
parent | dd43dad4b150adb66e571a56a8a5c053dec858d0 (diff) | |
parent | fd27f48a35736d8ba186c423a7de15ffee5143dd (diff) |
Merge tag '0.9.0rc2' into debian/experimental
Tag leap.bitmask version 0.9.0rc2
Diffstat (limited to 'src/leap/bitmask/gui')
-rw-r--r-- | src/leap/bitmask/gui/advanced_key_management.py | 7 | ||||
-rw-r--r-- | src/leap/bitmask/gui/app.py | 6 | ||||
-rw-r--r-- | src/leap/bitmask/gui/eip_preferenceswindow.py | 5 | ||||
-rw-r--r-- | src/leap/bitmask/gui/eip_status.py | 5 | ||||
-rw-r--r-- | src/leap/bitmask/gui/login.py | 12 | ||||
-rw-r--r-- | src/leap/bitmask/gui/logwindow.py (renamed from src/leap/bitmask/gui/loggerwindow.py) | 68 | ||||
-rw-r--r-- | src/leap/bitmask/gui/mail_status.py | 223 | ||||
-rw-r--r-- | src/leap/bitmask/gui/mainwindow.py | 400 | ||||
-rw-r--r-- | src/leap/bitmask/gui/passwordwindow.py | 8 | ||||
-rw-r--r-- | src/leap/bitmask/gui/preferences_account_page.py | 13 | ||||
-rw-r--r-- | src/leap/bitmask/gui/preferences_email_page.py | 6 | ||||
-rw-r--r-- | src/leap/bitmask/gui/preferenceswindow.py | 14 | ||||
-rw-r--r-- | src/leap/bitmask/gui/signaltracker.py | 6 | ||||
-rw-r--r-- | src/leap/bitmask/gui/statemachines.py | 5 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/wizard.ui | 56 | ||||
-rw-r--r-- | src/leap/bitmask/gui/wizard.py | 76 |
16 files changed, 508 insertions, 402 deletions
diff --git a/src/leap/bitmask/gui/advanced_key_management.py b/src/leap/bitmask/gui/advanced_key_management.py index 7d147b7b..2e315d18 100644 --- a/src/leap/bitmask/gui/advanced_key_management.py +++ b/src/leap/bitmask/gui/advanced_key_management.py @@ -17,14 +17,13 @@ """ Advanced Key Management """ -import logging - -from PySide import QtCore, QtGui +from PySide import QtGui +from leap.bitmask.logs.utils import get_logger from leap.bitmask.services import get_service_display_name, MX_SERVICE from ui_advanced_key_management import Ui_AdvancedKeyManagement -logger = logging.getLogger(__name__) +logger = get_logger() class AdvancedKeyManagement(QtGui.QDialog): diff --git a/src/leap/bitmask/gui/app.py b/src/leap/bitmask/gui/app.py index 5fe031b1..02357b2b 100644 --- a/src/leap/bitmask/gui/app.py +++ b/src/leap/bitmask/gui/app.py @@ -18,16 +18,14 @@ A single App instances holds the signals that are shared among different frontend UI components. The App also keeps a reference to the backend object and the signaler get signals from the backend. """ -import logging - -from functools import partial from PySide import QtCore, QtGui from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.backend.backend_proxy import BackendProxy from leap.bitmask.backend.leapsignaler import LeapSignaler +from leap.bitmask.logs.utils import get_logger -logger = logging.getLogger(__name__) +logger = get_logger() class App(QtGui.QWidget): diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py index 8939c709..756e8adf 100644 --- a/src/leap/bitmask/gui/eip_preferenceswindow.py +++ b/src/leap/bitmask/gui/eip_preferenceswindow.py @@ -18,15 +18,14 @@ """ EIP Preferences window """ -import logging - from functools import partial from PySide import QtCore, QtGui from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.logs.utils import get_logger from leap.bitmask.gui.ui_eippreferences import Ui_EIPPreferences -logger = logging.getLogger(__name__) +logger = get_logger() class EIPPreferencesWindow(QtGui.QDialog): diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 83490cac..8334c2ee 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -17,13 +17,12 @@ """ EIP Status Panel widget implementation """ -import logging - from datetime import datetime from functools import partial from PySide import QtCore, QtGui +from leap.bitmask.logs.utils import get_logger from leap.bitmask.services import get_service_display_name, EIP_SERVICE from leap.bitmask.platform_init import IS_LINUX from leap.bitmask.util.averages import RateMovingAverage @@ -32,7 +31,7 @@ from leap.common.check import leap_assert_type from ui_eip_status import Ui_EIPStatus QtDelayedCall = QtCore.QTimer.singleShot -logger = logging.getLogger(__name__) +logger = get_logger() class EIPStatusWidget(QtGui.QWidget): diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py index 90df0b73..756dd63c 100644 --- a/src/leap/bitmask/gui/login.py +++ b/src/leap/bitmask/gui/login.py @@ -30,8 +30,7 @@ The login sequence is the following: - on success: _authentication_finished """ -import logging - +from keyring.errors import InitError as KeyringInitError from PySide import QtCore, QtGui from ui_login import Ui_LoginWidget @@ -40,6 +39,7 @@ from ui_login import Ui_LoginWidget from leap.bitmask.backend.leapbackend import ERROR_KEY, PASSED_KEY from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.logs.utils import get_logger from leap.bitmask.gui.signaltracker import SignalTracker from leap.bitmask.util import make_address from leap.bitmask.util.credentials import USERNAME_REGEX @@ -47,7 +47,7 @@ from leap.bitmask.util.keyring_helpers import has_keyring from leap.bitmask.util.keyring_helpers import get_keyring from leap.common.check import leap_assert_type -logger = logging.getLogger(__name__) +logger = get_logger() class LoginState(object): @@ -365,6 +365,9 @@ class LoginWidget(QtGui.QWidget, SignalTracker): # Only save the username if it was saved correctly in # the keyring self._settings.set_user(full_user_id) + except KeyringInitError as e: + logger.error("Failed to unlock keyring, maybe the user " + "cancelled the operation {0!r}".format(e)) except Exception as e: logger.exception("Problem saving data to keyring. %r" % (e,)) @@ -653,6 +656,9 @@ class LoginWidget(QtGui.QWidget, SignalTracker): saved_password = keyring.get_password(self.KEYRING_KEY, u_user) except ValueError as e: logger.debug("Incorrect Password. %r." % (e,)) + except KeyringInitError as e: + logger.error("Failed to unlock keyring, maybe the user " + "cancelled the operation {0!r}".format(e)) if saved_password is not None: self.set_password(saved_password) diff --git a/src/leap/bitmask/gui/loggerwindow.py b/src/leap/bitmask/gui/logwindow.py index 463d2412..718269c9 100644 --- a/src/leap/bitmask/gui/loggerwindow.py +++ b/src/leap/bitmask/gui/logwindow.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# loggerwindow.py +# logwindow.py # Copyright (C) 2013 LEAP # # This program is free software: you can redistribute it and/or modify @@ -19,18 +19,18 @@ History log window """ import cgi -import logging from PySide import QtCore, QtGui +import logbook + from ui_loggerwindow import Ui_LoggerWindow +from leap.bitmask.logs.utils import get_logger, LOG_CONTROLLER from leap.bitmask.util.constants import PASTEBIN_API_DEV_KEY -from leap.bitmask.logs.leap_log_handler import LeapLogHandler from leap.bitmask.util import pastebin -from leap.common.check import leap_assert, leap_assert_type -logger = logging.getLogger(__name__) +logger = get_logger() class LoggerWindow(QtGui.QDialog): @@ -40,16 +40,11 @@ class LoggerWindow(QtGui.QDialog): _paste_ok = QtCore.Signal(object) _paste_error = QtCore.Signal(object) - def __init__(self, parent, handler): + def __init__(self, parent): """ - Initialize the widget with the custom handler. - - :param handler: Custom handler that supports history and signal. - :type handler: LeapLogHandler. + Initialize the widget. """ QtGui.QDialog.__init__(self, parent) - leap_assert(handler, "We need a handler for the logger window") - leap_assert_type(handler, LeapLogHandler) # Load UI self.ui = Ui_LoggerWindow() @@ -72,36 +67,27 @@ class LoggerWindow(QtGui.QDialog): self._current_filter = "" self._current_history = "" - # Load logging history and connect logger with the widget - self._logging_handler = handler - self._connect_to_handler() - self._load_history() + self._set_logs_to_display() - def _connect_to_handler(self): - """ - This method connects the loggerwindow with the handler through a - signal communicate the logger events. - """ - self._logging_handler.new_log.connect(self._add_log_line) + LOG_CONTROLLER.new_log.connect(self._add_log_line) + self._load_history() def _add_log_line(self, log): """ Adds a line to the history, only if it's in the desired levels to show. :param log: a log record to be inserted in the widget - :type log: a dict with RECORD_KEY and MESSAGE_KEY. - the record contains the LogRecord of the logging module, - the message contains the formatted message for the log. + :type log: Logbook.LogRecord. """ html_style = { - logging.DEBUG: "background: #CDFFFF;", - logging.INFO: "background: white;", - logging.WARNING: "background: #FFFF66;", - logging.ERROR: "background: red; color: white;", - logging.CRITICAL: "background: red; color: white; font: bold;" + logbook.DEBUG: "background: #CDFFFF;", + logbook.INFO: "background: white;", + logbook.WARNING: "background: #FFFF66;", + logbook.ERROR: "background: red; color: white;", + logbook.CRITICAL: "background: red; color: white; font: bold;" } - level = log[LeapLogHandler.RECORD_KEY].levelno - message = cgi.escape(log[LeapLogHandler.MESSAGE_KEY]) + level = log.level + message = cgi.escape(log.msg) if self._logs_to_display[level]: open_tag = "<tr style='" + html_style[level] + "'>" @@ -125,12 +111,10 @@ class LoggerWindow(QtGui.QDialog): """ self._set_logs_to_display() self.ui.txtLogHistory.clear() - history = self._logging_handler.log_history current_history = [] - for line in history: - self._add_log_line(line) - message = line[LeapLogHandler.MESSAGE_KEY] - current_history.append(message) + for record in LOG_CONTROLLER.get_logs(): + self._add_log_line(record) + current_history.append(record.msg) self._current_history = "\n".join(current_history) @@ -139,11 +123,11 @@ class LoggerWindow(QtGui.QDialog): Sets the logs_to_display dict getting the toggled options from the ui """ self._logs_to_display = { - logging.DEBUG: self.ui.btnDebug.isChecked(), - logging.INFO: self.ui.btnInfo.isChecked(), - logging.WARNING: self.ui.btnWarning.isChecked(), - logging.ERROR: self.ui.btnError.isChecked(), - logging.CRITICAL: self.ui.btnCritical.isChecked() + logbook.DEBUG: self.ui.btnDebug.isChecked(), + logbook.INFO: self.ui.btnInfo.isChecked(), + logbook.WARNING: self.ui.btnWarning.isChecked(), + logbook.ERROR: self.ui.btnError.isChecked(), + logbook.CRITICAL: self.ui.btnCritical.isChecked() } def _filter_by(self, text): diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index bbfbafb5..1a38c8cf 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -17,28 +17,27 @@ """ Mail Status Panel widget implementation """ -import logging - from PySide import QtCore, QtGui +from leap.bitmask.logs.utils import get_logger from leap.bitmask.platform_init import IS_LINUX from leap.bitmask.services import get_service_display_name, MX_SERVICE 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 leap.common.events import catalog from ui_mail_status import Ui_MailStatusWidget -logger = logging.getLogger(__name__) +logger = get_logger() class MailStatusWidget(QtGui.QWidget): """ Status widget that displays the state of the LEAP Mail service """ - _soledad_event = QtCore.Signal(object) + _soledad_event = QtCore.Signal(object, object) _smtp_event = QtCore.Signal(object) - _imap_event = QtCore.Signal(object) + _imap_event = QtCore.Signal(object, object) _keymanager_event = QtCore.Signal(object) def __init__(self, parent=None): @@ -70,51 +69,36 @@ class MailStatusWidget(QtGui.QWidget): 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.IMAP_UNREAD_MAIL, - callback=self._mail_handle_imap_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.SMTP_SERVICE_STARTED, - callback=self._mail_handle_imap_events, - reqcbk=lambda req, resp: None) - - register(signal=proto.SOLEDAD_INVALID_AUTH_TOKEN, - callback=self.set_soledad_invalid_auth_token, - reqcbk=lambda req, resp: None) + register(event=catalog.KEYMANAGER_LOOKING_FOR_KEY, + callback=self._mail_handle_keymanager_events) + register(event=catalog.KEYMANAGER_KEY_FOUND, + callback=self._mail_handle_keymanager_events) + register(event=catalog.KEYMANAGER_KEY_NOT_FOUND, + callback=self._mail_handle_keymanager_events) + register(event=catalog.KEYMANAGER_STARTED_KEY_GENERATION, + callback=self._mail_handle_keymanager_events) + register(event=catalog.KEYMANAGER_FINISHED_KEY_GENERATION, + callback=self._mail_handle_keymanager_events) + register(event=catalog.KEYMANAGER_DONE_UPLOADING_KEYS, + callback=self._mail_handle_keymanager_events) + + register(event=catalog.SOLEDAD_DONE_DOWNLOADING_KEYS, + callback=self._mail_handle_soledad_events) + register(event=catalog.SOLEDAD_DONE_UPLOADING_KEYS, + callback=self._mail_handle_soledad_events) + register(event=catalog.SOLEDAD_SYNC_RECEIVE_STATUS, + callback=self._mail_handle_soledad_events) + register(event=catalog.SOLEDAD_SYNC_SEND_STATUS, + callback=self._mail_handle_soledad_events) + register(event=catalog.SOLEDAD_INVALID_AUTH_TOKEN, + callback=self.set_soledad_invalid_auth_token) + + register(event=catalog.MAIL_UNREAD_MESSAGES, + callback=self._mail_handle_imap_events) + register(event=catalog.IMAP_SERVICE_STARTED, + callback=self._mail_handle_imap_events) + register(event=catalog.SMTP_SERVICE_STARTED, + callback=self._mail_handle_imap_events) self._soledad_event.connect( self._mail_handle_soledad_events_slot) @@ -194,12 +178,14 @@ class MailStatusWidget(QtGui.QWidget): msg = self.tr("There was an unexpected problem with Soledad.") self._set_mail_status(msg, ready=-1) - def set_soledad_invalid_auth_token(self): + def set_soledad_invalid_auth_token(self, event, content): """ - TRIGGERS: - SoledadBootstrapper.soledad_invalid_token - This method is called when the auth token is invalid + + :param event: The event that triggered the callback. + :type event: str + :param content: The content of the event. + :type content: list """ msg = self.tr("Invalid auth token, try logging in again.") self._set_mail_status(msg, ready=-1) @@ -239,58 +225,85 @@ class MailStatusWidget(QtGui.QWidget): self._action_mail_status.setText(tray_status) self._update_systray_tooltip() - def _mail_handle_soledad_events(self, req): + def _mail_handle_soledad_events(self, event, content): """ Callback for handling events that are emitted from Soledad - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str + :param content: The content of the event. + :type content: dict """ - self._soledad_event.emit(req) + self._soledad_event.emit(event, content) - def _mail_handle_soledad_events_slot(self, req): + def _mail_handle_soledad_events_slot(self, event, content): """ TRIGGERS: _mail_handle_soledad_events Reacts to an Soledad event - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str + :param content: The content of the event. + :type content: dict """ self._set_mail_status(self.tr("Starting..."), ready=1) ext_status = "" + ready = None - if req.event == proto.SOLEDAD_DONE_UPLOADING_KEYS: + if event == catalog.SOLEDAD_DONE_UPLOADING_KEYS: ext_status = self.tr("Soledad has started...") - elif req.event == proto.SOLEDAD_DONE_DOWNLOADING_KEYS: + ready = 1 + elif event == catalog.SOLEDAD_DONE_DOWNLOADING_KEYS: ext_status = self.tr("Soledad is starting, please wait...") + ready = 1 + elif event == catalog.SOLEDAD_SYNC_RECEIVE_STATUS: + sync_progress = content['received'] * 100 / content['total'] + if sync_progress < 100: + ext_status = self.tr("Sync: downloading ({0:02}%)") + ext_status = ext_status.format(sync_progress) + else: + ext_status = self.tr("Sync: download completed.") + + ready = 2 + elif event == catalog.SOLEDAD_SYNC_SEND_STATUS: + sync_progress = content['sent'] * 100 / content['total'] + if sync_progress < 100: + ext_status = self.tr("Sync: uploading ({0:02}%)") + ext_status = ext_status.format(sync_progress) + else: + ext_status = self.tr("Sync: upload complete.") + + ready = 2 else: leap_assert(False, "Don't know how to handle this state: %s" - % (req.event)) + % (event)) - self._set_mail_status(ext_status, ready=1) + self._set_mail_status(ext_status, ready=ready) - def _mail_handle_keymanager_events(self, req): + def _mail_handle_keymanager_events(self, event, content): """ Callback for the KeyManager events - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str + :param content: The content of the event. + :type content: list """ - self._keymanager_event.emit(req) + self._keymanager_event.emit(event) - def _mail_handle_keymanager_events_slot(self, req): + def _mail_handle_keymanager_events_slot(self, event): """ TRIGGERS: _mail_handle_keymanager_events Reacts to an KeyManager event - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str """ # We want to ignore this kind of events once everything has # started @@ -299,88 +312,90 @@ class MailStatusWidget(QtGui.QWidget): ext_status = "" - if req.event == proto.KEYMANAGER_LOOKING_FOR_KEY: + if event == catalog.KEYMANAGER_LOOKING_FOR_KEY: ext_status = self.tr("Initial sync in progress, please wait...") - elif req.event == proto.KEYMANAGER_KEY_FOUND: + elif event == catalog.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: + elif event == catalog.KEYMANAGER_KEY_NOT_FOUND: + ext_status = self.tr( + "Key not found...") + elif event == catalog.KEYMANAGER_STARTED_KEY_GENERATION: ext_status = self.tr( "Generating new key, this may take a few minutes.") - elif req.event == proto.KEYMANAGER_FINISHED_KEY_GENERATION: + elif event == catalog.KEYMANAGER_FINISHED_KEY_GENERATION: ext_status = self.tr("Finished generating key!") - elif req.event == proto.KEYMANAGER_DONE_UPLOADING_KEYS: + elif event == catalog.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)) - + logger.warning("don't know to to handle %s" % (event,)) self._set_mail_status(ext_status, ready=1) - def _mail_handle_smtp_events(self, req): + def _mail_handle_smtp_events(self, event): """ Callback for the SMTP events - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str """ - self._smtp_event.emit(req) + self._smtp_event.emit(event) - def _mail_handle_smtp_events_slot(self, req): + def _mail_handle_smtp_events_slot(self, event): """ TRIGGERS: _mail_handle_smtp_events Reacts to an SMTP event - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str """ ext_status = "" - if req.event == proto.SMTP_SERVICE_STARTED: + if event == catalog.SMTP_SERVICE_STARTED: self._smtp_started = True - elif req.event == proto.SMTP_SERVICE_FAILED_TO_START: + elif event == catalog.SMTP_SERVICE_FAILED_TO_START: ext_status = self.tr("SMTP failed to start, check the logs.") else: leap_assert(False, "Don't know how to handle this state: %s" - % (req.event)) + % (event)) self._set_mail_status(ext_status, ready=2) # ----- XXX deprecate (move to mail conductor) - def _mail_handle_imap_events(self, req): + def _mail_handle_imap_events(self, event, content): """ Callback for the IMAP events - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str + :param content: The content of the event. + :type content: list """ - self._imap_event.emit(req) + self._imap_event.emit(event, content) - def _mail_handle_imap_events_slot(self, req): + def _mail_handle_imap_events_slot(self, event, content): """ TRIGGERS: _mail_handle_imap_events Reacts to an IMAP event - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str + :param content: The content of the event. + :type content: list """ ext_status = None - if req.event == proto.IMAP_UNREAD_MAIL: + if event == catalog.MAIL_UNREAD_MESSAGES: # By now, the semantics of the UNREAD_MAIL event are # limited to mails with the Unread flag *in the Inbox". # We could make this configurable to include all unread mail # or all unread mail in subscribed folders. if self._started: - count = req.content + count = content if count != "0": status = self.tr("{0} Unread Emails " "in your Inbox").format(count) @@ -390,7 +405,7 @@ class MailStatusWidget(QtGui.QWidget): self._set_mail_status(status, ready=2) else: self._set_mail_status("", ready=2) - elif req.event == proto.IMAP_SERVICE_STARTED: + elif event == catalog.IMAP_SERVICE_STARTED: self._imap_started = True if ext_status is not None: self._set_mail_status(ext_status, ready=1) diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index cbf7a636..312048ba 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -17,7 +17,6 @@ """ Main window for Bitmask. """ -import logging import time from datetime import datetime @@ -34,12 +33,11 @@ from leap.bitmask import __version_hash__ as VERSION_HASH from leap.bitmask.backend.leapbackend import ERROR_KEY, PASSED_KEY from leap.bitmask.config import flags +from leap.bitmask.logs.utils import get_logger, LOG_CONTROLLER from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement -from leap.bitmask.gui.eip_status import EIPStatusWidget -from leap.bitmask.gui.loggerwindow import LoggerWindow +from leap.bitmask.gui.logwindow import LoggerWindow from leap.bitmask.gui.login import LoginWidget -from leap.bitmask.gui.mail_status import MailStatusWidget from leap.bitmask.gui.preferenceswindow import PreferencesWindow from leap.bitmask.gui.signaltracker import SignalTracker from leap.bitmask.gui.systray import SysTray @@ -53,24 +51,34 @@ from leap.bitmask.platform_init import locks from leap.bitmask.platform_init.initializers import init_platform from leap.bitmask.platform_init.initializers import init_signals -from leap.bitmask.services.eip import conductor as eip_conductor -from leap.bitmask.services.mail import conductor as mail_conductor - -from leap.bitmask.services import EIP_SERVICE, MX_SERVICE - from leap.bitmask.util import autostart, make_address from leap.bitmask.util.keyring_helpers import has_keyring -from leap.bitmask.logs.leap_log_handler import LeapLogHandler from leap.common.events import register -from leap.common.events import events_pb2 as proto +from leap.common.events import catalog from leap.mail.imap.service.imap import IMAP_PORT from ui_mainwindow import Ui_MainWindow +from leap.bitmask._components import HAS_EIP, HAS_MAIL + +if HAS_EIP: + from leap.bitmask.gui.eip_status import EIPStatusWidget + from leap.bitmask.services.eip import conductor as eip_conductor + from leap.bitmask.services import EIP_SERVICE + +if HAS_MAIL: + from leap.bitmask.gui.mail_status import MailStatusWidget + from leap.bitmask.services.mail import conductor as mail_conductor + from leap.bitmask.services import MX_SERVICE + QtDelayedCall = QtCore.QTimer.singleShot -logger = logging.getLogger(__name__) + +logger = get_logger() + +if not HAS_EIP: + BITMASK_MAIL_ONLY_ICON = ":/images/menubar-mask-icon.png" class MainWindow(QtGui.QMainWindow, SignalTracker): @@ -78,17 +86,19 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): Main window for login and presenting status updates to the user """ # Signals - eip_needs_login = QtCore.Signal([]) + new_updates = QtCore.Signal(object) raise_window = QtCore.Signal([]) soledad_ready = QtCore.Signal([]) all_services_stopped = QtCore.Signal() - # We use this flag to detect abnormal terminations - user_stopped_eip = False + if HAS_EIP: + eip_needs_login = QtCore.Signal([]) + # We use this flag to detect abnormal terminations + user_stopped_eip = False - # We give EIP some time to come up before starting soledad anyway - EIP_START_TIMEOUT = 60000 # in milliseconds + # We give EIP some time to come up before starting soledad anyway + EIP_START_TIMEOUT = 60000 # in milliseconds # We give the services some time to a halt before forcing quit. SERVICES_STOP_TIMEOUT = 3000 # in milliseconds @@ -107,12 +117,10 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): autostart.set_autostart(True) # register leap events ######################################## - register(signal=proto.UPDATER_NEW_UPDATES, - callback=self._new_updates_available, - reqcbk=lambda req, resp: None) # make rpc call async - register(signal=proto.RAISE_WINDOW, - callback=self._on_raise_window_event, - reqcbk=lambda req, resp: None) # make rpc call async + register(event=catalog.UPDATER_NEW_UPDATES, + callback=self._new_updates_available) # make rpc call async + register(event=catalog.RAISE_WINDOW, + callback=self._on_raise_window_event) # make rpc call async # end register leap events #################################### self._updates_content = "" @@ -126,15 +134,17 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._backend = self.app.backend self._leap_signaler = self.app.signaler self._settings = self.app.settings + self._backend_settings = self._backend.settings # Login Widget self._login_widget = LoginWidget(self._backend, self._leap_signaler, self) self.ui.loginLayout.addWidget(self._login_widget) - # Mail Widget - self._mail_status = MailStatusWidget(self) - self.ui.mailLayout.addWidget(self._mail_status) + if HAS_MAIL: + # Mail Widget + self._mail_status = MailStatusWidget(self) + self.ui.mailLayout.addWidget(self._mail_status) # Provider List self._providers = Providers(self.ui.cmbProviders) @@ -151,41 +161,43 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._providers.connect_provider_changed(self._on_provider_changed) - # EIP Control redux ######################################### - self._eip_conductor = eip_conductor.EIPConductor( - self._settings, self._backend, self._leap_signaler) - self._eip_status = EIPStatusWidget(self, self._eip_conductor, - self._leap_signaler) - - init_signals.eip_missing_helpers.connect( - self._disable_eip_missing_helpers) - - self.ui.eipLayout.addWidget(self._eip_status) - - # XXX we should get rid of the circular refs - # conductor <-> status, right now keeping state on the widget ifself. - self._eip_conductor.add_eip_widget(self._eip_status) - - self._eip_conductor.connect_signals() - self._eip_conductor.qtsigs.connecting_signal.connect( - self._on_eip_connecting) - self._eip_conductor.qtsigs.connected_signal.connect( - self._on_eip_connection_connected) - self._eip_conductor.qtsigs.disconnected_signal.connect( - self._on_eip_connection_disconnected) - self._eip_conductor.qtsigs.connected_signal.connect( - self._maybe_run_soledad_setup_checks) + if HAS_EIP: + # EIP Control redux ######################################### + self._eip_conductor = eip_conductor.EIPConductor( + self._settings, self._backend, self._leap_signaler) + self._eip_status = EIPStatusWidget(self, self._eip_conductor, + self._leap_signaler) + + init_signals.eip_missing_helpers.connect( + self._disable_eip_missing_helpers) + + self.ui.eipLayout.addWidget(self._eip_status) + + # XXX we should get rid of the circular refs + # conductor <-> status, + # right now keeping state on the widget ifself. + self._eip_conductor.add_eip_widget(self._eip_status) + + self._eip_conductor.connect_signals() + self._eip_conductor.qtsigs.connecting_signal.connect( + self._on_eip_connecting) + self._eip_conductor.qtsigs.connected_signal.connect( + self._on_eip_connection_connected) + self._eip_conductor.qtsigs.disconnected_signal.connect( + self._on_eip_connection_disconnected) + self._eip_conductor.qtsigs.connected_signal.connect( + self._maybe_run_soledad_setup_checks) + + self.eip_needs_login.connect(self._eip_status.disable_eip_start) + self.eip_needs_login.connect(self._disable_eip_start_action) + + # XXX all this info about state should move to eip conductor too + self._already_started_eip = False + self._trying_to_start_eip = False self._login_widget.login_offline_finished.connect( self._maybe_run_soledad_setup_checks) - self.eip_needs_login.connect(self._eip_status.disable_eip_start) - self.eip_needs_login.connect(self._disable_eip_start_action) - - # XXX all this info about state should move to eip conductor too - self._already_started_eip = False - self._trying_to_start_eip = False - self._soledad_started = False # This is created once we have a valid provider config @@ -210,15 +222,14 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self.ui.action_wizard.triggered.connect(self._show_wizard) self.ui.action_show_logs.triggered.connect(self._show_logger_window) - # XXX hide the help menu since it only shows email information and - # right now we don't have stable mail and just confuses users. - self.ui.action_help.setVisible(False) - # self.ui.action_help.triggered.connect(self._help) + self.ui.action_help.setVisible(True) + self.ui.action_help.triggered.connect(self._help) self.ui.action_create_new_account.triggered.connect( self._on_provider_changed) # Action item hidden since we don't provide stable mail yet. + # TODO enable for 0.9.0 release?? # self.ui.action_advanced_key_management.triggered.connect( # self._show_AKM) @@ -230,11 +241,16 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._systray = None # XXX separate actions into a different module. - self._action_mail_status = QtGui.QAction(self.tr("Mail is OFF"), self) - self._mail_status.set_action_mail_status(self._action_mail_status) + if HAS_MAIL: + self._action_mail_status = QtGui.QAction( + self.tr("Mail is OFF"), self) + self._mail_status.set_action_mail_status( + self._action_mail_status) - self._action_eip_startstop = QtGui.QAction("", self) - self._eip_status.set_action_eip_startstop(self._action_eip_startstop) + if HAS_EIP: + self._action_eip_startstop = QtGui.QAction("", self) + self._eip_status.set_action_eip_startstop( + self._action_eip_startstop) self._action_visible = QtGui.QAction(self.tr("Show Main Window"), self) self._action_visible.triggered.connect(self._ensure_visible) @@ -272,19 +288,21 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._start_hidden = start_hidden self._backend_pid = backend_pid - self._mail_conductor = mail_conductor.MailConductor(self._backend) - self._mail_conductor.connect_mail_signals(self._mail_status) + if HAS_MAIL: + self._mail_conductor = mail_conductor.MailConductor(self._backend) + self._mail_conductor.connect_mail_signals(self._mail_status) if not init_platform(): self.quit() return # start event machines from within the eip and mail conductors - # TODO should encapsulate all actions into one object - self._eip_conductor.start_eip_machine( - action=self._action_eip_startstop) - self._mail_conductor.start_mail_machine() + if HAS_EIP: + self._eip_conductor.start_eip_machine( + action=self._action_eip_startstop) + if HAS_MAIL: + self._mail_conductor.start_mail_machine() if self._first_run(): self._wizard_firstrun = True @@ -363,17 +381,17 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): # here. sig.srp_not_logged_in_error.connect(self._not_logged_in_error) - # EIP start signals ============================================== - self._eip_conductor.connect_backend_signals() - sig.eip_can_start.connect(self._backend_can_start_eip) - sig.eip_cannot_start.connect(self._backend_cannot_start_eip) + if HAS_EIP: + # EIP start signals ============================================== + self._eip_conductor.connect_backend_signals() + sig.eip_can_start.connect(self._backend_can_start_eip) + sig.eip_cannot_start.connect(self._backend_cannot_start_eip) - sig.eip_dns_error.connect(self._eip_dns_error) + sig.eip_dns_error.connect(self._eip_dns_error) - sig.eip_get_gateway_country_code.connect(self._set_eip_provider) - sig.eip_no_gateway.connect(self._set_eip_provider) - - # ================================================================== + sig.eip_get_gateway_country_code.connect(self._set_eip_provider) + sig.eip_no_gateway.connect(self._set_eip_provider) + # ================================================================== # Soledad signals # TODO delegate connection to soledad bootstrapper @@ -491,25 +509,11 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._login_widget.set_password(possible_password) self._login() else: - self.eip_needs_login.emit() + if HAS_EIP: + self.eip_needs_login.emit() self._wizard = None - def _get_leap_logging_handler(self): - """ - Gets the leap handler from the top level logger - - :return: a logging handler or None - :rtype: LeapLogHandler or None - """ - # TODO this can be a function, does not need - # to be a method. - leap_logger = logging.getLogger('leap') - for h in leap_logger.handlers: - if isinstance(h, LeapLogHandler): - return h - return None - def _show_logger_window(self): """ TRIGGERS: @@ -518,13 +522,8 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): Display the window with the history of messages logged until now and displays the new ones on arrival. """ - leap_log_handler = self._get_leap_logging_handler() - if leap_log_handler is None: - logger.error('Leap logger handler not found') - return - else: - lw = LoggerWindow(self, handler=leap_log_handler) - lw.show() + lw = LoggerWindow(self) + lw.show() def _show_AKM(self): """ @@ -589,22 +588,26 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._backend_cannot_start_eip() return - if EIP_SERVICE not in self.app.settings.get_enabled_services(domain): - self._eip_conductor.terminate() + services_enabled = self.app.settings.get_enabled_services(domain) - def hide(): - self.app.backend.eip_can_start(domain=domain) + if HAS_EIP: + if EIP_SERVICE not in services_enabled: + self._eip_conductor.terminate() - QtDelayedCall(100, hide) - # ^^ VERY VERY Hacky, but with the simple state machine, - # there is no way to signal 'disconnect and then disable' + def hide(): + self.app.backend.eip_can_start(domain=domain) - else: - self._trying_to_start_eip = self.app.settings.get_autostart_eip() - if not self._trying_to_start_eip: - self._backend.eip_setup(provider=domain, skip_network=True) - # check if EIP can start (will trigger widget update) - self.app.backend.eip_can_start(domain=domain) + QtDelayedCall(100, hide) + # ^^ VERY VERY Hacky, but with the simple state machine, + # there is no way to signal 'disconnect and then disable' + + else: + settings = self.app.settings + self._trying_to_start_eip = settings.get_autostart_eip() + if not self._trying_to_start_eip: + self._backend.eip_setup(provider=domain, skip_network=True) + # check if EIP can start (will trigger widget update) + self.app.backend.eip_can_start(domain=domain) def _backend_can_start_eip(self): """ @@ -656,15 +659,16 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): if default_provider is not None: enabled_services = settings.get_enabled_services(default_provider) - if EIP_SERVICE in enabled_services: - # we don't have a usable provider - # so the user needs to log in first - self._eip_status.disable_eip_start() - else: - self._eip_status.disable_eip_start() - # NOTE: we shouldn't be setting the message here. - if not self._eip_status.missing_helpers: - self._eip_status.set_eip_status(self.tr("Disabled")) + if HAS_EIP: + if EIP_SERVICE in enabled_services: + # we don't have a usable provider + # so the user needs to log in first + self._eip_status.disable_eip_start() + else: + self._eip_status.disable_eip_start() + # NOTE: we shouldn't be setting the message here. + if not self._eip_status.missing_helpers: + self._eip_status.set_eip_status(self.tr("Disabled")) # this state flag is responsible for deferring the login # so we must update it, otherwise we're in a deadlock. @@ -683,29 +687,31 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): # updates # - def _new_updates_available(self, req): + def _new_updates_available(self, event, content): """ Callback for the new updates event - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param event: The event that triggered the callback. + :type event: str + :param content: The content of the event. + :type content: list """ - self.new_updates.emit(req) + self.new_updates.emit(content) - def _react_to_new_updates(self, req): + def _react_to_new_updates(self, content): """ TRIGGERS: self.new_updates Display the new updates label and sets the updates_content - :param req: Request type - :type req: leap.common.events.events_pb2.SignalRequest + :param content: The content of the event. + :type content: list """ self.moveToThread(QtCore.QCoreApplication.instance().thread()) self.ui.lblNewUpdates.setVisible(True) self.ui.btnMore.setVisible(True) - self._updates_content = req.content + self._updates_content = content def _updates_details(self): """ @@ -761,6 +767,8 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._show_hide_unsupported_services() + LOG_CONTROLLER.start_logbook_subscriber() + # XXX - HACK, kind of... # With the 1ms QTimer.singleShot call we schedule the call right after # other signals waiting for the qt reactor to take control. @@ -798,12 +806,13 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): only, the mail widget won't be displayed. """ providers = self._settings.get_configured_providers() - self._backend.provider_get_all_services(providers=providers) def _provider_get_all_services(self, services): - self._set_eip_visible(EIP_SERVICE in services) - self._set_mx_visible(MX_SERVICE in services) + if HAS_EIP: + self._set_eip_visible(EIP_SERVICE in services) + if HAS_MAIL: + self._set_mx_visible(MX_SERVICE in services) def _set_mx_visible(self, visible): """ @@ -856,23 +865,34 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): systrayMenu.addAction(self._action_visible) systrayMenu.addSeparator() - eip_status_label = u"{0}: {1}".format( - self._eip_conductor.eip_name, self.tr("OFF")) - self._eip_menu = eip_menu = systrayMenu.addMenu(eip_status_label) - eip_menu.addAction(self._action_eip_startstop) - self._eip_status.set_eip_status_menu(eip_menu) - systrayMenu.addSeparator() - systrayMenu.addAction(self._action_mail_status) - systrayMenu.addSeparator() + if HAS_EIP: + eip_status_label = u"{0}: {1}".format( + self._eip_conductor.eip_name, self.tr("OFF")) + self._eip_menu = eip_menu = systrayMenu.addMenu(eip_status_label) + eip_menu.addAction(self._action_eip_startstop) + self._eip_status.set_eip_status_menu(eip_menu) + systrayMenu.addSeparator() + if HAS_MAIL: + systrayMenu.addAction(self._action_mail_status) + systrayMenu.addSeparator() systrayMenu.addAction(self.ui.action_quit) + self._systray = SysTray(self) self._systray.setContextMenu(systrayMenu) - self._systray.setIcon(self._eip_status.ERROR_ICON_TRAY) + + if HAS_EIP: + self._systray.setIcon(self._eip_status.ERROR_ICON_TRAY) + else: + mail_status_icon = QtGui.QPixmap(BITMASK_MAIL_ONLY_ICON) + self._systray.setIcon(mail_status_icon) + self._systray.setVisible(True) self._systray.activated.connect(self._tray_activated) - self._mail_status.set_systray(self._systray) - self._eip_status.set_systray(self._systray) + if HAS_EIP: + self._eip_status.set_systray(self._systray) + if HAS_MAIL: + self._mail_status.set_systray(self._systray) if self._start_hidden: hello = lambda: self._systray.showMessage( @@ -1004,7 +1024,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): "manager or download it from <a href='{0}'>" "addons.mozilla.org</a>.".format(thunderbird_extension_url)) manual_text = self.tr( - "Alternately, you can manually configure " + "Alternatively, you can manually configure " "your mail client to use Bitmask Email with these options:") manual_imap = self.tr("IMAP: localhost, port {0}".format(IMAP_PORT)) manual_smtp = self.tr("SMTP: localhost, port {0}".format(smtp_port)) @@ -1055,7 +1075,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): if not e.spontaneous(): # if the system requested the `close` then we should quit. self._system_quit = True - self.quit() + self.quit(disable_autostart=False) return if QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ @@ -1112,8 +1132,11 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): # TODO: we should handle the case that EIP is autostarting since we # won't get a warning until EIP has fully started. # TODO: we need to add a check for the mail status (smtp/imap/soledad) - something_runing = (self._login_widget.get_logged_user() is not None or - self._already_started_eip) + + something_runing = self._login_widget.get_logged_user() is not None + if HAS_EIP: + something_runing = something_runing or self._already_started_eip + provider = self._providers.get_selected_provider() self._login_widget.set_provider(provider) @@ -1192,22 +1215,34 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._disconnect_login_wait() user = self._login_widget.get_logged_user() - domain = self._providers.get_selected_provider() - full_user_id = make_address(user, domain) - self._mail_conductor.userid = full_user_id - self._start_eip_bootstrap() - self.ui.action_create_new_account.setEnabled(True) + # XXX the widget now gives us the full user id. + # this is confusing. - # if soledad/mail is enabled: - if MX_SERVICE in self._enabled_services: - btn_enabled = self._login_widget.set_logout_btn_enabled - btn_enabled(False) - sig = self._leap_signaler - sig.soledad_bootstrap_failed.connect(lambda: btn_enabled(True)) - sig.soledad_bootstrap_finished.connect(lambda: btn_enabled(True)) + self.ui.action_create_new_account.setEnabled(True) - if MX_SERVICE not in self._provider_details['services']: - self._set_mx_visible(False) + if HAS_EIP: + self._start_eip_bootstrap() + if HAS_MAIL: + # XXX the casting to str (needed by smtp gateway) should be done + # in a better place. + self._mail_conductor.userid = str(user) + if MX_SERVICE in self._enabled_services: + btn_enabled = self._login_widget.set_logout_btn_enabled + btn_enabled(False) + sig = self._leap_signaler + sig.soledad_bootstrap_failed.connect( + lambda: btn_enabled(True)) + sig.soledad_bootstrap_finished.connect( + lambda: btn_enabled(True)) + + if MX_SERVICE not in self._provider_details['services']: + self._set_mx_visible(False) + + if not HAS_EIP: + # This has to be worked out in Bitmask 0.10. + # Since EIP won't start, we need to trigger + # the soledad setup service from here. + self._maybe_run_soledad_setup_checks() def _on_user_logged_out(self): """ @@ -1217,8 +1252,9 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): Switch the stackedWidget back to the login stage after logging out """ - self._mail_conductor.stop_mail_services() - self._mail_status.mail_state_disabled() + if HAS_MAIL: + self._mail_conductor.stop_mail_services() + self._mail_status.mail_state_disabled() self._show_hide_unsupported_services() def _start_eip_bootstrap(self): @@ -1312,10 +1348,10 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): if flags.OFFLINE: full_user_id = make_address(username, provider_domain) - uuid = self._settings.get_uuid(full_user_id) + uuid = self._backend_settings.get_uuid(full_user_id) self._mail_conductor.userid = full_user_id - if uuid is None: + if not uuid: # We don't need more visibility at the moment, # this is mostly for internal use/debug for now. logger.warning("Sorry! Log-in at least one time.") @@ -1479,9 +1515,9 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): missing_helpers = self._eip_status.missing_helpers already_started = self._already_started_eip - can_start = (should_start - and not already_started - and not missing_helpers) + can_start = (should_start and + not already_started and + not missing_helpers) if can_start: if self._eip_status.is_cold_start: @@ -1518,7 +1554,9 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): msg = self.tr("Disabled") self._eip_status.disable_eip_start() self._eip_status.set_eip_status(msg) + # eip will not start, so we start soledad anyway + # XXX This is the entry point for soledad startup. self._maybe_run_soledad_setup_checks() def _finish_eip_bootstrap(self, data): @@ -1566,9 +1604,14 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): # window handling methods # - def _on_raise_window_event(self, req): + def _on_raise_window_event(self, event, content): """ Callback for the raise window event + + :param event: The event that triggered the callback. + :type event: str + :param content: The content of the event. + :type content: list """ if IS_WIN: locks.raise_window_ack() @@ -1618,18 +1661,24 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): logger.debug('Terminating vpn') self._backend.eip_stop(shutdown=True) - def quit(self): + def quit(self, disable_autostart=True): """ Start the quit sequence and wait for services to finish. Cleanup and close the main window before quitting. + + :param disable_autostart: whether we should disable the autostart + feature or not + :type disable_autostart: bool """ if self._quitting: return + if disable_autostart: + autostart.set_autostart(False) + self._quitting = True self._close_to_tray = False logger.debug('Quitting...') - autostart.set_autostart(False) # first thing to do quitting, hide the mainwindow and show tooltip. self.hide() @@ -1712,6 +1761,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._leap_signaler.stop() + LOG_CONTROLLER.stop_logbook_subscriber() self._backend.stop() time.sleep(0.05) # give the thread a little time to finish. diff --git a/src/leap/bitmask/gui/passwordwindow.py b/src/leap/bitmask/gui/passwordwindow.py index 88565829..94cf25da 100644 --- a/src/leap/bitmask/gui/passwordwindow.py +++ b/src/leap/bitmask/gui/passwordwindow.py @@ -19,14 +19,14 @@ Change password dialog window """ -from PySide import QtCore, QtGui -from leap.bitmask.util.credentials import password_checks +from PySide import QtGui +from leap.bitmask.logs.utils import get_logger +from leap.bitmask.util.credentials import password_checks from leap.bitmask.gui.ui_password_change import Ui_PasswordChange from leap.bitmask.gui.flashable import Flashable -import logging -logger = logging.getLogger(__name__) +logger = get_logger() class PasswordWindow(QtGui.QDialog, Flashable): diff --git a/src/leap/bitmask/gui/preferences_account_page.py b/src/leap/bitmask/gui/preferences_account_page.py index cab90eec..da9da14d 100644 --- a/src/leap/bitmask/gui/preferences_account_page.py +++ b/src/leap/bitmask/gui/preferences_account_page.py @@ -16,16 +16,17 @@ """ Widget for "account" preferences """ -import logging - from functools import partial from PySide import QtCore, QtGui -from leap.bitmask.gui.ui_preferences_account_page import Ui_PreferencesAccountPage + +from leap.bitmask.logs.utils import get_logger +from leap.bitmask.gui import ui_preferences_account_page as ui_pref from leap.bitmask.gui.passwordwindow import PasswordWindow from leap.bitmask.services import get_service_display_name +from leap.bitmask._components import HAS_EIP -logger = logging.getLogger(__name__) +logger = get_logger() class PreferencesAccountPage(QtGui.QWidget): @@ -42,7 +43,7 @@ class PreferencesAccountPage(QtGui.QWidget): :type app: App """ QtGui.QWidget.__init__(self, parent) - self.ui = Ui_PreferencesAccountPage() + self.ui = ui_pref.Ui_PreferencesAccountPage() self.ui.setupUi(self) self.account = account @@ -120,6 +121,8 @@ class PreferencesAccountPage(QtGui.QWidget): # add one checkbox per service and set the current value # from what is saved in settings. for service in services: + if not HAS_EIP and service == "openvpn": + continue try: checkbox = QtGui.QCheckBox( get_service_display_name(service), self) diff --git a/src/leap/bitmask/gui/preferences_email_page.py b/src/leap/bitmask/gui/preferences_email_page.py index 80e8d93e..3087f343 100644 --- a/src/leap/bitmask/gui/preferences_email_page.py +++ b/src/leap/bitmask/gui/preferences_email_page.py @@ -16,12 +16,12 @@ """ Widget for "email" preferences """ -import logging +from PySide import QtGui -from PySide import QtCore, QtGui +from leap.bitmask.logs.utils import get_logger from leap.bitmask.gui.ui_preferences_email_page import Ui_PreferencesEmailPage -logger = logging.getLogger(__name__) +logger = get_logger() class PreferencesEmailPage(QtGui.QWidget): diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index daad08b0..baa71252 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -18,18 +18,18 @@ """ Preferences window """ -import logging - from PySide import QtCore, QtGui -from leap.bitmask.services import EIP_SERVICE, MX_SERVICE +from leap.bitmask.services import EIP_SERVICE +from leap.bitmask._components import HAS_EIP +from leap.bitmask.logs.utils import get_logger from leap.bitmask.gui.ui_preferences import Ui_Preferences from leap.bitmask.gui.preferences_account_page import PreferencesAccountPage from leap.bitmask.gui.preferences_vpn_page import PreferencesVpnPage from leap.bitmask.gui.preferences_email_page import PreferencesEmailPage -logger = logging.getLogger(__name__) +logger = get_logger() class PreferencesWindow(QtGui.QDialog): @@ -121,7 +121,8 @@ class PreferencesWindow(QtGui.QDialog): """ Adds the pages for the different configuration categories. """ - self._account_page = PreferencesAccountPage(self, self.account, self.app) + self._account_page = PreferencesAccountPage( + self, self.account, self.app) self._vpn_page = PreferencesVpnPage(self, self.account, self.app) self._email_page = PreferencesEmailPage(self, self.account, self.app) @@ -179,6 +180,7 @@ class PreferencesWindow(QtGui.QDialog): if account != self.account: return - self._vpn_item.setHidden(not EIP_SERVICE in services) + if HAS_EIP: + self._vpn_item.setHidden(EIP_SERVICE not in services) # self._email_item.setHidden(not MX_SERVICE in services) # ^^ disable email for now, there is nothing there yet. diff --git a/src/leap/bitmask/gui/signaltracker.py b/src/leap/bitmask/gui/signaltracker.py index 0e3b2dce..3dfcfe18 100644 --- a/src/leap/bitmask/gui/signaltracker.py +++ b/src/leap/bitmask/gui/signaltracker.py @@ -14,11 +14,11 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import logging - from PySide import QtCore -logger = logging.getLogger(__name__) +from leap.bitmask.logs.utils import get_logger + +logger = get_logger() class SignalTracker(QtCore.QObject): diff --git a/src/leap/bitmask/gui/statemachines.py b/src/leap/bitmask/gui/statemachines.py index 91f1f605..ab48b756 100644 --- a/src/leap/bitmask/gui/statemachines.py +++ b/src/leap/bitmask/gui/statemachines.py @@ -17,16 +17,15 @@ """ State machines for the Bitmask app. """ -import logging - from PySide import QtCore from PySide.QtCore import QStateMachine, QState, Signal from PySide.QtCore import QObject from leap.bitmask.services import connections from leap.common.check import leap_assert_type +from leap.bitmask.logs.utils import get_logger -logger = logging.getLogger(__name__) +logger = get_logger() _tr = QObject().tr diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui index 0e28ecbf..b125577e 100644 --- a/src/leap/bitmask/gui/ui/wizard.ui +++ b/src/leap/bitmask/gui/ui/wizard.ui @@ -43,7 +43,7 @@ <string>Welcome to Bitmask</string> </property> <property name="subTitle"> - <string> </string> + <string/> </property> <attribute name="pageId"> <string notr="true">0</string> @@ -59,7 +59,7 @@ <item row="0" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> - <string></string> + <string/> </property> <property name="textFormat"> <enum>Qt::RichText</enum> @@ -112,7 +112,7 @@ <string>Choose a provider</string> </property> <property name="subTitle"> - <string> </string> + <string/> </property> <attribute name="pageId"> <string notr="true">1</string> @@ -187,15 +187,15 @@ <height>22</height> </size> </property> - <property name="scaledContents"> - <bool>true</bool> - </property> <property name="text"> <string/> </property> <property name="pixmap"> <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> </widget> </item> <item row="2" column="1"> @@ -218,15 +218,15 @@ <height>22</height> </size> </property> - <property name="scaledContents"> - <bool>true</bool> - </property> <property name="text"> <string/> </property> <property name="pixmap"> <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> </widget> </item> <item row="1" column="1"> @@ -249,15 +249,15 @@ <height>22</height> </size> </property> - <property name="scaledContents"> - <bool>true</bool> - </property> <property name="text"> <string/> </property> <property name="pixmap"> <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> </widget> </item> <item row="1" column="0"> @@ -363,6 +363,12 @@ </item> <item> <widget class="QPushButton" name="btnCheck"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> <property name="text"> <string>Check</string> </property> @@ -380,7 +386,7 @@ <string>About this provider</string> </property> <property name="subTitle"> - <string> </string> + <string/> </property> <attribute name="pageId"> <string notr="true">2</string> @@ -522,7 +528,7 @@ <string>Provider setup</string> </property> <property name="subTitle"> - <string> </string> + <string/> </property> <attribute name="pageId"> <string notr="true">3</string> @@ -590,15 +596,15 @@ <height>22</height> </size> </property> - <property name="scaledContents"> - <bool>true</bool> - </property> <property name="text"> <string/> </property> <property name="pixmap"> <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> </widget> </item> <item row="1" column="1"> @@ -621,15 +627,15 @@ <height>22</height> </size> </property> - <property name="scaledContents"> - <bool>true</bool> - </property> <property name="text"> <string/> </property> <property name="pixmap"> <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> </widget> </item> <item row="1" column="0"> @@ -673,15 +679,15 @@ <height>22</height> </size> </property> - <property name="scaledContents"> - <bool>true</bool> - </property> <property name="text"> <string/> </property> <property name="pixmap"> <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> </widget> </item> <item row="0" column="0"> @@ -720,7 +726,7 @@ <string>Register new user</string> </property> <property name="subTitle"> - <string> </string> + <string/> </property> <attribute name="pageId"> <string notr="true">4</string> @@ -845,7 +851,7 @@ <string>Service selection</string> </property> <property name="subTitle"> - <string> </string> + <string/> </property> <attribute name="pageId"> <string notr="true">5</string> diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 5da021d1..abaf2108 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -17,7 +17,6 @@ """ First run wizard """ -import logging import random from functools import partial @@ -30,16 +29,18 @@ from leap.bitmask.backend.leapbackend import ERROR_KEY, PASSED_KEY from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.logs.utils import get_logger from leap.bitmask.gui.signaltracker import SignalTracker from leap.bitmask.services import get_service_display_name, get_supported from leap.bitmask.util.credentials import password_checks, username_checks from leap.bitmask.util.credentials import USERNAME_REGEX from leap.bitmask.util.keyring_helpers import has_keyring +from leap.bitmask._components import HAS_EIP from ui_wizard import Ui_Wizard QtDelayedCall = QtCore.QTimer.singleShot -logger = logging.getLogger(__name__) +logger = get_logger() class Wizard(QtGui.QWizard, SignalTracker): @@ -264,6 +265,20 @@ class Wizard(QtGui.QWizard, SignalTracker): if reset: self._reset_provider_check() + def _provider_widget_set_enabled(self, enabled): + """ + Enable/Disable the provider widget. + The widget to use depends on whether the used decided to use an + existing provider or a new one. + + :param enabled: the new state for the widget + :type enabled: bool + """ + if self.ui.rbNewProvider.isChecked(): + self.ui.lnProvider.setEnabled(enabled) + else: + self.ui.cbProviders.setEnabled(enabled) + def _focus_username(self): """ Focus at the username lineedit for the registration page @@ -371,6 +386,19 @@ class Wizard(QtGui.QWizard, SignalTracker): self._set_register_status(error_msg, error=True) self.ui.btnRegister.setEnabled(True) + def _registration_disabled(self): + """ + TRIGGERS: + self._backend.signaler.srp_registration_disabled + + The registration is disabled in the current provider. + """ + self._username = self._password = None + + error_msg = self.tr("The registration is disabled for this provider.") + self._set_register_status(error_msg, error=True) + self.ui.btnRegister.setEnabled(True) + def _registration_taken(self): """ TRIGGERS: @@ -439,11 +467,7 @@ class Wizard(QtGui.QWizard, SignalTracker): self.ui.grpCheckProvider.setVisible(True) self.ui.btnCheck.setEnabled(False) - # Disable provider widget - if self.ui.rbNewProvider.isChecked(): - self.ui.lnProvider.setEnabled(False) - else: - self.ui.cbProviders.setEnabled(False) + self._provider_widget_set_enabled(False) self.button(QtGui.QWizard.BackButton).clearFocus() @@ -510,7 +534,7 @@ class Wizard(QtGui.QWizard, SignalTracker): self.ui.lblHTTPS.setPixmap(self.QUESTION_ICON) self.ui.lblProviderSelectStatus.setText(status) self.ui.btnCheck.setEnabled(not passed) - self.ui.lnProvider.setEnabled(not passed) + self._provider_widget_set_enabled(not passed) def _https_connection(self, data): """ @@ -529,7 +553,8 @@ class Wizard(QtGui.QWizard, SignalTracker): else: self.ui.lblProviderInfo.setPixmap(self.QUESTION_ICON) self.ui.btnCheck.setEnabled(not passed) - self.ui.lnProvider.setEnabled(not passed) + + self._provider_widget_set_enabled(not passed) def _download_provider_info(self, data): """ @@ -558,13 +583,9 @@ class Wizard(QtGui.QWizard, SignalTracker): status = self.tr("<font color='red'><b>Not a valid provider" "</b></font>") self.ui.lblProviderSelectStatus.setText(status) - self.ui.btnCheck.setEnabled(True) - # Enable provider widget - if self.ui.rbNewProvider.isChecked(): - self.ui.lnProvider.setEnabled(True) - else: - self.ui.cbProviders.setEnabled(True) + self.ui.btnCheck.setEnabled(True) + self._provider_widget_set_enabled(True) def _provider_get_details(self, details): """ @@ -574,6 +595,22 @@ class Wizard(QtGui.QWizard, SignalTracker): :type details: dict """ self._provider_details = details + self._check_registration_allowed() + + def _check_registration_allowed(self): + """ + Check whether the provider allows new users registration or not. + If it is not allowed we display a message and prevent the user moving + forward on the wizard. + """ + if self._show_register: # user wants to register a new account + if not self._provider_details['allow_registration']: + logger.debug("Registration not allowed") + status = ("<font color='red'><b>" + + self.tr("The provider has disabled registration") + + "</b></font>") + self.ui.lblProviderSelectStatus.setText(status) + self.button(QtGui.QWizard.NextButton).setEnabled(False) def _download_ca_cert(self, data): """ @@ -654,6 +691,12 @@ class Wizard(QtGui.QWizard, SignalTracker): checkbox.stateChanged.connect( partial(self._service_selection_changed, service)) checkbox.setChecked(True) + + if service == "openvpn" and not HAS_EIP: + # this is a mail-only build, we disable eip. + checkbox.setEnabled(False) + checkbox.setChecked(False) + self._shown_services.add(service) except ValueError: logger.error( @@ -675,9 +718,11 @@ class Wizard(QtGui.QWizard, SignalTracker): skip = self.ui.rbExistingProvider.isChecked() if not self._provider_checks_ok: self._enable_check() + self.ui.btnCheck.setFocus() self._skip_provider_checks(skip) else: self._enable_check(reset=False) + self._check_registration_allowed() if pageId == self.SETUP_PROVIDER_PAGE: if not self._provider_setup_ok: @@ -757,5 +802,6 @@ class Wizard(QtGui.QWizard, SignalTracker): conntrack(sig.prov_check_api_certificate, self._check_api_certificate) conntrack(sig.srp_registration_finished, self._registration_finished) + conntrack(sig.srp_registration_disabled, self._registration_disabled) conntrack(sig.srp_registration_failed, self._registration_failed) conntrack(sig.srp_registration_taken, self._registration_taken) |