From 68b1be8ef443b088cf5c1f7f964e1bd7ad42408e Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 21 Jul 2014 17:03:47 -0300 Subject: Add heartbeat to check if backend is alive. Send a 'ping' request every 2 secs to ensure that the backend is running. Use polling instead of recv on the backend_proxy. This was already implemented for the signaler. --- src/leap/bitmask/backend/api.py | 2 + src/leap/bitmask/backend/backend.py | 6 ++- src/leap/bitmask/backend/backend_proxy.py | 64 ++++++++++++++++++++++++++----- src/leap/bitmask/gui/mainwindow.py | 22 +++++++++++ 4 files changed, 83 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py index b8533f36..4f52e470 100644 --- a/src/leap/bitmask/backend/api.py +++ b/src/leap/bitmask/backend/api.py @@ -18,10 +18,12 @@ Backend available API and SIGNALS definition. """ STOP_REQUEST = "stop" +PING_REQUEST = "PING" API = ( STOP_REQUEST, # this method needs to be defined in order to support the # backend stop action + PING_REQUEST, "eip_can_start", "eip_cancel_setup", diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py index 833f4368..c895f8f5 100644 --- a/src/leap/bitmask/backend/backend.py +++ b/src/leap/bitmask/backend/backend.py @@ -23,7 +23,7 @@ from twisted.internet import defer, reactor, threads import zmq from zmq.auth.thread import ThreadAuthenticator -from leap.bitmask.backend.api import API +from leap.bitmask.backend.api import API, PING_REQUEST from leap.bitmask.backend.utils import get_backend_certificates from leap.bitmask.backend.signaler import Signaler @@ -146,6 +146,10 @@ class Backend(object): :param request_json: a json specification of a request. :type request_json: str """ + if request_json == PING_REQUEST: + # do not process request if it's just a ping + return + try: # request = zmq.utils.jsonapi.loads(request_json) # We use stdlib's json to ensure that we get unicode strings diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py index f683e465..dc30d2cb 100644 --- a/src/leap/bitmask/backend/backend_proxy.py +++ b/src/leap/bitmask/backend/backend_proxy.py @@ -25,7 +25,7 @@ import time import zmq -from leap.bitmask.backend.api import API, STOP_REQUEST +from leap.bitmask.backend.api import API, STOP_REQUEST, PING_REQUEST from leap.bitmask.backend.utils import get_backend_certificates import logging @@ -40,6 +40,11 @@ class BackendProxy(object): PORT = '5556' SERVER = "tcp://localhost:%s" % PORT + POLL_TIMEOUT = 4000 # ms + POLL_TRIES = 3 + + PING_INTERVAL = 2 # secs + def __init__(self): self._socket = None @@ -62,6 +67,9 @@ class BackendProxy(object): socket.connect(self.SERVER) self._socket = socket + self._ping_at = 0 + self.online = False + self._call_queue = Queue.Queue() self._worker_caller = threading.Thread(target=self._worker) self._worker_caller.start() @@ -82,9 +90,26 @@ class BackendProxy(object): except Queue.Empty: pass time.sleep(0.01) + self._ping() logger.debug("BackendProxy worker stopped.") + def _reset_ping(self): + """ + Reset the ping timeout counter. + This is called for every ping and request. + """ + self._ping_at = time.time() + self.PING_INTERVAL + + def _ping(self): + """ + Heartbeat helper. + Sends a PING request just to know that the server is alive. + """ + if time.time() > self._ping_at: + self._send_request(PING_REQUEST) + self._reset_ping() + def _api_call(self, *args, **kwargs): """ Call the `api_method` method in backend (through zmq). @@ -134,16 +159,35 @@ class BackendProxy(object): # logger.debug("Sending request to backend: {0}".format(request)) self._socket.send(request) - try: - # Get the reply. - self._socket.recv() - # response = self._socket.recv() - # msg = "Received reply for '{0}' -> '{1}'" - # msg = msg.format(request, response) - # logger.debug(msg) - except zmq.error.Again as e: - msg = "Timeout error contacting backend. {0!r}".format(e) + poll = zmq.Poller() + poll.register(self._socket, zmq.POLLIN) + + reply = None + tries = 0 + + while True: + socks = dict(poll.poll(self.POLL_TIMEOUT)) + if socks.get(self._socket) == zmq.POLLIN: + reply = self._socket.recv() + break + + tries += 1 + if tries < self.POLL_TRIES: + logger.warning('Retrying receive... {0}/{1}'.format( + tries, self.POLL_TRIES)) + else: + break + + if reply is None: + msg = "Timeout error contacting backend." logger.critical(msg) + self.online = False + else: + # msg = "Received reply for '{0}' -> '{1}'".format(request, reply) + # logger.debug(msg) + self.online = True + # request received, no ping needed for other interval. + self._reset_ping() def __getattribute__(self, name): """ diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 6959650b..a15c4dd8 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -125,6 +125,11 @@ class MainWindow(QtGui.QMainWindow): self._backend = BackendProxy() + # periodically check if the backend is alive + self._backend_checker = QtCore.QTimer(self) + self._backend_checker.timeout.connect(self._check_backend_status) + self._backend_checker.start(2000) + self._leap_signaler = LeapSignaler() self._leap_signaler.start() @@ -334,6 +339,23 @@ class MainWindow(QtGui.QMainWindow): logger.error("Bad call to the backend:") logger.error(data) + @QtCore.Slot() + def _check_backend_status(self): + """ + TRIGGERS: + self._backend_checker.timeout + + Check that the backend is running. Otherwise show an error to the user. + """ + online = self._backend.online + if not online: + logger.critical("Backend is not online.") + QtGui.QMessageBox.critical( + self, self.tr("Application error"), + self.tr("There is a problem contacting the backend, please " + "restart Bitmask.")) + self._backend_checker.stop() + def _backend_connect(self, only_tracked=False): """ Connect to backend signals. -- cgit v1.2.3 From aeacb80a34dc7b8996278e35e9cc888d93e2f853 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 22 Jul 2014 16:10:10 -0300 Subject: Kill backend on quit if it does not respond. --- src/leap/bitmask/app.py | 2 +- src/leap/bitmask/frontend_app.py | 4 ++-- src/leap/bitmask/gui/mainwindow.py | 21 +++++++++++++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 88f6bc15..ab49ee37 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -185,7 +185,7 @@ def start_app(): backend_process.daemon = True backend_process.start() - run_frontend(options, flags_dict) + run_frontend(options, flags_dict, backend_pid=backend_process.pid) if __name__ == "__main__": diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py index 51607d0b..5ea89fc9 100644 --- a/src/leap/bitmask/frontend_app.py +++ b/src/leap/bitmask/frontend_app.py @@ -54,7 +54,7 @@ def signal_handler(window, pid, signum, frame): window.quit() -def run_frontend(options, flags_dict): +def run_frontend(options, flags_dict, backend_pid): """ Run the GUI for the application. @@ -102,7 +102,7 @@ def run_frontend(options, flags_dict): timer.start(500) # You may change this if you wish. timer.timeout.connect(lambda: None) # Let the interpreter run each 500 ms. - window = MainWindow(start_hidden=start_hidden) + window = MainWindow(start_hidden=start_hidden, backend_pid=backend_pid) my_pid = os.getpid() sig_handler = partial(signal_handler, window, my_pid) diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index a15c4dd8..59a65b1e 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -22,6 +22,8 @@ import time from datetime import datetime +import psutil + from PySide import QtCore, QtGui from leap.bitmask import __version__ as VERSION @@ -97,7 +99,7 @@ class MainWindow(QtGui.QMainWindow): # We give the services some time to a halt before forcing quit. SERVICES_STOP_TIMEOUT = 20000 # in milliseconds - def __init__(self, start_hidden=False): + def __init__(self, start_hidden=False, backend_pid=None): """ Constructor for the client main window @@ -272,6 +274,7 @@ class MainWindow(QtGui.QMainWindow): self._logger_window = None 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) @@ -1819,6 +1822,15 @@ class MainWindow(QtGui.QMainWindow): # or if we reach the timeout QtDelayedCall(self.SERVICES_STOP_TIMEOUT, self.final_quit) + def _backend_kill(self): + """ + Send a kill signal to the backend process. + This is called if the backend does not respond to requests. + """ + if self._backend_pid is not None: + logger.debug("Killing backend") + psutil.Process(self._backend_pid).kill() + @QtCore.Slot() def _remove_service(self, service): """ @@ -1854,7 +1866,12 @@ class MainWindow(QtGui.QMainWindow): logger.debug('Final quit...') self._leap_signaler.stop() - self._backend.stop() + + if self._backend.online: + self._backend.stop() + else: + self._backend_kill() + time.sleep(0.05) # give the thread a little time to finish. # Remove lockfiles on a clean shutdown. -- cgit v1.2.3 From 227a31d8892c67c64beebe5135cc850dfa71c3c6 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 23 Jul 2014 12:03:44 -0300 Subject: Restrict access to the zmq certificates folder. --- src/leap/bitmask/backend/utils.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py index 54a16fd7..65bf6753 100644 --- a/src/leap/bitmask/backend/utils.py +++ b/src/leap/bitmask/backend/utils.py @@ -19,6 +19,7 @@ Backend utilities to handle ZMQ certificates. """ import os import shutil +import stat import zmq.auth @@ -36,6 +37,8 @@ def generate_certificates(): if os.path.exists(KEYS_DIR): shutil.rmtree(KEYS_DIR) mkdir_p(KEYS_DIR) + # set permissions to: 0700 (U:rwx G:--- O:---) + os.chmod(KEYS_DIR, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) # create new keys in certificates dir # public_file, secret_file = create_certificates(...) -- cgit v1.2.3 From aec9c8ff50ed61cd484e3aefe638da6705b53ff8 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 23 Jul 2014 14:51:29 -0300 Subject: Set the standalone value for BaseConfig. --- src/leap/bitmask/config/providerconfig.py | 2 ++ src/leap/bitmask/services/eip/eipconfig.py | 2 ++ 2 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/leap/bitmask/config/providerconfig.py b/src/leap/bitmask/config/providerconfig.py index 7b979e61..57bc3a98 100644 --- a/src/leap/bitmask/config/providerconfig.py +++ b/src/leap/bitmask/config/providerconfig.py @@ -22,6 +22,7 @@ import logging import os from leap.bitmask import provider +from leap.bitmask.config import flags from leap.bitmask.config.provider_spec import leap_provider_spec from leap.bitmask.services import get_service_display_name from leap.bitmask.util import get_path_prefix @@ -43,6 +44,7 @@ class ProviderConfig(BaseConfig): Provider configuration abstraction class """ def __init__(self): + self.standalone = flags.STANDALONE BaseConfig.__init__(self) def get_light_config(self, domain, lang=None): diff --git a/src/leap/bitmask/services/eip/eipconfig.py b/src/leap/bitmask/services/eip/eipconfig.py index e7419b22..37c0c8ae 100644 --- a/src/leap/bitmask/services/eip/eipconfig.py +++ b/src/leap/bitmask/services/eip/eipconfig.py @@ -24,6 +24,7 @@ import time import ipaddr +from leap.bitmask.config import flags from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.services import ServiceConfig from leap.bitmask.services.eip.eipspec import get_schema @@ -220,6 +221,7 @@ class EIPConfig(ServiceConfig): OPENVPN_CIPHERS_REGEX = re.compile("[A-Z0-9\-]+") def __init__(self): + self.standalone = flags.STANDALONE ServiceConfig.__init__(self) self._api_version = None -- cgit v1.2.3 From d97a9804c1a6fb06d7ce39066f92a0259a6ab8c3 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 24 Jul 2014 12:54:06 -0300 Subject: Don't call the backend if it's not online. --- src/leap/bitmask/gui/mainwindow.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 59a65b1e..ff19e17f 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1813,10 +1813,14 @@ class MainWindow(QtGui.QMainWindow): # Set this in case that the app is hidden QtGui.QApplication.setQuitOnLastWindowClosed(True) - self._stop_services() - self._really_quit = True + if not self._backend.online: + self.final_quit() + return + + self._stop_services() + # call final quit when all the services are stopped self.all_services_stopped.connect(self.final_quit) # or if we reach the timeout @@ -1859,11 +1863,12 @@ class MainWindow(QtGui.QMainWindow): if self._finally_quitting: return + logger.debug('Final quit...') self._finally_quitting = True - logger.debug('Closing soledad...') - self._backend.soledad_close() - logger.debug('Final quit...') + if self._backend.online: + logger.debug('Closing soledad...') + self._backend.soledad_close() self._leap_signaler.stop() -- cgit v1.2.3 From ce88b52295881a3dd1bc0efec8e72b1d3a235e87 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 22 Jul 2014 11:33:09 -0300 Subject: Add frontend alive check to the backend. Stop the backend if the frontend process does not exist any more and backend is not a daemon. --- src/leap/bitmask/app.py | 3 ++- src/leap/bitmask/backend/backend.py | 24 +++++++++++++++++++++++- src/leap/bitmask/backend/leapbackend.py | 4 ++-- src/leap/bitmask/backend_app.py | 5 +++-- 4 files changed, 30 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index ab49ee37..37ded92a 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -180,7 +180,8 @@ def start_app(): flags_dict = flags_to_dict() - backend = lambda: run_backend(opts.danger, flags_dict) + frontend_pid = os.getpid() + backend = lambda: run_backend(opts.danger, flags_dict, frontend_pid) backend_process = multiprocessing.Process(target=backend, name='Backend') backend_process.daemon = True backend_process.start() diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py index c895f8f5..67ffe35a 100644 --- a/src/leap/bitmask/backend/backend.py +++ b/src/leap/bitmask/backend/backend.py @@ -18,6 +18,8 @@ import json import threading import time +import psutil + from twisted.internet import defer, reactor, threads import zmq @@ -39,12 +41,16 @@ class Backend(object): PORT = '5556' BIND_ADDR = "tcp://127.0.0.1:%s" % PORT - def __init__(self): + PING_INTERVAL = 2 # secs + + def __init__(self, frontend_pid=None): """ Backend constructor, create needed instances. """ self._signaler = Signaler() + self._frontend_pid = frontend_pid + self._do_work = threading.Event() # used to stop the worker thread. self._zmq_socket = None @@ -81,6 +87,8 @@ class Backend(object): Note: we use a simple while since is less resource consuming than a Twisted's LoopingCall. """ + pid = self._frontend_pid + check_wait = 0 while self._do_work.is_set(): # Wait for next request from client try: @@ -93,6 +101,20 @@ class Backend(object): raise time.sleep(0.01) + check_wait += 0.01 + if pid is not None and check_wait > self.PING_INTERVAL: + check_wait = 0 + self._check_frontend_alive() + + def _check_frontend_alive(self): + """ + Check if the frontend is alive and stop the backend if it is not. + """ + pid = self._frontend_pid + if pid is not None and not psutil.pid_exists(pid): + logger.critical("The frontend is down!") + self.stop() + def _stop_reactor(self): """ Stop the Twisted reactor, but first wait a little for some threads to diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py index d3c4fcda..6b0328ca 100644 --- a/src/leap/bitmask/backend/leapbackend.py +++ b/src/leap/bitmask/backend/leapbackend.py @@ -36,11 +36,11 @@ class LeapBackend(Backend): """ Backend server subclass, used to implement the API methods. """ - def __init__(self, bypass_checks=False): + def __init__(self, bypass_checks=False, frontend_pid=None): """ Constructor for the backend. """ - Backend.__init__(self) + Backend.__init__(self, frontend_pid) self._settings = Settings() diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py index 5c0e4803..716ae4a7 100644 --- a/src/leap/bitmask/backend_app.py +++ b/src/leap/bitmask/backend_app.py @@ -44,7 +44,7 @@ def signal_handler(signum, frame): logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum)) -def run_backend(bypass_checks, flags_dict): +def run_backend(bypass_checks, flags_dict, frontend_pid=None): """ Run the backend for the application. @@ -59,5 +59,6 @@ def run_backend(bypass_checks, flags_dict): dict_to_flags(flags_dict) - backend = LeapBackend(bypass_checks=bypass_checks) + backend = LeapBackend(bypass_checks=bypass_checks, + frontend_pid=frontend_pid) backend.run() -- cgit v1.2.3 From beac7a8ce70acb17c320580538510761dff3ac93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Thu, 24 Jul 2014 16:33:25 -0300 Subject: Improve hide and show main window on Ubuntu --- src/leap/bitmask/gui/mainwindow.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index ff19e17f..383f97bb 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -999,6 +999,12 @@ class MainWindow(QtGui.QMainWindow): if not visible: QtGui.QApplication.setQuitOnLastWindowClosed(True) self.show() + if IS_LINUX: + # On ubuntu, activateWindow doesn't work reliably, so + # we do the following as a workaround. See + # https://bugreports.qt-project.org/browse/QTBUG-24932 + # for more details + QtGui.QX11Info.setAppUserTime(0) self.activateWindow() self.raise_() else: -- cgit v1.2.3 From 8c9005e665bb7a77f91cf298f49832f663b0df67 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 24 Jul 2014 17:58:56 -0300 Subject: Disable user/pass remembering temporarily. Set the keyring to None in order to simulate an always unavailable keyring, that way we avoid the possibility of the user running into the existing keyring issues. See https://leap.se/code/issues/4190 Update comparisons to do a proper comparison with `None`. Fix login widget 'enabled' changer in order to change the 'remember' widget *only* if we have an usable keyring. --- src/leap/bitmask/gui/login.py | 3 ++- src/leap/bitmask/util/keyring_helpers.py | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py index f66e71d9..baf29c23 100644 --- a/src/leap/bitmask/gui/login.py +++ b/src/leap/bitmask/gui/login.py @@ -216,7 +216,8 @@ class LoginWidget(QtGui.QWidget): """ self.ui.lnUser.setEnabled(enabled) self.ui.lnPassword.setEnabled(enabled) - self.ui.chkRemember.setEnabled(enabled) + if has_keyring(): + self.ui.chkRemember.setEnabled(enabled) self.ui.cmbProviders.setEnabled(enabled) self._set_cancel(not enabled) diff --git a/src/leap/bitmask/util/keyring_helpers.py b/src/leap/bitmask/util/keyring_helpers.py index ee2d7a1c..0512d988 100644 --- a/src/leap/bitmask/util/keyring_helpers.py +++ b/src/leap/bitmask/util/keyring_helpers.py @@ -34,6 +34,10 @@ except Exception: # dbus socket, or stuff like that. keyring = None +# XXX remember password disabled right now! +# see: https://leap.se/code/issues/4190 +keyring = None + logger = logging.getLogger(__name__) @@ -46,7 +50,7 @@ def _get_keyring_with_fallback(): This is a workaround for the cases in which the keyring module chooses an insecure keyring by default (ie, inside a virtualenv). """ - if not keyring: + if keyring is None: return None kr = keyring.get_keyring() if not canuse(kr): @@ -67,7 +71,7 @@ def has_keyring(): :rtype: bool """ - if not keyring: + if keyring is None: return False kr = _get_keyring_with_fallback() return canuse(kr) @@ -79,7 +83,7 @@ def get_keyring(): :rtype: keyringBackend or None """ - if not keyring: + if keyring is None: return False kr = _get_keyring_with_fallback() return kr if canuse(kr) else None -- cgit v1.2.3 From be27a8b548f01220f34c8f15dbc1973b110a790f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 25 Jul 2014 11:13:23 -0300 Subject: Simplify and sort OS flags. --- src/leap/bitmask/platform_init/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/platform_init/__init__.py b/src/leap/bitmask/platform_init/__init__.py index 2a262a30..a9a97af9 100644 --- a/src/leap/bitmask/platform_init/__init__.py +++ b/src/leap/bitmask/platform_init/__init__.py @@ -22,7 +22,7 @@ import platform _system = platform.system() -IS_WIN = True if _system == "Windows" else False -IS_MAC = True if _system == "Darwin" else False -IS_LINUX = True if _system == "Linux" else False +IS_LINUX = _system == "Linux" +IS_MAC = _system == "Darwin" IS_UNIX = IS_MAC or IS_LINUX +IS_WIN = _system == "Windows" -- cgit v1.2.3 From 28553c41c3d879481923102a1b41ecd71641d0d8 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 25 Jul 2014 11:13:53 -0300 Subject: Add Linux autostart. Closes #4989. --- src/leap/bitmask/gui/mainwindow.py | 5 ++- src/leap/bitmask/util/autostart.py | 67 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/leap/bitmask/util/autostart.py (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 383f97bb..2f78fd14 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -58,7 +58,7 @@ from leap.bitmask.services.mail import conductor as mail_conductor from leap.bitmask.services import EIP_SERVICE, MX_SERVICE -from leap.bitmask.util import make_address +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 @@ -108,6 +108,7 @@ class MainWindow(QtGui.QMainWindow): :type start_hidden: bool """ QtGui.QMainWindow.__init__(self) + autostart.set_autostart(True) # register leap events ######################################## register(signal=proto.UPDATER_NEW_UPDATES, @@ -1797,6 +1798,8 @@ class MainWindow(QtGui.QMainWindow): if self._quitting: return + autostart.set_autostart(False) + self._quitting = True # first thing to do quitting, hide the mainwindow and show tooltip. diff --git a/src/leap/bitmask/util/autostart.py b/src/leap/bitmask/util/autostart.py new file mode 100644 index 00000000..b8ac02b1 --- /dev/null +++ b/src/leap/bitmask/util/autostart.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# autostart.py +# Copyright (C) 2013, 2014 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 . +""" +Helpers to enable/disable bitmask's autostart. +""" +import flags +import logging +import os + +from leap.bitmask.platform_init import IS_LINUX + +logger = logging.getLogger(__name__) + + +DESKTOP_ENTRY = """\ +[Desktop Entry] +Version=1.0 +Encoding=UTF-8 +Type=Application +Name=Bitmask +Comment=Secure Communication +Exec=bitmask --start-hidden +Terminal=false +Icon=bitmask +""" + +DESKTOP_ENTRY_PATH = os.path.expanduser("~/.config/autostart/bitmask.desktop") + + +def set_autostart(enabled): + """ + Set the autostart mode to enabled or disabled depending on the parameter. + If `enabled` is `True`, save the autostart file to its place. Otherwise, + remove that file. + Right now we support only Linux autostart. + + :param enabled: whether the autostart should be enabled or not. + :type enabled: bool + """ + # we don't do autostart for bundle or systems different than Linux + if flags.STANDALONE or not IS_LINUX: + return + + if enabled: + with open(DESKTOP_ENTRY_PATH, 'w') as f: + f.write(DESKTOP_ENTRY) + else: + try: + os.remove(DESKTOP_ENTRY_PATH) + except OSError: # if the file does not exist + pass + except Exception as e: + logger.error("Problem disabling autostart, {0!r}".format(e)) -- cgit v1.2.3 From 89cb09b95f1c45a95c22c9ec99e7ba62fa6dd98b Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 25 Jul 2014 12:21:06 -0300 Subject: Fix misused import. --- src/leap/bitmask/util/autostart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/bitmask/util/autostart.py b/src/leap/bitmask/util/autostart.py index b8ac02b1..5f003bd8 100644 --- a/src/leap/bitmask/util/autostart.py +++ b/src/leap/bitmask/util/autostart.py @@ -17,10 +17,10 @@ """ Helpers to enable/disable bitmask's autostart. """ -import flags import logging import os +from leap.bitmask.config import flags from leap.bitmask.platform_init import IS_LINUX logger = logging.getLogger(__name__) -- cgit v1.2.3 From c4df5cff32524bf2fa9e5d43f08210361531d273 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 25 Jul 2014 12:41:25 -0300 Subject: Create the autostart path in case that does not exist. --- src/leap/bitmask/util/autostart.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/util/autostart.py b/src/leap/bitmask/util/autostart.py index 5f003bd8..d7a8afb8 100644 --- a/src/leap/bitmask/util/autostart.py +++ b/src/leap/bitmask/util/autostart.py @@ -22,6 +22,7 @@ import os from leap.bitmask.config import flags from leap.bitmask.platform_init import IS_LINUX +from leap.common.files import mkdir_p logger = logging.getLogger(__name__) @@ -38,7 +39,8 @@ Terminal=false Icon=bitmask """ -DESKTOP_ENTRY_PATH = os.path.expanduser("~/.config/autostart/bitmask.desktop") +DESKTOP_ENTRY_PATH = os.path.expanduser("~/.config/autostart/") +DESKTOP_ENTRY_FILE = os.path.join(DESKTOP_ENTRY_PATH, 'bitmask.desktop') def set_autostart(enabled): @@ -56,11 +58,12 @@ def set_autostart(enabled): return if enabled: - with open(DESKTOP_ENTRY_PATH, 'w') as f: + mkdir_p(DESKTOP_ENTRY_PATH) + with open(DESKTOP_ENTRY_FILE, 'w') as f: f.write(DESKTOP_ENTRY) else: try: - os.remove(DESKTOP_ENTRY_PATH) + os.remove(DESKTOP_ENTRY_FILE) except OSError: # if the file does not exist pass except Exception as e: -- cgit v1.2.3 From 72b6e999c883272cbe291ac610c528b5ae51077b Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 28 Jul 2014 16:49:44 -0300 Subject: Do `quit()` if the system requested the app to close. This fixes the issue where a system logout was blocked by bitmask since we were interpreting the closeEvent as if the user clicked on the 'X' button. Closes #5870. --- src/leap/bitmask/gui/mainwindow.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 2f78fd14..4f7f519c 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1138,6 +1138,11 @@ class MainWindow(QtGui.QMainWindow): """ Reimplementation of closeEvent to close to tray """ + if not e.spontaneous(): + # if the system requested the `close` then we should quit. + self.quit() + return + if QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ not self._really_quit: self._toggle_visible() -- cgit v1.2.3 From 0f72cb6694ea8f6d17f731c469f976250eab61f8 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 30 Jul 2014 18:07:33 -0300 Subject: Reduce services stop timeout. --- src/leap/bitmask/gui/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 4f7f519c..c08ef08d 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -97,7 +97,7 @@ class MainWindow(QtGui.QMainWindow): EIP_START_TIMEOUT = 60000 # in milliseconds # We give the services some time to a halt before forcing quit. - SERVICES_STOP_TIMEOUT = 20000 # in milliseconds + SERVICES_STOP_TIMEOUT = 3000 # in milliseconds def __init__(self, start_hidden=False, backend_pid=None): """ -- cgit v1.2.3 From 08d89399eb41261d796e8b35427354581c0c8f4a Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 30 Jul 2014 18:07:37 -0300 Subject: Handle the system's quit correctly. Use a simple sleep to wait until the services are stopped and then kill the backend, always in a fixed time in order to avoid blocks/hangs on the system session logout. Closes #5870. --- src/leap/bitmask/gui/mainwindow.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index c08ef08d..46f0928f 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -197,6 +197,7 @@ class MainWindow(QtGui.QMainWindow): # used to know if we are in the final steps of quitting self._quitting = False self._finally_quitting = False + self._system_quit = False self._backend_connected_signals = [] self._backend_connect() @@ -1140,6 +1141,7 @@ class MainWindow(QtGui.QMainWindow): """ if not e.spontaneous(): # if the system requested the `close` then we should quit. + self._system_quit = True self.quit() return @@ -1809,7 +1811,7 @@ class MainWindow(QtGui.QMainWindow): # first thing to do quitting, hide the mainwindow and show tooltip. self.hide() - if self._systray is not None: + if not self._system_quit and self._systray is not None: self._systray.showMessage( self.tr('Quitting...'), self.tr('Bitmask is quitting, please wait.')) @@ -1833,10 +1835,18 @@ class MainWindow(QtGui.QMainWindow): self.final_quit() return - self._stop_services() - # call final quit when all the services are stopped self.all_services_stopped.connect(self.final_quit) + + self._stop_services() + + # we wait and call manually since during the system's logout the + # backend process can be killed and we won't get a response. + # XXX: also, for some reason the services stop timeout does not work. + if self._system_quit: + time.sleep(0.5) + self.final_quit() + # or if we reach the timeout QtDelayedCall(self.SERVICES_STOP_TIMEOUT, self.final_quit) @@ -1859,6 +1869,7 @@ class MainWindow(QtGui.QMainWindow): :param service: the service that we want to remove :type service: str """ + logger.debug("Removing service: {0}".format(service)) self._services_being_stopped.discard(service) if not self._services_being_stopped: @@ -1886,13 +1897,13 @@ class MainWindow(QtGui.QMainWindow): self._leap_signaler.stop() - if self._backend.online: - self._backend.stop() - else: - self._backend_kill() - + self._backend.stop() time.sleep(0.05) # give the thread a little time to finish. + if self._system_quit or not self._backend.online: + logger.debug("Killing the backend") + self._backend_kill() + # Remove lockfiles on a clean shutdown. logger.debug('Cleaning pidfiles') if IS_WIN: -- cgit v1.2.3 From 75eddcf502d23f761cbac26da34fcfd1ab669b8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Thu, 31 Jul 2014 14:45:43 -0300 Subject: Enable keyring again --- src/leap/bitmask/gui/login.py | 3 +-- src/leap/bitmask/util/keyring_helpers.py | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py index baf29c23..8e0a3a15 100644 --- a/src/leap/bitmask/gui/login.py +++ b/src/leap/bitmask/gui/login.py @@ -216,8 +216,7 @@ class LoginWidget(QtGui.QWidget): """ self.ui.lnUser.setEnabled(enabled) self.ui.lnPassword.setEnabled(enabled) - if has_keyring(): - self.ui.chkRemember.setEnabled(enabled) + self.ui.chkRemember.setEnabled(enabled and has_keyring()) self.ui.cmbProviders.setEnabled(enabled) self._set_cancel(not enabled) diff --git a/src/leap/bitmask/util/keyring_helpers.py b/src/leap/bitmask/util/keyring_helpers.py index 0512d988..088e7b3d 100644 --- a/src/leap/bitmask/util/keyring_helpers.py +++ b/src/leap/bitmask/util/keyring_helpers.py @@ -34,10 +34,6 @@ except Exception: # dbus socket, or stuff like that. keyring = None -# XXX remember password disabled right now! -# see: https://leap.se/code/issues/4190 -keyring = None - logger = logging.getLogger(__name__) -- cgit v1.2.3 From d201ee8ff03905e008ce316bae81aa6cfe2caf58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Thu, 31 Jul 2014 15:50:28 -0300 Subject: Do not default to SecretService keyring --- src/leap/bitmask/util/keyring_helpers.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/util/keyring_helpers.py b/src/leap/bitmask/util/keyring_helpers.py index 088e7b3d..2b729b65 100644 --- a/src/leap/bitmask/util/keyring_helpers.py +++ b/src/leap/bitmask/util/keyring_helpers.py @@ -50,11 +50,8 @@ def _get_keyring_with_fallback(): return None kr = keyring.get_keyring() if not canuse(kr): - try: - kr_klass = keyring.backends.SecretService - kr = kr_klass.Keyring() - except AttributeError: - logger.warning("Keyring cannot find SecretService Backend") + logger.debug("No usable keyring found") + return None logger.debug("Selected keyring: %s" % (kr.__class__,)) if not canuse(kr): logger.debug("Not using default keyring since it is obsolete") -- cgit v1.2.3 From 3b469a2c006381ba9e56c1de92be4e87ad67e51b Mon Sep 17 00:00:00 2001 From: kali Date: Sun, 27 Jul 2014 19:00:37 -0500 Subject: Add cancel button for EIP connection. Closes: #4035 This falls in the "quick" workaround category. A proper state machine that extends the four basic connection states is hence needed. We have to accomodate design to have a connection-oriented state machine in the backend (I would favor a twisted protocol for this), and a more lightweight one that conducts the gui-level changes (ie, change the actions / buttons / labels accordingly). Since this "cancel" functionality has been long postponed, I chose to do one more ugly hack here, that is, show and hide dance with a button that just calls the bitmask-root to kill the vpn process. It should work well enough until we get to the reorganization needed for a clean process control for eip. --- src/leap/bitmask/backend/api.py | 4 ++ src/leap/bitmask/backend/backend_proxy.py | 3 ++ src/leap/bitmask/backend/components.py | 7 +++- src/leap/bitmask/backend/leapbackend.py | 6 +++ src/leap/bitmask/backend/leapsignaler.py | 1 + src/leap/bitmask/gui/eip_status.py | 45 +++++++++++++++++++- src/leap/bitmask/gui/mainwindow.py | 64 ++++++++++++++++++----------- src/leap/bitmask/gui/ui/eip_status.ui | 41 ++++++++++-------- src/leap/bitmask/services/eip/conductor.py | 18 ++++++-- src/leap/bitmask/services/eip/vpnprocess.py | 12 ++++++ 10 files changed, 153 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py index 4f52e470..3f6c0ad1 100644 --- a/src/leap/bitmask/backend/api.py +++ b/src/leap/bitmask/backend/api.py @@ -20,6 +20,8 @@ Backend available API and SIGNALS definition. STOP_REQUEST = "stop" PING_REQUEST = "PING" +# XXX this needs documentation. What is it used for? + API = ( STOP_REQUEST, # this method needs to be defined in order to support the # backend stop action @@ -56,6 +58,7 @@ API = ( "soledad_close", "soledad_load_offline", "tear_fw_down", + "bitmask_root_vpn_down", "user_cancel_login", "user_change_password", "user_get_logged_in_status", @@ -97,6 +100,7 @@ SIGNALS = ( "eip_status_changed", "eip_stopped", "eip_tear_fw_down", + "eip_bitmask_root_vpn_down", "eip_uninitialized_provider", "eip_vpn_launcher_exception", "imap_stopped", diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py index dc30d2cb..e2611251 100644 --- a/src/leap/bitmask/backend/backend_proxy.py +++ b/src/leap/bitmask/backend/backend_proxy.py @@ -18,6 +18,8 @@ The BackendProxy handles calls from the GUI and forwards (through ZMQ) to the backend. """ +# XXX should document the relationship to the API here. + import functools import Queue import threading @@ -37,6 +39,7 @@ class BackendProxy(object): The BackendProxy handles calls from the GUI and forwards (through ZMQ) to the backend. """ + PORT = '5556' SERVER = "tcp://localhost:%s" % PORT diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py index b372db89..f721086b 100644 --- a/src/leap/bitmask/backend/components.py +++ b/src/leap/bitmask/backend/components.py @@ -69,7 +69,6 @@ class ILEAPComponent(zope.interface.Interface): """ Interface that every component for the backend should comply to """ - key = zope.interface.Attribute("Key id for this component") @@ -552,6 +551,12 @@ class EIP(object): """ self._vpn.tear_down_firewall() + def bitmask_root_vpn_down(self): + """ + Bring openvpn down, using bitmask-root helper. + """ + self._vpn.bitmask_root_vpn_down() + def get_gateways_list(self, domain): """ Signal a list of gateways for the given provider. diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py index 6b0328ca..3b023563 100644 --- a/src/leap/bitmask/backend/leapbackend.py +++ b/src/leap/bitmask/backend/leapbackend.py @@ -317,6 +317,12 @@ class LeapBackend(Backend): """ self._eip.tear_fw_down() + def bitmask_root_vpn_down(self): + """ + Signal the need to bring vpn down. + """ + self._eip.bitmask_root_vpn_down() + def user_login(self, provider, username, password): """ Execute the whole authentication process for a user diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py index a36e6fdc..c0fdffdc 100644 --- a/src/leap/bitmask/backend/leapsignaler.py +++ b/src/leap/bitmask/backend/leapsignaler.py @@ -58,6 +58,7 @@ class LeapSignaler(SignalerQt): eip_status_changed = QtCore.Signal(dict) eip_stopped = QtCore.Signal() eip_tear_fw_down = QtCore.Signal(object) + eip_bitmask_root_vpn_down = QtCore.Signal(object) eip_uninitialized_provider = QtCore.Signal() eip_vpn_launcher_exception = QtCore.Signal() diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index a707050a..f283b148 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -70,8 +70,11 @@ class EIPStatusWidget(QtGui.QWidget): self.ui.eip_bandwidth.hide() self.hide_fw_down_button() + self.hide_eip_cancel_button() self.ui.btnFwDown.clicked.connect( self._on_fw_down_button_clicked) + self.ui.btnEipCancel.clicked.connect( + self._on_eip_cancel_button_clicked) # Set the EIP status icons self.CONNECTING_ICON = None @@ -88,6 +91,7 @@ class EIPStatusWidget(QtGui.QWidget): self._provider = "" self.is_restart = False self.is_cold_start = True + self.user_cancelled = False self.missing_helpers = False @@ -285,6 +289,8 @@ class EIPStatusWidget(QtGui.QWidget): Triggered when the app activates eip. Disables the start/stop button. """ + # XXX hack -- we show the cancel button instead. + self.ui.btnEipStartStop.hide() self.set_startstop_enabled(False) msg = self.tr("Encrypted Internet is starting") self.set_eip_message(msg) @@ -295,6 +301,9 @@ class EIPStatusWidget(QtGui.QWidget): Triggered when a default provider_config has not been found. Disables the start button and adds instructions to the user. """ + # XXX this name is unfortunate. "disable" is also applied to a + # pushbutton being grayed out. + 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. @@ -327,6 +336,7 @@ class EIPStatusWidget(QtGui.QWidget): """ # logger.debug('Showing EIP start button') self.eip_button.show() + self.hide_eip_cancel_button() # Restore the eip action menu menu = self._systray.contextMenu() @@ -420,6 +430,28 @@ class EIPStatusWidget(QtGui.QWidget): self.set_eip_message(msg) self.set_eip_status("") + def hide_eip_cancel_button(self): + """ + Hide eip-cancel button. + """ + self.ui.btnEipCancel.hide() + + def show_eip_cancel_button(self): + """ + Show eip-cancel button. + """ + self.ui.btnEipCancel.show() + self.user_cancelled = False + + def _on_eip_cancel_button_clicked(self): + """ + Call backend to kill the openvpn process with root privileges. + """ + self.eip_conductor.cancelled = True + self.eip_conductor._backend.bitmask_root_vpn_down() + self.user_cancelled = True + self.hide_eip_cancel_button() + @QtCore.Slot(dict) def eip_stopped(self, restart=False, failed=False): """ @@ -433,6 +465,11 @@ class EIPStatusWidget(QtGui.QWidget): self._reset_traffic_rates() self.ui.eip_bandwidth.hide() + if self.user_cancelled: + self.eip_conductor._backend.tear_fw_down() + self.eip_button.show() + failed = False + # This is assuming the firewall works correctly, but we should test fw # status positively. # Or better call it from the conductor... @@ -447,6 +484,7 @@ class EIPStatusWidget(QtGui.QWidget): msg = failed_msg else: msg = clear_traffic + self.set_eip_message(msg) self.ui.lblEIPStatus.show() self.show() @@ -523,16 +561,19 @@ class EIPStatusWidget(QtGui.QWidget): self.eipconnection.qtsigs.connected_signal.emit() self._on_eip_connected() self.is_cold_start = False + self.hide_eip_cancel_button() + self.eip_button.show() # XXX should lookup vpn_state map in EIPConnection elif vpn_state == "AUTH": self.set_eip_status(self.tr("Authenticating...")) + + # XXX should be handled by a future state machine instead. + self.show_eip_cancel_button() # we wipe up any previous error info in the EIP message # when we detect vpn authentication is happening msg = self.tr("Encrypted Internet is starting") self.set_eip_message(msg) - # on the first-run path, we hadn't showed the button yet. - self.eip_button.show() elif vpn_state == "GET_CONFIG": self.set_eip_status(self.tr("Retrieving configuration...")) elif vpn_state == "WAIT": diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 46f0928f..25bda305 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -166,6 +166,9 @@ class MainWindow(QtGui.QMainWindow): 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() @@ -180,6 +183,7 @@ class MainWindow(QtGui.QMainWindow): 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 @@ -561,7 +565,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self.ui.action_show_logs.triggered - Displays the window with the history of messages logged until now + Display the window with the history of messages logged until now and displays the new ones on arrival. """ if self._logger_window is None: @@ -582,7 +586,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self.ui.action_advanced_key_management.triggered - Displays the Advanced Key Management dialog. + Display the Advanced Key Management dialog. """ domain = self._login_widget.get_selected_provider() logged_user = "{0}@{1}".format(self._logged_user, domain) @@ -604,7 +608,7 @@ class MainWindow(QtGui.QMainWindow): self.ui.btnPreferences.clicked (disabled for now) self.ui.action_preferences - Displays the preferences window. + Display the preferences window. """ user = self._logged_user domain = self._login_widget.get_selected_provider() @@ -722,7 +726,7 @@ class MainWindow(QtGui.QMainWindow): self.ui.btnEIPPreferences.clicked self.ui.action_eip_preferences (disabled for now) - Displays the EIP preferences window. + Display the EIP preferences window. """ domain = self._login_widget.get_selected_provider() pref = EIPPreferencesWindow(self, domain, @@ -748,7 +752,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self.new_updates - Displays the new updates label and sets the updates_content + Display the new updates label and sets the updates_content :param req: Request type :type req: leap.common.events.events_pb2.SignalRequest @@ -963,7 +967,7 @@ class MainWindow(QtGui.QMainWindow): :param reason: the reason why the tray got activated. :type reason: int - Displays the context menu from the tray icon + Display the context menu from the tray icon """ self._update_hideshow_menu() @@ -977,7 +981,7 @@ class MainWindow(QtGui.QMainWindow): def _update_hideshow_menu(self): """ - Updates the Hide/Show main window menu text based on the + Update the Hide/Show main window menu text based on the visibility of the window. """ get_action = lambda visible: ( @@ -994,7 +998,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self._action_visible.triggered - Toggles the window visibility + Toggle the window visibility """ visible = self.isVisible() and self.isActiveWindow() @@ -1022,7 +1026,7 @@ class MainWindow(QtGui.QMainWindow): def _center_window(self): """ - Centers the mainwindow based on the desktop geometry + Center the main window based on the desktop geometry """ geometry = self._settings.get_geometry() state = self._settings.get_windowstate() @@ -1124,7 +1128,7 @@ class MainWindow(QtGui.QMainWindow): def changeEvent(self, e): """ - Reimplements the changeEvent method to minimize to tray + Reimplementation of changeEvent method to minimize to tray """ if not IS_MAC and \ QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ @@ -1158,7 +1162,7 @@ class MainWindow(QtGui.QMainWindow): def _first_run(self): """ - Returns True if there are no configured providers. False otherwise + Return True if there are no configured providers. False otherwise :rtype: bool """ @@ -1169,7 +1173,7 @@ class MainWindow(QtGui.QMainWindow): def _download_provider_config(self): """ - Starts the bootstrapping sequence. It will download the + Start the bootstrapping sequence. It will download the provider configuration if it's not present, otherwise will emit the corresponding signals inmediately """ @@ -1199,8 +1203,9 @@ class MainWindow(QtGui.QMainWindow): @QtCore.Slot() def _login_problem_provider(self): """ - Warns the user about a problem with the provider during login. + Warn the user about a problem with the provider during login. """ + # XXX triggers? self._login_widget.set_status( self.tr("Unable to login: Problem with provider")) self._login_widget.set_enabled(True) @@ -1211,7 +1216,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self._login_widget.login - Starts the login sequence. Which involves bootstrapping the + Start the login sequence. Which involves bootstrapping the selected provider if the selection is valid (not empty), then start the SRP authentication, and as the last step bootstrapping the EIP service @@ -1256,7 +1261,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self._login_widget.cancel_login - Stops the login sequence. + Stop the login sequence. """ logger.debug("Cancelling log in.") self._cancel_ongoing_defers() @@ -1280,7 +1285,7 @@ class MainWindow(QtGui.QMainWindow): Signaler.prov_cancelled_setup fired by self._backend.provider_cancel_setup() - This method re-enables the login widget and display a message for + Re-enable the login widget and display a message for the cancelled operation. """ self._login_widget.set_status(self.tr("Log in cancelled by the user.")) @@ -1340,7 +1345,7 @@ class MainWindow(QtGui.QMainWindow): def _start_eip_bootstrap(self): """ - Changes the stackedWidget index to the EIP status one and + Change the stackedWidget index to the EIP status one and triggers the eip bootstrapping. """ @@ -1384,7 +1389,7 @@ class MainWindow(QtGui.QMainWindow): def _provides_mx_and_enabled(self): """ - Defines if the current provider provides mx and if we have it enabled. + Define if the current provider provides mx and if we have it enabled. :returns: True if provides and is enabled, False otherwise :rtype: bool @@ -1401,7 +1406,7 @@ class MainWindow(QtGui.QMainWindow): def _provides_eip_and_enabled(self): """ - Defines if the current provider provides eip and if we have it enabled. + Define if the current provider provides eip and if we have it enabled. :returns: True if provides and is enabled, False otherwise :rtype: bool @@ -1503,14 +1508,14 @@ class MainWindow(QtGui.QMainWindow): @QtCore.Slot() def _disable_eip_start_action(self): """ - Disables the EIP start action in the systray menu. + Disable 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. + Enable the EIP start action in the systray menu. """ self._action_eip_startstop.setEnabled(True) self._eip_status.enable_eip_start() @@ -1567,7 +1572,7 @@ class MainWindow(QtGui.QMainWindow): def _try_autostart_eip(self): """ - Tries to autostart EIP + Try to autostart EIP. """ settings = self._settings default_provider = settings.get_defaultprovider() @@ -1587,6 +1592,8 @@ class MainWindow(QtGui.QMainWindow): :param autostart: we are autostarting EIP when this is True :type autostart: bool """ + # XXX should move to EIP conductor. + # during autostart we assume that the provider provides EIP if autostart: should_start = EIP_SERVICE in self._enabled_services @@ -1606,6 +1613,12 @@ class MainWindow(QtGui.QMainWindow): self._enable_eip_start_action() self._eip_status.set_eip_status( self.tr("Starting...")) + self._eip_status.show_eip_cancel_button() + + # We were disabling the button, but now that we have + # a cancel button we just hide it. It will be visible + # when the connection is completed successfully. + self._eip_status.eip_button.hide() self._eip_status.eip_button.setEnabled(False) domain = self._login_widget.get_selected_provider() @@ -1680,7 +1693,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self._login_widget.logout - Starts the logout sequence + Start the logout sequence """ self._cancel_ongoing_defers() @@ -1708,7 +1721,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGER: self._srp_auth.logout_ok - Switches the stackedWidget back to the login stage after + Switch the stackedWidget back to the login stage after logging out """ self._login_widget.done_logout() @@ -1729,7 +1742,7 @@ class MainWindow(QtGui.QMainWindow): self._backend.signaler.prov_https_connection self._backend.signaler.prov_download_ca_cert - If there was a problem, displays it, otherwise it does nothing. + If there was a problem, display it, otherwise it does nothing. This is used for intermediate bootstrapping stages, in case they fail. """ @@ -1783,6 +1796,7 @@ class MainWindow(QtGui.QMainWindow): imap_stopped = lambda: self._remove_service('imap') self._leap_signaler.imap_stopped.connect(imap_stopped) + # XXX change name, already used in conductor. eip_stopped = lambda: self._remove_service('eip') self._leap_signaler.eip_stopped.connect(eip_stopped) diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui index 7216bb0a..e0996620 100644 --- a/src/leap/bitmask/gui/ui/eip_status.ui +++ b/src/leap/bitmask/gui/ui/eip_status.ui @@ -28,13 +28,26 @@ 0 - + Turn On + + + + Qt::Horizontal + + + + 40 + 0 + + + + @@ -86,7 +99,7 @@ - + @@ -105,20 +118,7 @@ - - - - Qt::Horizontal - - - - 40 - 0 - - - - - + @@ -239,7 +239,7 @@ - + Turn Off @@ -253,6 +253,13 @@ + + + + Cancel + + + diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py index bb07809a..b755f283 100644 --- a/src/leap/bitmask/services/eip/conductor.py +++ b/src/leap/bitmask/services/eip/conductor.py @@ -137,6 +137,7 @@ class EIPConductor(object): else: self._eip_status.eip_pre_up() self.user_stopped_eip = False + self.cancelled = False self._eip_status.hide_fw_down_button() # Until we set an option in the preferences window, we'll assume that @@ -175,6 +176,9 @@ class EIPConductor(object): :param failed: whether this is the final step of a retry sequence :type failed: bool """ + # XXX we should NOT keep status in the widget, but we do for a series + # of hacks related to restarts. All status should be kept in a backend + # object, widgets should be just widgets. self._eip_status.is_restart = restart self.user_stopped_eip = not restart and not failed @@ -302,18 +306,26 @@ class EIPConductor(object): # bitmask-root is masking the exitcode, so we might need # to fix it on that side. # if exitCode != 0 and not self.user_stopped_eip: - if not self.user_stopped_eip: + + if not self.user_stopped_eip and not self.cancelled: + error = True eip_status_label = self._eip_status.tr( "{0} finished in an unexpected manner!") eip_status_label = eip_status_label.format(self.eip_name) - self._eip_status.eip_stopped() self._eip_status.set_eip_status_icon("error") self._eip_status.set_eip_status(eip_status_label, - error=True) + error=error) + self._eip_status.eip_stopped() signal = self.qtsigs.connection_died_signal self._eip_status.show_fw_down_button() self._eip_status.eip_failed_to_connect() + if self.cancelled: + signal = self.qtsigs.connection_aborted_signal + self._eip_status.set_eip_status_icon("error") + self._eip_status.eip_stopped() + self._eip_status.set_eip_status("", error=False) + if exitCode == 0 and IS_MAC: # XXX remove this warning after I fix cocoasudo. logger.warning("The above exit code MIGHT BE WRONG.") diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index d1a3fdaa..c6a7b98b 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -263,6 +263,18 @@ class VPN(object): BM_ROOT, "firewall", "stop"]) return True if exitCode is 0 else False + def bitmask_root_vpn_down(self): + """ + Bring openvpn down using the privileged wrapper. + """ + if IS_MAC: + # We don't support Mac so far + return True + BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT) + exitCode = subprocess.call(["pkexec", + BM_ROOT, "openvpn", "stop"]) + return True if exitCode is 0 else False + def _kill_if_left_alive(self, tries=0): """ Check if the process is still alive, and send a -- cgit v1.2.3 From b0365dbb706af23375fd6676d2ffe4a64a824754 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 4 Aug 2014 15:29:57 -0300 Subject: Disable daemon mode, we use processes in the backend. --- src/leap/bitmask/app.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 37ded92a..ad886bc4 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -183,7 +183,9 @@ def start_app(): frontend_pid = os.getpid() backend = lambda: run_backend(opts.danger, flags_dict, frontend_pid) backend_process = multiprocessing.Process(target=backend, name='Backend') - backend_process.daemon = True + # we don't set the 'daemon mode' since we need to start child processes in + # the backend + # backend_process.daemon = True backend_process.start() run_frontend(options, flags_dict, backend_pid=backend_process.pid) -- cgit v1.2.3 From 2eb3805dc2c470feab5a3d3bc283e82ff7c6bce7 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 5 Aug 2014 18:03:05 -0300 Subject: Reduce height to fit on smaller resolutions. Closes #5722. --- src/leap/bitmask/gui/ui/mainwindow.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index d755115a..1eeb636f 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 524 - 722 + 640 @@ -75,7 +75,7 @@ 0 0 524 - 667 + 589 @@ -297,7 +297,7 @@ 0 0 524 - 23 + 21 -- cgit v1.2.3 From 9a7485bcaf5460d68b7f601927500299bb2ca9f0 Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 5 Aug 2014 12:43:25 -0500 Subject: fix uncatched error with missing polkit. Closes: #5955 --- src/leap/bitmask/backend/backend.py | 10 ++++++++++ src/leap/bitmask/gui/eip_status.py | 11 ++++++++++- src/leap/bitmask/services/eip/conductor.py | 13 ++++++++++--- src/leap/bitmask/services/eip/vpnprocess.py | 19 ++++++++++++++++++- 4 files changed, 48 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py index 67ffe35a..37535f37 100644 --- a/src/leap/bitmask/backend/backend.py +++ b/src/leap/bitmask/backend/backend.py @@ -14,6 +14,11 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . + +# FIXME this is missing module documentation. It would be fine to say a couple +# of lines about the whole backend architecture. +# TODO use txzmq bindings instead. + import json import threading import time @@ -38,7 +43,11 @@ class Backend(object): Backend server. Receives signals from backend_proxy and emit signals if needed. """ + # XXX this should not be hardcoded. Make it configurable. PORT = '5556' + + # XXX we might want to make this configurable per-platform, + # and use the most performant socket type on each one. BIND_ADDR = "tcp://127.0.0.1:%s" % PORT PING_INTERVAL = 2 # secs @@ -67,6 +76,7 @@ class Backend(object): # Start an authenticator for this context. auth = ThreadAuthenticator(context) auth.start() + # XXX do not hardcode this here. auth.allow('127.0.0.1') # Tell authenticator to use the certificate in a directory diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index f283b148..1e764a8c 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -367,6 +367,7 @@ class EIPStatusWidget(QtGui.QWidget): leap_assert_type(error, bool) if error: logger.error(status) + self.hide_eip_cancel_button() else: logger.debug(status) self._eip_status = status @@ -723,9 +724,17 @@ class EIPStatusWidget(QtGui.QWidget): def _on_eip_vpn_launcher_exception(self): # XXX We should implement again translatable exceptions so # we can pass a translatable string to the panel (usermessage attr) - self.set_eip_status("VPN Launcher error.", error=True) + # FIXME this logic should belong to the backend, not to this + # widget. self.set_eipstatus_off() + st = self.tr("VPN Launcher error. See the logs for more info.") + self.set_eip_status(st, error=True) + + msg = self.tr("Encrypted Internet failed to start") + self.set_eip_message(msg) + self.show_fw_down_button() + self.aborted() def _on_eip_no_polkit_agent_error(self): diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py index b755f283..0ee56628 100644 --- a/src/leap/bitmask/services/eip/conductor.py +++ b/src/leap/bitmask/services/eip/conductor.py @@ -16,6 +16,9 @@ # along with this program. If not, see . """ EIP Conductor module. + +This handles Qt Signals and triggers the calls to the backend, +where the VPNProcess has been initialized. """ import logging @@ -90,7 +93,7 @@ class EIPConductor(object): def start_eip_machine(self, action): """ - Initializes and starts the EIP state machine. + Initialize and start the EIP state machine. Needs the reference to the eip_status widget not to be empty. :action: QtAction @@ -124,8 +127,12 @@ class EIPConductor(object): @QtCore.Slot() def _start_eip(self): """ - Starts EIP. + Start EIP. + + This set a couple of status flags and calls the start procedure in the + backend. """ + # TODO status should be kept in a singleton in the backend. st = self._eip_status is_restart = st and st.is_restart @@ -271,7 +278,7 @@ class EIPConductor(object): TRIGGERS: Signaler.eip_process_finished - Triggered when the EIP/VPN process finishes to set the UI + Triggered when the EIP/VPN process finishes, in order to set the UI accordingly. Ideally we would have the right exit code here, diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py index c6a7b98b..c7159a93 100644 --- a/src/leap/bitmask/services/eip/vpnprocess.py +++ b/src/leap/bitmask/services/eip/vpnprocess.py @@ -202,7 +202,24 @@ class VPN(object): "aborting openvpn launch.") return - cmd = vpnproc.getCommand() + # FIXME it would be good to document where the + # errors here are catched, since we currently handle them + # at the frontend layer. This *should* move to be handled entirely + # in the backend. + # exception is indeed technically catched in backend, then converted + # into a signal, that is catched in the eip_status widget in the + # frontend, and converted into a signal to abort the connection that is + # sent to the backend again. + + # the whole exception catching should be done in the backend, without + # the ping-pong to the frontend, and without adding any logical checks + # in the frontend. We should just communicate UI changes to frontend, + # and abstract us away from anything else. + try: + cmd = vpnproc.getCommand() + except Exception: + logger.error("Error while getting vpn command...") + raise env = os.environ for key, val in vpnproc.vpn_env.items(): env[key] = val -- cgit v1.2.3 From f4e6d6a77b8b5498e9190c3d35841ef39222cfec Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 6 Aug 2014 14:46:37 -0300 Subject: Replace twisted thread with QThread. This fix the bug that prevents pastebin to work. Closes #5949. --- src/leap/bitmask/gui/loggerwindow.py | 113 ++++++++++++++++++----------------- src/leap/bitmask/gui/mainwindow.py | 2 +- 2 files changed, 60 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/loggerwindow.py b/src/leap/bitmask/gui/loggerwindow.py index 3a8354b1..c4f44dd7 100644 --- a/src/leap/bitmask/gui/loggerwindow.py +++ b/src/leap/bitmask/gui/loggerwindow.py @@ -18,11 +18,10 @@ """ History log window """ -import logging import cgi +import logging from PySide import QtCore, QtGui -from twisted.internet import threads from ui_loggerwindow import Ui_LoggerWindow @@ -38,6 +37,9 @@ class LoggerWindow(QtGui.QDialog): """ Window that displays a history of the logged messages in the app. """ + _paste_ok = QtCore.Signal(object) + _paste_error = QtCore.Signal(object) + def __init__(self, handler): """ Initialize the widget with the custom handler. @@ -45,9 +47,6 @@ class LoggerWindow(QtGui.QDialog): :param handler: Custom handler that supports history and signal. :type handler: LeapLogHandler. """ - from twisted.internet import reactor - self.reactor = reactor - QtGui.QDialog.__init__(self) leap_assert(handler, "We need a handler for the logger window") leap_assert_type(handler, LeapLogHandler) @@ -67,6 +66,9 @@ class LoggerWindow(QtGui.QDialog): self.ui.cbCaseInsensitive.stateChanged.connect(self._load_history) self.ui.btnPastebin.clicked.connect(self._pastebin_this) + self._paste_ok.connect(self._pastebin_ok) + self._paste_error.connect(self._pastebin_err) + self._current_filter = "" self._current_history = "" @@ -193,6 +195,45 @@ class LoggerWindow(QtGui.QDialog): self.ui.btnPastebin.setText(self.tr("Send to Pastebin.com")) self.ui.btnPastebin.setEnabled(True) + def _pastebin_ok(self, link): + """ + Handle a successful paste. + + :param link: the recently created pastebin link. + :type link: str + """ + self._set_pastebin_sending(False) + msg = self.tr("Your pastebin link {0}") + msg = msg.format(link) + + # We save the dialog in an instance member to avoid dialog being + # deleted right after we exit this method + self._msgBox = msgBox = QtGui.QMessageBox( + QtGui.QMessageBox.Information, self.tr("Pastebin OK"), msg) + msgBox.setWindowModality(QtCore.Qt.NonModal) + msgBox.show() + + def _pastebin_err(self, failure): + """ + Handle a failure in paste. + + :param failure: the exception that made the paste fail. + :type failure: Exception + """ + self._set_pastebin_sending(False) + logger.error(repr(failure)) + + msg = self.tr("Sending logs to Pastebin failed!") + if isinstance(failure, pastebin.PostLimitError): + msg = self.tr('Maximum posts per day reached') + + # We save the dialog in an instance member to avoid dialog being + # deleted right after we exit this method + self._msgBox = msgBox = QtGui.QMessageBox( + QtGui.QMessageBox.Critical, self.tr("Pastebin Error"), msg) + msgBox.setWindowModality(QtCore.Qt.NonModal) + msgBox.show() + def _pastebin_this(self): """ Send the current log history to pastebin.com and gives the user a link @@ -204,55 +245,19 @@ class LoggerWindow(QtGui.QDialog): """ content = self._current_history pb = pastebin.PastebinAPI() - link = pb.paste(PASTEBIN_API_DEV_KEY, content, - paste_name="Bitmask log", - paste_expire_date='1M') - - # convert to 'raw' link - link = "http://pastebin.com/raw.php?i=" + link.split('/')[-1] - - return link - - def pastebin_ok(link): - """ - Callback handler for `do_pastebin`. - - :param link: the recently created pastebin link. - :type link: str - """ - self._set_pastebin_sending(False) - msg = self.tr("Your pastebin link {0}") - msg = msg.format(link) - - # We save the dialog in an instance member to avoid dialog being - # deleted right after we exit this method - self._msgBox = msgBox = QtGui.QMessageBox( - QtGui.QMessageBox.Information, self.tr("Pastebin OK"), msg) - msgBox.setWindowModality(QtCore.Qt.NonModal) - msgBox.show() - - def pastebin_err(failure): - """ - Errback handler for `do_pastebin`. - - :param failure: the failure that triggered the errback. - :type failure: twisted.python.failure.Failure - """ - self._set_pastebin_sending(False) - logger.error(repr(failure)) - - msg = self.tr("Sending logs to Pastebin failed!") - if failure.check(pastebin.PostLimitError): - msg = self.tr('Maximum posts per day reached') + try: + link = pb.paste(PASTEBIN_API_DEV_KEY, content, + paste_name="Bitmask log", + paste_expire_date='1M') + # convert to 'raw' link + link = "http://pastebin.com/raw.php?i=" + link.split('/')[-1] - # We save the dialog in an instance member to avoid dialog being - # deleted right after we exit this method - self._msgBox = msgBox = QtGui.QMessageBox( - QtGui.QMessageBox.Critical, self.tr("Pastebin Error"), msg) - msgBox.setWindowModality(QtCore.Qt.NonModal) - msgBox.show() + self._paste_ok.emit(link) + except Exception as e: + self._paste_error.emit(e) self._set_pastebin_sending(True) - d = threads.deferToThread(do_pastebin) - d.addCallback(pastebin_ok) - d.addErrback(pastebin_err) + + self._paste_thread = QtCore.QThread() + self._paste_thread.run = lambda: do_pastebin() + self._paste_thread.start() diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 25bda305..1bc4c96f 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1837,7 +1837,7 @@ class MainWindow(QtGui.QMainWindow): if self._wizard: self._wizard.close() - if self._logger_window: + if self._logger_window is not None: self._logger_window.close() # Set this in case that the app is hidden -- cgit v1.2.3 From e6a7feeb93a27ef36d15dddcb45c2cc4812a37b0 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 6 Aug 2014 16:03:49 -0300 Subject: Fix logger window blocking the bitmask quit(). - Set the logger window parent, - don't use an mainwindow instance variable to hold the window object. This fix have the side offect that prevent multiple log windows being created at the same time, but it does not causes any side effect or problem. --- src/leap/bitmask/gui/loggerwindow.py | 4 ++-- src/leap/bitmask/gui/mainwindow.py | 21 ++++++--------------- 2 files changed, 8 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/loggerwindow.py b/src/leap/bitmask/gui/loggerwindow.py index c4f44dd7..360dd5f0 100644 --- a/src/leap/bitmask/gui/loggerwindow.py +++ b/src/leap/bitmask/gui/loggerwindow.py @@ -40,14 +40,14 @@ class LoggerWindow(QtGui.QDialog): _paste_ok = QtCore.Signal(object) _paste_error = QtCore.Signal(object) - def __init__(self, handler): + def __init__(self, parent, handler): """ Initialize the widget with the custom handler. :param handler: Custom handler that supports history and signal. :type handler: LeapLogHandler. """ - QtGui.QDialog.__init__(self) + QtGui.QDialog.__init__(self, parent) leap_assert(handler, "We need a handler for the logger window") leap_assert_type(handler, LeapLogHandler) diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 1bc4c96f..389ff172 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -277,8 +277,6 @@ class MainWindow(QtGui.QMainWindow): self._wizard = None self._wizard_firstrun = False - self._logger_window = None - self._start_hidden = start_hidden self._backend_pid = backend_pid @@ -568,17 +566,13 @@ class MainWindow(QtGui.QMainWindow): Display the window with the history of messages logged until now and displays the new ones on arrival. """ - if self._logger_window is None: - leap_log_handler = self._get_leap_logging_handler() - if leap_log_handler is None: - logger.error('Leap logger handler not found') - return - else: - self._logger_window = LoggerWindow(handler=leap_log_handler) - self._logger_window.setVisible( - not self._logger_window.isVisible()) + leap_log_handler = self._get_leap_logging_handler() + if leap_log_handler is None: + logger.error('Leap logger handler not found') + return else: - self._logger_window.setVisible(not self._logger_window.isVisible()) + lw = LoggerWindow(self, handler=leap_log_handler) + lw.show() @QtCore.Slot() def _show_AKM(self): @@ -1837,9 +1831,6 @@ class MainWindow(QtGui.QMainWindow): if self._wizard: self._wizard.close() - if self._logger_window is not None: - self._logger_window.close() - # Set this in case that the app is hidden QtGui.QApplication.setQuitOnLastWindowClosed(True) -- cgit v1.2.3 From db9e6c728118c93413d11262993548dbeb51e28b Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 8 Aug 2014 11:33:30 -0500 Subject: remove outdated comment eip machine was already moved into conductor --- src/leap/bitmask/gui/mainwindow.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 389ff172..02488af1 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -285,14 +285,8 @@ class MainWindow(QtGui.QMainWindow): self.logout.connect(self._mail_conductor.stop_mail_services) - # 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. - - # start event machines + # 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) -- cgit v1.2.3 From 8433b869c86fe6cc153ce410a1946d97d509b85f Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 10 Aug 2014 12:59:41 -0700 Subject: Clean up help dialog text. --- src/leap/bitmask/gui/mainwindow.py | 48 +++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 02488af1..3f74feb5 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1073,22 +1073,38 @@ class MainWindow(QtGui.QMainWindow): # TODO: don't hardcode! smtp_port = 2013 - url = ("bitmask addon") - - msg = self.tr( - "Instructions to use mail:
" - "If you use Thunderbird you can use the Bitmask extension helper. " - "Search for 'Bitmask' in the add-on manager or download it " - "from: {0}.

" - "You can configure Bitmask manually with these options:
" - "" - " Incoming -> IMAP, port: {1}
" - " Outgoing -> SMTP, port: {2}
" - " Username -> your bitmask username.
" - " Password -> does not matter, use any text. " - " Just don't leave it empty and don't use your account's password." - "
").format(url, IMAP_PORT, smtp_port) + help_url = "

{0}

".format( + self.tr("bitmask.net/help")) + + lang = QtCore.QLocale.system().name().replace('_','-') + thunderbird_extension_url = \ + "https://addons.mozilla.org/{0}/" \ + "thunderbird/addon/bitmask/".format(lang) + + email_quick_reference = self.tr("Email quick reference") + thunderbird_text = self.tr("For Thunderbird, you can use the " + "Bitmask extension. Search for \"Bitmask\" in the add-on " + "manager or download it from " + "addons.mozilla.org.".format(thunderbird_extension_url)) + manual_text = self.tr("Alternately, 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)) + manual_username = self.tr("Username: your full email address") + manual_password = self.tr("Password: any non-empty text") + + msg = help_url + self.tr( + "

{0}

" + "

{1}

" + "

{2}" + "

    " + "
  •  {3}
  • " + "
  •  {4}
  • " + "
  •  {5}
  • " + "
  •  {6}
  • " + "

").format(email_quick_reference, thunderbird_text, + manual_text, manual_imap, manual_smtp, + manual_username, manual_password) QtGui.QMessageBox.about(self, self.tr("Bitmask Help"), msg) def _needs_update(self): -- cgit v1.2.3 From a54a4bcd1aac5d42953f5f7f152080a391cbf643 Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 10 Aug 2014 13:06:37 -0700 Subject: remove "Hide Main Window" -- much better UX, less buggy, and makes it possible raise window when it is obscured. To hide, just close window. --- src/leap/bitmask/gui/mainwindow.py | 79 +++++++++++++------------------------- 1 file changed, 26 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 3f74feb5..c11cff9f 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -237,8 +237,8 @@ class MainWindow(QtGui.QMainWindow): 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("Hide Main Window"), self) - self._action_visible.triggered.connect(self._toggle_visible) + self._action_visible = QtGui.QAction(self.tr("Show Main Window"), self) + self._action_visible.triggered.connect(self._ensure_visible) # disable buttons for now, may come back later. # self.ui.btnPreferences.clicked.connect(self._show_preferences) @@ -957,8 +957,6 @@ class MainWindow(QtGui.QMainWindow): Display the context menu from the tray icon """ - self._update_hideshow_menu() - context_menu = self._systray.contextMenu() if not IS_MAC: # for some reason, context_menu.show() @@ -967,50 +965,38 @@ class MainWindow(QtGui.QMainWindow): # this works however. context_menu.exec_(self._systray.geometry().center()) - def _update_hideshow_menu(self): - """ - Update the Hide/Show main window menu text based on the - visibility of the window. + @QtCore.Slot() + def _ensure_visible(self): """ - get_action = lambda visible: ( - self.tr("Show Main Window"), - self.tr("Hide Main Window"))[int(visible)] + TRIGGERS: + self._action_visible.triggered - # set labels - visible = self.isVisible() and self.isActiveWindow() - self._action_visible.setText(get_action(visible)) + Ensure that the window is visible and raised. + """ + QtGui.QApplication.setQuitOnLastWindowClosed(True) + self.show() + if IS_LINUX: + # On ubuntu, activateWindow doesn't work reliably, so + # we do the following as a workaround. See + # https://bugreports.qt-project.org/browse/QTBUG-24932 + # for more details + QtGui.QX11Info.setAppUserTime(0) + self.activateWindow() + self.raise_() @QtCore.Slot() - def _toggle_visible(self): + def _ensure_invisible(self): """ TRIGGERS: self._action_visible.triggered - Toggle the window visibility + Ensure that the window is hidden. """ - visible = self.isVisible() and self.isActiveWindow() - - if not visible: - QtGui.QApplication.setQuitOnLastWindowClosed(True) - self.show() - if IS_LINUX: - # On ubuntu, activateWindow doesn't work reliably, so - # we do the following as a workaround. See - # https://bugreports.qt-project.org/browse/QTBUG-24932 - # for more details - QtGui.QX11Info.setAppUserTime(0) - self.activateWindow() - self.raise_() - else: - # We set this in order to avoid dialogs shutting down the - # app on close, as they will be the only visible window. - # e.g.: PreferencesWindow, LoggerWindow - QtGui.QApplication.setQuitOnLastWindowClosed(False) - self.hide() - - # Wait a bit until the window visibility has changed so - # the menu is set with the correct value. - QtDelayedCall(500, self._update_hideshow_menu) + # We set this in order to avoid dialogs shutting down the + # app on close, as they will be the only visible window. + # e.g.: PreferencesWindow, LoggerWindow + QtGui.QApplication.setQuitOnLastWindowClosed(False) + self.hide() def _center_window(self): """ @@ -1130,19 +1116,6 @@ class MainWindow(QtGui.QMainWindow): "Error: API version incompatible.") QtGui.QMessageBox.warning(self, self.tr("Incompatible Provider"), msg) - def changeEvent(self, e): - """ - Reimplementation of changeEvent method to minimize to tray - """ - if not IS_MAC and \ - QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ - e.type() == QtCore.QEvent.WindowStateChange and \ - self.isMinimized(): - self._toggle_visible() - e.accept() - return - QtGui.QMainWindow.changeEvent(self, e) - def closeEvent(self, e): """ Reimplementation of closeEvent to close to tray @@ -1155,7 +1128,7 @@ class MainWindow(QtGui.QMainWindow): if QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ not self._really_quit: - self._toggle_visible() + self._ensure_invisible() e.ignore() return -- cgit v1.2.3 From 047b4bce66532f43456eff7f2f1d847e2b746a6d Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 10 Aug 2014 13:44:59 -0700 Subject: properly align login and logout buttons --- src/leap/bitmask/gui/ui/login.ui | 60 +++++++++++++++++++------------ src/leap/bitmask/gui/ui/logout.ui | 74 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 22 deletions(-) create mode 100644 src/leap/bitmask/gui/ui/logout.ui (limited to 'src') diff --git a/src/leap/bitmask/gui/ui/login.ui b/src/leap/bitmask/gui/ui/login.ui index 216eca9e..cd20108e 100644 --- a/src/leap/bitmask/gui/ui/login.ui +++ b/src/leap/bitmask/gui/ui/login.ui @@ -33,7 +33,7 @@ 0 - -1 + 6 @@ -79,8 +79,14 @@
- + + + + 0 + 0 + + Log In @@ -198,26 +204,17 @@ - - - 0 - 0 - - - - - 0 - 0 - - - + 0 + + 26 + - 12 + 18 - + @@ -231,22 +228,41 @@ - + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 24 + 24 + + + + + Logout - - + + Qt::Horizontal + + QSizePolicy::Fixed + - 40 - 20 + 24 + 24 diff --git a/src/leap/bitmask/gui/ui/logout.ui b/src/leap/bitmask/gui/ui/logout.ui new file mode 100644 index 00000000..3faa93b6 --- /dev/null +++ b/src/leap/bitmask/gui/ui/logout.ui @@ -0,0 +1,74 @@ + + + Form + + + + 0 + 0 + 434 + 202 + + + + Form + + + + + + + 15 + 75 + true + + + + ... + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 24 + 24 + + + + + + + + Logout + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 24 + 24 + + + + + + + + + -- cgit v1.2.3 From 9b8251efe382f944e14a320e60e26a372a87d66b Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 10 Aug 2014 14:14:17 -0700 Subject: added non-functional decorative footer --- src/leap/bitmask/gui/ui/mainwindow.ui | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index 1eeb636f..5bd21484 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 524 - 640 + 600 @@ -216,6 +216,28 @@ + + + + + 0 + 0 + + + + false + + + background-color: rgba(0,0,0,20); border-top: 1px solid rgba(0,0,0,30); + + + + 0 + 16 + + + + -- cgit v1.2.3 From dddd670e8d9fde0772547453696c26c3d08fe5a1 Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 10 Aug 2014 15:07:24 -0700 Subject: simplify wizard instructions --- src/leap/bitmask/gui/ui/wizard.ui | 32 ++++++++++++++++---------------- src/leap/bitmask/gui/wizard.py | 15 ++++----------- 2 files changed, 20 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui index 8c52897d..e895dc5a 100644 --- a/src/leap/bitmask/gui/ui/wizard.ui +++ b/src/leap/bitmask/gui/ui/wizard.ui @@ -23,7 +23,7 @@ - Bitmask first run + Bitmask Provider Setup @@ -40,10 +40,10 @@ - Welcome + Welcome to Bitmask - This is the Bitmask first run wizard + 0 @@ -59,7 +59,7 @@ - <html><head/><body><p>Now we will guide you through some configuration that is needed before you can connect for the first time.</p><p>If you ever need to modify these options again, you can find the wizard in the <span style=" font-style:italic;">'Bitmask -&gt; Create new account...'</span> menu from the main window.</p><p>Do you want to <span style=" font-weight:600;">sign up</span> for a new account, or <span style=" font-weight:600;">log in</span> with an already existing username?</p></body></html> + Qt::RichText @@ -109,10 +109,10 @@ - Provider selection + Choose a provider - Please enter the domain of the provider you want to use for your connection + 1 @@ -156,7 +156,7 @@ - Getting provider information + Getting provider information. @@ -350,10 +350,10 @@ - Provider Information + About this provider - Description of services offered by this provider + 2 @@ -495,7 +495,7 @@ Provider setup - Gathering configuration options for this provider + 3 @@ -517,7 +517,7 @@ - We are downloading some bits that we need to establish a secure connection with the provider for the first time. + Bitmask is attempting to establish a secure connection with this provider for the first time. true @@ -590,21 +590,21 @@ - Getting info from the Certificate Authority + Fetching provider credentials. - Do we trust this Certificate Authority? + Do we trust these credentials? - Establishing a trust relationship with this provider + Connecting to provider. @@ -666,7 +666,7 @@ Register new user - Register a new user with provider + 4 @@ -791,7 +791,7 @@ Service selection - Please select the services you would like to have + 5 diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index be5bde52..e0b4b620 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -679,7 +679,7 @@ class Wizard(QtGui.QWizard): the user to enable or disable. """ self.ui.grpServices.setTitle( - self.tr("Services by {0}").format(self._provider_details['name'])) + self.tr("Services by {0}").format(self._provider_details['domain'])) services = get_supported(self._provider_details['services']) @@ -723,18 +723,11 @@ class Wizard(QtGui.QWizard): if pageId == self.SETUP_PROVIDER_PAGE: if not self._provider_setup_ok: self._reset_provider_setup() - sub_title = self.tr("Gathering configuration options for {0}") - sub_title = sub_title.format(self._provider_details['name']) - self.page(pageId).setSubTitle(sub_title) self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) self._provider_setup_defer = self._backend.\ provider_bootstrap(provider=self._domain) if pageId == self.PRESENT_PROVIDER_PAGE: - sub_title = self.tr("Description of services offered by {0}") - sub_title = sub_title.format(self._provider_details['name']) - self.page(pageId).setSubTitle(sub_title) - details = self._provider_details name = "{0}".format(details['name']) domain = "https://{0}".format(details['domain']) @@ -746,9 +739,9 @@ class Wizard(QtGui.QWizard): self.ui.lblProviderPolicy.setText(details['enrollment_policy']) if pageId == self.REGISTER_USER_PAGE: - sub_title = self.tr("Register a new user with {0}") - sub_title = sub_title.format(self._provider_details['name']) - self.page(pageId).setSubTitle(sub_title) + title = self.tr("Register a new user with {0}") + title = title.format(self._provider_details['domain']) + self.page(pageId).setTitle(title) self.ui.chkRemember.setVisible(False) if pageId == self.SERVICES_PAGE: -- cgit v1.2.3 From 7e48a36a681e89def5826f00e322c3c37b5dfe98 Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 10 Aug 2014 15:08:28 -0700 Subject: clean up icons in mainwindow.qrc --- src/leap/bitmask/gui/wizard.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index e0b4b620..175d744c 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -70,9 +70,9 @@ class Wizard(QtGui.QWizard): self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/images/mask-icon.png")) - self.QUESTION_ICON = QtGui.QPixmap(":/images/Emblem-question.png") - self.ERROR_ICON = QtGui.QPixmap(":/images/Dialog-error.png") - self.OK_ICON = QtGui.QPixmap(":/images/Dialog-accept.png") + self.QUESTION_ICON = QtGui.QPixmap(":/images/black/24/question.png") + self.ERROR_ICON = QtGui.QPixmap(":/images/black/24/off.png") + self.OK_ICON = QtGui.QPixmap(":/images/black/24/on.png") self._selected_services = set() self._shown_services = set() -- cgit v1.2.3 From 9dc94c0eb18a625e3a4a9e0126349ad7c21567c5 Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 10 Aug 2014 16:24:56 -0700 Subject: svg icons! well, how about that? --- src/leap/bitmask/gui/eip_status.py | 12 +++---- src/leap/bitmask/gui/mail_status.py | 12 +++---- src/leap/bitmask/gui/ui/eip_status.ui | 2 +- src/leap/bitmask/gui/ui/mail_status.ui | 2 +- src/leap/bitmask/gui/ui/wizard.ui | 66 ++++++++++++++++++++++++++++++---- src/leap/bitmask/gui/wizard.py | 6 ++-- 6 files changed, 77 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 1e764a8c..05e28f92 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -214,15 +214,15 @@ class EIPStatusWidget(QtGui.QWidget): WIN : light icons """ EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/black/32/wait.png", - ":/images/black/32/on.png", - ":/images/black/32/off.png") + ":/images/black/wait.svg", + ":/images/black/on.svg", + ":/images/black/off.svg") if IS_LINUX: EIP_ICONS_TRAY = ( - ":/images/white/32/wait.png", - ":/images/white/32/on.png", - ":/images/white/32/off.png") + ":/images/white/wait.svg", + ":/images/white/on.svg", + ":/images/white/off.svg") self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index bb755b5c..4ec93d88 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -134,15 +134,15 @@ class MailStatusWidget(QtGui.QWidget): WIN : light icons """ EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/black/32/wait.png", - ":/images/black/32/on.png", - ":/images/black/32/off.png") + ":/images/black/wait.svg", + ":/images/black/on.svg", + ":/images/black/off.svg") if IS_LINUX: EIP_ICONS_TRAY = ( - ":/images/white/32/wait.png", - ":/images/white/32/on.png", - ":/images/white/32/off.png") + ":/images/white/wait.svg", + ":/images/white/on.svg", + ":/images/white/off.svg") self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui index e0996620..e97add61 100644 --- a/src/leap/bitmask/gui/ui/eip_status.ui +++ b/src/leap/bitmask/gui/ui/eip_status.ui @@ -111,7 +111,7 @@ - :/images/black/32/off.png + :/images/black/off.svg true diff --git a/src/leap/bitmask/gui/ui/mail_status.ui b/src/leap/bitmask/gui/ui/mail_status.ui index 22976f39..6103c77b 100644 --- a/src/leap/bitmask/gui/ui/mail_status.ui +++ b/src/leap/bitmask/gui/ui/mail_status.ui @@ -60,7 +60,7 @@ - :/images/black/32/off.png + :/images/black/off.svg true diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui index e895dc5a..f67e9dd5 100644 --- a/src/leap/bitmask/gui/ui/wizard.ui +++ b/src/leap/bitmask/gui/ui/wizard.ui @@ -181,11 +181,20 @@ 24 + + + 24 + 24 + + + + true + - :/images/Emblem-question.png + :/images/black/question.svg @@ -203,11 +212,20 @@ 24 + + + 24 + 24 + + + + true + - :/images/Emblem-question.png + :/images/black/question.svg @@ -225,11 +243,20 @@ 24 + + + 24 + 24 + + + + true + - :/images/Emblem-question.png + :/images/black/question.svg @@ -557,11 +584,20 @@ 24 + + + 24 + 24 + + + + true + - :/images/Emblem-question.png + :/images/black/question.svg @@ -579,11 +615,20 @@ 24 + + + 24 + 24 + + + + true + - :/images/Emblem-question.png + :/images/black/question.svg
@@ -622,11 +667,20 @@ 24 + + + 24 + 24 + + + + true + - :/images/Emblem-question.png + :/images/black/question.svg
diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 175d744c..44f91365 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -70,9 +70,9 @@ class Wizard(QtGui.QWizard): self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/images/mask-icon.png")) - self.QUESTION_ICON = QtGui.QPixmap(":/images/black/24/question.png") - self.ERROR_ICON = QtGui.QPixmap(":/images/black/24/off.png") - self.OK_ICON = QtGui.QPixmap(":/images/black/24/on.png") + self.QUESTION_ICON = QtGui.QPixmap(":/images/black/question.svg") + self.ERROR_ICON = QtGui.QPixmap(":/images/black/off.svg") + self.OK_ICON = QtGui.QPixmap(":/images/black/on.svg") self._selected_services = set() self._shown_services = set() -- cgit v1.2.3 From ff4f8e1b1b0cbe48e8d94fed5128acc60be9bf1a Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Sat, 9 Aug 2014 15:39:37 -0500 Subject: Wait until EIP is up to autologin. Closes #5939. --- src/leap/bitmask/gui/mainwindow.py | 51 +++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 389ff172..990ea643 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1165,12 +1165,14 @@ class MainWindow(QtGui.QMainWindow): skip_first_run = self._settings.get_skip_first_run() return not (has_provider_on_disk and skip_first_run) + @QtCore.Slot() def _download_provider_config(self): """ Start the bootstrapping sequence. It will download the provider configuration if it's not present, otherwise will emit the corresponding signals inmediately """ + self._disconnect_scheduled_login() domain = self._login_widget.get_selected_provider() self._backend.provider_setup(provider=domain) @@ -1204,6 +1206,40 @@ class MainWindow(QtGui.QMainWindow): self.tr("Unable to login: Problem with provider")) self._login_widget.set_enabled(True) + def _schedule_login(self): + """ + Schedule the login sequence to go after the EIP started. + + The login sequence is connected to all finishing status of EIP + (connected, disconnected, aborted or died) to continue with the login + after EIP. + """ + logger.debug('Login scheduled when eip_connected is triggered') + eip_sigs = self._eip_conductor.qtsigs + eip_sigs.connected_signal.connect(self._download_provider_config) + eip_sigs.disconnected_signal.connect(self._download_provider_config) + eip_sigs.connection_aborted_signal.connect(self._download_provider_config) + eip_sigs.connection_died_signal.connect(self._download_provider_config) + + def _disconnect_scheduled_login(self): + """ + Disconnect scheduled login signals if exists + """ + try: + eip_sigs = self._eip_conductor.qtsigs + eip_sigs.connected_signal.disconnect( + self._download_provider_config) + eip_sigs.disconnected_signal.disconnect( + self._download_provider_config) + eip_sigs.connection_aborted_signal.disconnect( + self._download_provider_config) + eip_sigs.connection_died_signal.disconnect( + self._download_provider_config) + except Exception: + # signal not connected + pass + + @QtCore.Slot() def _login(self): """ @@ -1229,7 +1265,10 @@ class MainWindow(QtGui.QMainWindow): else: self.ui.action_create_new_account.setEnabled(False) if self._login_widget.start_login(): - self._download_provider_config() + if self._trying_to_start_eip: + self._schedule_login() + else: + self._download_provider_config() @QtCore.Slot(unicode) def _authentication_error(self, msg): @@ -1258,8 +1297,13 @@ class MainWindow(QtGui.QMainWindow): Stop the login sequence. """ logger.debug("Cancelling log in.") + self._disconnect_scheduled_login() + self._cancel_ongoing_defers() + # Needed in case of EIP starting and login deferer never set + self._set_login_cancelled() + def _cancel_ongoing_defers(self): """ Cancel the running defers to avoid app blocking. @@ -1673,8 +1717,9 @@ class MainWindow(QtGui.QMainWindow): """ passed = data[PASSED_KEY] if not passed: - self._login_widget.set_status( - self.tr("Unable to connect: Problem with provider")) + self._eip_status.set_eip_status( + self.tr("Unable to connect: Problem with provider"), + error=True) logger.error(data[ERROR_KEY]) self._already_started_eip = False self._eip_status.aborted() -- cgit v1.2.3 From c52ca1aa1e9637d3e7d18f30b7c476ab1b1fe13a Mon Sep 17 00:00:00 2001 From: elijah Date: Mon, 11 Aug 2014 13:08:43 -0700 Subject: temporarily switch back to using png icons --- src/leap/bitmask/gui/eip_status.py | 12 ++++++------ src/leap/bitmask/gui/mail_status.py | 12 ++++++------ src/leap/bitmask/gui/ui/eip_status.ui | 2 +- src/leap/bitmask/gui/ui/mail_status.ui | 2 +- src/leap/bitmask/gui/ui/wizard.ui | 12 ++++++------ src/leap/bitmask/gui/wizard.py | 6 +++--- 6 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 05e28f92..836f984a 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -214,15 +214,15 @@ class EIPStatusWidget(QtGui.QWidget): WIN : light icons """ EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/black/wait.svg", - ":/images/black/on.svg", - ":/images/black/off.svg") + ":/images/black/24/wait.png", + ":/images/black/24/on.png", + ":/images/black/24/off.png") if IS_LINUX: EIP_ICONS_TRAY = ( - ":/images/white/wait.svg", - ":/images/white/on.svg", - ":/images/white/off.svg") + ":/images/white/24/wait.png", + ":/images/white/24/on.png", + ":/images/white/24/off.png") self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index 4ec93d88..831c6788 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -134,15 +134,15 @@ class MailStatusWidget(QtGui.QWidget): WIN : light icons """ EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/black/wait.svg", - ":/images/black/on.svg", - ":/images/black/off.svg") + ":/images/black/24/wait.png", + ":/images/black/24/on.png", + ":/images/black/24/off.png") if IS_LINUX: EIP_ICONS_TRAY = ( - ":/images/white/wait.svg", - ":/images/white/on.svg", - ":/images/white/off.svg") + ":/images/white/24/wait.png", + ":/images/white/24/on.png", + ":/images/white/24/off.png") self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui index e97add61..adbd8964 100644 --- a/src/leap/bitmask/gui/ui/eip_status.ui +++ b/src/leap/bitmask/gui/ui/eip_status.ui @@ -111,7 +111,7 @@ - :/images/black/off.svg + :/images/black/24/off.png true diff --git a/src/leap/bitmask/gui/ui/mail_status.ui b/src/leap/bitmask/gui/ui/mail_status.ui index 6103c77b..64b8ba8c 100644 --- a/src/leap/bitmask/gui/ui/mail_status.ui +++ b/src/leap/bitmask/gui/ui/mail_status.ui @@ -60,7 +60,7 @@ - :/images/black/off.svg + :/images/black/24/off.png true diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui index f67e9dd5..5473310b 100644 --- a/src/leap/bitmask/gui/ui/wizard.ui +++ b/src/leap/bitmask/gui/ui/wizard.ui @@ -194,7 +194,7 @@ - :/images/black/question.svg + :/images/black/24/question.png @@ -225,7 +225,7 @@ - :/images/black/question.svg + :/images/black/24/question.png @@ -256,7 +256,7 @@ - :/images/black/question.svg + :/images/black/24/question.png @@ -597,7 +597,7 @@ - :/images/black/question.svg + :/images/black/24/question.png @@ -628,7 +628,7 @@ - :/images/black/question.svg + :/images/black/24/question.png @@ -680,7 +680,7 @@ - :/images/black/question.svg + :/images/black/24/question.png diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 44f91365..175d744c 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -70,9 +70,9 @@ class Wizard(QtGui.QWizard): self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/images/mask-icon.png")) - self.QUESTION_ICON = QtGui.QPixmap(":/images/black/question.svg") - self.ERROR_ICON = QtGui.QPixmap(":/images/black/off.svg") - self.OK_ICON = QtGui.QPixmap(":/images/black/on.svg") + self.QUESTION_ICON = QtGui.QPixmap(":/images/black/24/question.png") + self.ERROR_ICON = QtGui.QPixmap(":/images/black/24/off.png") + self.OK_ICON = QtGui.QPixmap(":/images/black/24/on.png") self._selected_services = set() self._shown_services = set() -- cgit v1.2.3 From 6771ba8958d385509f7cc55acab13fe14873e0c2 Mon Sep 17 00:00:00 2001 From: elijah Date: Mon, 11 Aug 2014 15:35:33 -0700 Subject: used 22x22 pixel icons instead of 24x24 pixel icons (since ubuntu needs 22 anyway) --- src/leap/bitmask/gui/eip_status.py | 12 ++-- src/leap/bitmask/gui/mail_status.py | 12 ++-- src/leap/bitmask/gui/ui/advanced_key_management.ui | 4 +- src/leap/bitmask/gui/ui/eip_status.ui | 13 ++--- src/leap/bitmask/gui/ui/eippreferences.ui | 4 +- src/leap/bitmask/gui/ui/loggerwindow.ui | 4 +- src/leap/bitmask/gui/ui/login.ui | 6 +- src/leap/bitmask/gui/ui/mail_status.ui | 6 +- src/leap/bitmask/gui/ui/mainwindow.ui | 4 +- src/leap/bitmask/gui/ui/preferences.ui | 4 +- src/leap/bitmask/gui/ui/wizard.ui | 64 +++++++++++----------- src/leap/bitmask/gui/wizard.py | 6 +- 12 files changed, 69 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 836f984a..1b0e5b92 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -214,15 +214,15 @@ class EIPStatusWidget(QtGui.QWidget): WIN : light icons """ EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/black/24/wait.png", - ":/images/black/24/on.png", - ":/images/black/24/off.png") + ":/images/black/22/wait.png", + ":/images/black/22/on.png", + ":/images/black/22/off.png") if IS_LINUX: EIP_ICONS_TRAY = ( - ":/images/white/24/wait.png", - ":/images/white/24/on.png", - ":/images/white/24/off.png") + ":/images/white/22/wait.png", + ":/images/white/22/on.png", + ":/images/white/22/off.png") self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index 831c6788..d523f449 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -134,15 +134,15 @@ class MailStatusWidget(QtGui.QWidget): WIN : light icons """ EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/black/24/wait.png", - ":/images/black/24/on.png", - ":/images/black/24/off.png") + ":/images/black/22/wait.png", + ":/images/black/22/on.png", + ":/images/black/22/off.png") if IS_LINUX: EIP_ICONS_TRAY = ( - ":/images/white/24/wait.png", - ":/images/white/24/on.png", - ":/images/white/24/off.png") + ":/images/white/22/wait.png", + ":/images/white/22/on.png", + ":/images/white/22/off.png") self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) diff --git a/src/leap/bitmask/gui/ui/advanced_key_management.ui b/src/leap/bitmask/gui/ui/advanced_key_management.ui index 3b567347..72f70d24 100644 --- a/src/leap/bitmask/gui/ui/advanced_key_management.ui +++ b/src/leap/bitmask/gui/ui/advanced_key_management.ui @@ -14,7 +14,7 @@ Advanced Key Management - + :/images/mask-icon.png:/images/mask-icon.png @@ -184,7 +184,7 @@ - + diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui index adbd8964..4aaa682a 100644 --- a/src/leap/bitmask/gui/ui/eip_status.ui +++ b/src/leap/bitmask/gui/ui/eip_status.ui @@ -60,7 +60,7 @@ - :/images/black/32/earth.png + :/images/black/32/earth.png @@ -103,15 +103,15 @@ - 24 - 24 + 22 + 22 - :/images/black/24/off.png + :/images/black/22/off.png true @@ -162,7 +162,7 @@ 0.0 KB/s - + :/images/black/32/arrow-down.png:/images/black/32/arrow-down.png @@ -213,7 +213,7 @@ 0.0 KB/s - + :/images/black/32/arrow-up.png:/images/black/32/arrow-up.png @@ -265,7 +265,6 @@ - diff --git a/src/leap/bitmask/gui/ui/eippreferences.ui b/src/leap/bitmask/gui/ui/eippreferences.ui index a3050683..1a5fcd24 100644 --- a/src/leap/bitmask/gui/ui/eippreferences.ui +++ b/src/leap/bitmask/gui/ui/eippreferences.ui @@ -14,7 +14,7 @@ Encrypted Internet Preferences - + :/images/mask-icon.png:/images/mask-icon.png @@ -96,7 +96,7 @@ pbSaveGateway - + diff --git a/src/leap/bitmask/gui/ui/loggerwindow.ui b/src/leap/bitmask/gui/ui/loggerwindow.ui index b19ed91a..fd8644c9 100644 --- a/src/leap/bitmask/gui/ui/loggerwindow.ui +++ b/src/leap/bitmask/gui/ui/loggerwindow.ui @@ -14,7 +14,7 @@ Logs - + :/images/mask-icon.png:/images/mask-icon.png @@ -180,7 +180,7 @@ - + diff --git a/src/leap/bitmask/gui/ui/login.ui b/src/leap/bitmask/gui/ui/login.ui index cd20108e..26decc6d 100644 --- a/src/leap/bitmask/gui/ui/login.ui +++ b/src/leap/bitmask/gui/ui/login.ui @@ -170,7 +170,7 @@ - :/images/black/32/user.png + :/images/black/32/user.png false @@ -209,7 +209,7 @@ 0 - 26 + 25 18 @@ -299,7 +299,7 @@ chkRemember - + diff --git a/src/leap/bitmask/gui/ui/mail_status.ui b/src/leap/bitmask/gui/ui/mail_status.ui index 64b8ba8c..6fd63aec 100644 --- a/src/leap/bitmask/gui/ui/mail_status.ui +++ b/src/leap/bitmask/gui/ui/mail_status.ui @@ -60,7 +60,7 @@ - :/images/black/24/off.png + :/images/black/22/off.png true @@ -104,14 +104,14 @@ - :/images/black/32/email.png + :/images/black/32/email.png - + diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index 5bd21484..5dc48f29 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -32,7 +32,7 @@ Bitmask - + :/images/mask-icon.png:/images/mask-icon.png @@ -399,7 +399,7 @@ - + diff --git a/src/leap/bitmask/gui/ui/preferences.ui b/src/leap/bitmask/gui/ui/preferences.ui index e187c016..cd4d3a77 100644 --- a/src/leap/bitmask/gui/ui/preferences.ui +++ b/src/leap/bitmask/gui/ui/preferences.ui @@ -14,7 +14,7 @@ Preferences - + :/images/mask-icon.png:/images/mask-icon.png @@ -174,7 +174,7 @@ - + diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui index 5473310b..0e28ecbf 100644 --- a/src/leap/bitmask/gui/ui/wizard.ui +++ b/src/leap/bitmask/gui/ui/wizard.ui @@ -26,7 +26,7 @@ Bitmask Provider Setup - + :/images/mask-icon.png:/images/mask-icon.png @@ -177,14 +177,14 @@ - 24 - 24 + 22 + 22 - 24 - 24 + 22 + 22 @@ -194,7 +194,7 @@ - :/images/black/24/question.png + :/images/black/22/question.png @@ -208,14 +208,14 @@ - 24 - 24 + 22 + 22 - 24 - 24 + 22 + 22 @@ -225,7 +225,7 @@ - :/images/black/24/question.png + :/images/black/22/question.png @@ -239,14 +239,14 @@ - 24 - 24 + 22 + 22 - 24 - 24 + 22 + 22 @@ -256,7 +256,7 @@ - :/images/black/24/question.png + :/images/black/22/question.png @@ -580,14 +580,14 @@ - 24 - 24 + 22 + 22 - 24 - 24 + 22 + 22 @@ -597,7 +597,7 @@ - :/images/black/24/question.png + :/images/black/22/question.png @@ -611,14 +611,14 @@ - 24 - 24 + 22 + 22 - 24 - 24 + 22 + 22 @@ -628,7 +628,7 @@ - :/images/black/24/question.png + :/images/black/22/question.png @@ -663,14 +663,14 @@ - 24 - 24 + 22 + 22 - 24 - 24 + 22 + 22 @@ -680,7 +680,7 @@ - :/images/black/24/question.png + :/images/black/22/question.png @@ -883,7 +883,7 @@ rdoLogin - + diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index 175d744c..0223c053 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -70,9 +70,9 @@ class Wizard(QtGui.QWizard): self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/images/mask-icon.png")) - self.QUESTION_ICON = QtGui.QPixmap(":/images/black/24/question.png") - self.ERROR_ICON = QtGui.QPixmap(":/images/black/24/off.png") - self.OK_ICON = QtGui.QPixmap(":/images/black/24/on.png") + self.QUESTION_ICON = QtGui.QPixmap(":/images/black/22/question.png") + self.ERROR_ICON = QtGui.QPixmap(":/images/black/22/off.png") + self.OK_ICON = QtGui.QPixmap(":/images/black/22/on.png") self._selected_services = set() self._shown_services = set() -- cgit v1.2.3 From 3274c7c52f5afb1481197686c0d2961a605aae8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Mon, 11 Aug 2014 20:19:53 -0300 Subject: We do not have eipstatus.qrc anymore --- src/leap/bitmask/gui/eip_status.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 1b0e5b92..abd6e2c9 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -793,6 +793,3 @@ class EIPStatusWidget(QtGui.QWidget): """ self.set_eip_status("", error=error) self.set_eip_status_icon("error") - -import eipstatus_rc -assert(eipstatus_rc) -- cgit v1.2.3 From 769f334a3a424612b454061f4dc3937e3e46071f Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 11 Aug 2014 17:35:36 -0300 Subject: Do some pep8 fixes. --- src/leap/bitmask/gui/mainwindow.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 0518350e..c6fd12e1 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -1062,17 +1062,19 @@ class MainWindow(QtGui.QMainWindow): help_url = "

{0}

".format( self.tr("bitmask.net/help")) - lang = QtCore.QLocale.system().name().replace('_','-') + lang = QtCore.QLocale.system().name().replace('_', '-') thunderbird_extension_url = \ "https://addons.mozilla.org/{0}/" \ "thunderbird/addon/bitmask/".format(lang) email_quick_reference = self.tr("Email quick reference") - thunderbird_text = self.tr("For Thunderbird, you can use the " + thunderbird_text = self.tr( + "For Thunderbird, you can use the " "Bitmask extension. Search for \"Bitmask\" in the add-on " "manager or download it from " "addons.mozilla.org.".format(thunderbird_extension_url)) - manual_text = self.tr("Alternately, you can manually configure " + manual_text = self.tr( + "Alternately, 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)) @@ -1089,8 +1091,8 @@ class MainWindow(QtGui.QMainWindow): "
  •  {5}
  • " "
  •  {6}
  • " "

    ").format(email_quick_reference, thunderbird_text, - manual_text, manual_imap, manual_smtp, - manual_username, manual_password) + manual_text, manual_imap, manual_smtp, + manual_username, manual_password) QtGui.QMessageBox.about(self, self.tr("Bitmask Help"), msg) def _needs_update(self): @@ -1201,7 +1203,8 @@ class MainWindow(QtGui.QMainWindow): eip_sigs = self._eip_conductor.qtsigs eip_sigs.connected_signal.connect(self._download_provider_config) eip_sigs.disconnected_signal.connect(self._download_provider_config) - eip_sigs.connection_aborted_signal.connect(self._download_provider_config) + eip_sigs.connection_aborted_signal.connect( + self._download_provider_config) eip_sigs.connection_died_signal.connect(self._download_provider_config) def _disconnect_scheduled_login(self): @@ -1211,18 +1214,17 @@ class MainWindow(QtGui.QMainWindow): try: eip_sigs = self._eip_conductor.qtsigs eip_sigs.connected_signal.disconnect( - self._download_provider_config) + self._download_provider_config) eip_sigs.disconnected_signal.disconnect( - self._download_provider_config) + self._download_provider_config) eip_sigs.connection_aborted_signal.disconnect( - self._download_provider_config) + self._download_provider_config) eip_sigs.connection_died_signal.disconnect( - self._download_provider_config) + self._download_provider_config) except Exception: # signal not connected pass - @QtCore.Slot() def _login(self): """ -- cgit v1.2.3 From 516c732fc603a8d26d30110f4fbab1e991006010 Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 12 Aug 2014 14:31:33 -0700 Subject: fix missing country flags --- src/leap/bitmask/gui/ui/eip_status.ui | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui index 4aaa682a..0fb861bc 100644 --- a/src/leap/bitmask/gui/ui/eip_status.ui +++ b/src/leap/bitmask/gui/ui/eip_status.ui @@ -266,6 +266,7 @@ + -- cgit v1.2.3 From 1d8fd48517a44f81d816eba2488e23fe3080f83b Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 11 Aug 2014 15:48:54 -0300 Subject: Stop the services if the selected provider is changed. Store the last 2 indexes on a deque and improve the 'select previous provider' action. --- src/leap/bitmask/gui/login.py | 46 +++++++++++++++++++--------- src/leap/bitmask/gui/mainwindow.py | 62 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py index 8e0a3a15..0e64bbcf 100644 --- a/src/leap/bitmask/gui/login.py +++ b/src/leap/bitmask/gui/login.py @@ -19,6 +19,8 @@ Login widget implementation """ import logging +from collections import deque + from PySide import QtCore, QtGui from ui_login import Ui_LoginWidget @@ -43,9 +45,10 @@ class LoginWidget(QtGui.QWidget): cancel_login = QtCore.Signal() logout = QtCore.Signal() - # Emitted when the user selects "Other..." in the provider - # combobox or click "Create Account" - show_wizard = QtCore.Signal() + # Emitted when the user changes the provider combobox index. The object + # parameter is actually a boolean value that is True if "Other..." was + # selected, False otherwse + provider_changed = QtCore.Signal(object) MAX_STATUS_WIDTH = 40 @@ -64,7 +67,9 @@ class LoginWidget(QtGui.QWidget): QtGui.QWidget.__init__(self, parent) self._settings = settings - self._selected_provider_index = -1 + + self._providers_indexes = deque(maxlen=2) # previous and current + self._providers_indexes.append(-1) self.ui = Ui_LoginWidget() self.ui.setupUi(self) @@ -132,7 +137,14 @@ class LoginWidget(QtGui.QWidget): :type name: str """ provider_index = self.ui.cmbProviders.findText(name) + self._providers_indexes.append(provider_index) + + # block the signals during a combobox change since we don't want to + # trigger the default signal that makes the UI ask the user for + # confirmation + self.ui.cmbProviders.blockSignals(True) self.ui.cmbProviders.setCurrentIndex(provider_index) + self.ui.cmbProviders.blockSignals(False) def get_selected_provider(self): """ @@ -267,17 +279,21 @@ class LoginWidget(QtGui.QWidget): :param idx: the index of the new selected item :type idx: int """ - if idx == (self.ui.cmbProviders.count() - 1): - self.show_wizard.emit() - # Leave the previously selected provider in the combobox - prev_provider = 0 - if self._selected_provider_index != -1: - prev_provider = self._selected_provider_index - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.setCurrentIndex(prev_provider) - self.ui.cmbProviders.blockSignals(False) - else: - self._selected_provider_index = idx + self._providers_indexes.append(idx) + is_wizard = idx == (self.ui.cmbProviders.count() - 1) + self.provider_changed.emit(is_wizard) + if is_wizard: + self.restore_previous_provider() + + def restore_previous_provider(self): + """ + Set as selected provider the one that was selected previously. + """ + prev_provider = self._providers_indexes.popleft() + self._providers_indexes.append(prev_provider) + self.ui.cmbProviders.blockSignals(True) + self.ui.cmbProviders.setCurrentIndex(prev_provider) + self.ui.cmbProviders.blockSignals(False) def start_login(self): """ diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index c6fd12e1..a85cb657 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -153,8 +153,8 @@ 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._login_widget.logout.connect(self._logout) + self._login_widget.provider_changed.connect(self._on_provider_changed) # EIP Control redux ######################################### self._eip_conductor = eip_conductor.EIPConductor( @@ -174,6 +174,8 @@ class MainWindow(QtGui.QMainWindow): self._eip_conductor.connect_signals() 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) @@ -187,7 +189,6 @@ class MainWindow(QtGui.QMainWindow): self._already_started_eip = False self._trying_to_start_eip = False - self._already_started_eip = False self._soledad_started = False # This is created once we have a valid provider config @@ -502,7 +503,6 @@ class MainWindow(QtGui.QMainWindow): def _launch_wizard(self): """ TRIGGERS: - self._login_widget.show_wizard self.ui.action_wizard.triggered Also called in first run. @@ -1225,6 +1225,52 @@ class MainWindow(QtGui.QMainWindow): # signal not connected pass + @QtCore.Slot(object) + def _on_provider_changed(self, wizard): + """ + TRIGGERS: + self._login.provider_changed + + Ask the user if really wants to change provider since a services stop + is required for that action. + + :param wizard: whether the 'other...' option was picked or not. + :type wizard: bool + """ + # 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._logged_user is not None or + self._already_started_eip) + if not something_runing: + if wizard: + self._launch_wizard() + return + + title = self.tr("Stop services") + text = self.tr("Do you want to stop all services?") + informative_text = self.tr("In order to change the provider, the " + "running services needs to be stopped.") + + msg = QtGui.QMessageBox(self) + msg.setWindowTitle(title) + msg.setText(text) + msg.setInformativeText(informative_text) + msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + msg.setDefaultButton(QtGui.QMessageBox.No) + msg.setIcon(QtGui.QMessageBox.Warning) + res = msg.exec_() + + if res == QtGui.QMessageBox.Yes: + self._stop_services() + self._eip_conductor.qtsigs.do_disconnect_signal.emit() + if wizard: + self._launch_wizard() + else: + if not wizard: + # if wizard, the widget restores itself + self._login_widget.restore_previous_provider() + @QtCore.Slot() def _login(self): """ @@ -1563,6 +1609,16 @@ class MainWindow(QtGui.QMainWindow): # check for connectivity self._backend.eip_check_dns(domain=domain) + @QtCore.Slot() + def _on_eip_connection_disconnected(self): + """ + TRIGGERS: + self._eip_conductor.qtsigs.disconnected_signal + + Set the eip status to not started. + """ + self._already_started_eip = False + @QtCore.Slot() def _set_eip_provider(self, country_code=None): """ -- cgit v1.2.3 From dd2097d27efc32820a25faff9236d091372f7930 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 12 Aug 2014 17:12:11 -0300 Subject: Ask for services stop when the wizard is needed. --- src/leap/bitmask/gui/mainwindow.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index a85cb657..03f91996 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -215,8 +215,9 @@ class MainWindow(QtGui.QMainWindow): self.ui.action_wizard.triggered.connect(self._launch_wizard) self.ui.action_show_logs.triggered.connect(self._show_logger_window) self.ui.action_help.triggered.connect(self._help) + self.ui.action_create_new_account.triggered.connect( - self._launch_wizard) + self._on_provider_changed) self.ui.action_advanced_key_management.triggered.connect( self._show_AKM) @@ -1226,10 +1227,11 @@ class MainWindow(QtGui.QMainWindow): pass @QtCore.Slot(object) - def _on_provider_changed(self, wizard): + def _on_provider_changed(self, wizard=True): """ TRIGGERS: self._login.provider_changed + self.ui.action_create_new_account.triggered Ask the user if really wants to change provider since a services stop is required for that action. @@ -1251,6 +1253,9 @@ class MainWindow(QtGui.QMainWindow): text = self.tr("Do you want to stop all services?") informative_text = self.tr("In order to change the provider, the " "running services needs to be stopped.") + if wizard: + informative_text = self.tr("In order to start the wizard, the " + "running services needs to be stopped.") msg = QtGui.QMessageBox(self) msg.setWindowTitle(title) -- cgit v1.2.3 From e35b7f006b6cb076ff6b982a2f173ab5bc3a41d3 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 13 Aug 2014 17:14:10 -0300 Subject: Use same user/password restrictions as in the webapp. - no uppercase allowed in usernames, - password length min to 8 Closes #5894. --- src/leap/bitmask/util/credentials.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/util/credentials.py b/src/leap/bitmask/util/credentials.py index 07ded17b..757ce10c 100644 --- a/src/leap/bitmask/util/credentials.py +++ b/src/leap/bitmask/util/credentials.py @@ -21,7 +21,7 @@ Credentials utilities from PySide import QtCore, QtGui WEAK_PASSWORDS = ("123456", "qweasd", "qwerty", "password") -USERNAME_REGEX = r"^[A-Za-z][A-Za-z\d_\-\.]+[A-Za-z\d]$" +USERNAME_REGEX = r"^[a-z][a-z\d_\-\.]+[a-z\d]$" USERNAME_VALIDATOR = QtGui.QRegExpValidator(QtCore.QRegExp(USERNAME_REGEX)) @@ -69,7 +69,7 @@ def password_checks(username, password, password2): if message is None and not password: message = _tr("You can't use an empty password") - if message is None and len(password) < 6: + if message is None and len(password) < 8: message = _tr("Password too short") if message is None and password in WEAK_PASSWORDS: -- cgit v1.2.3 From 919f29542ff7f2efd9cdd6232fee0eb395fa4f9c Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Aug 2014 13:23:58 -0300 Subject: Default to No if ESC pressed on 'install helper files'. Closes #5819. --- src/leap/bitmask/platform_init/initializers.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py index e4d6f9b3..f56b9330 100644 --- a/src/leap/bitmask/platform_init/initializers.py +++ b/src/leap/bitmask/platform_init/initializers.py @@ -106,6 +106,7 @@ def get_missing_helpers_dialog(): msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) msg.addButton("No, don't ask again", QtGui.QMessageBox.RejectRole) msg.setDefaultButton(QtGui.QMessageBox.Yes) + msg.setEscapeButton(QtGui.QMessageBox.No) return msg -- cgit v1.2.3 From 9a7df988191e2cdeb2e01fb30da55a0c5f4651f9 Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 13 Aug 2014 16:20:49 -0700 Subject: moved provider selection popup menu to be at the top of the main window --- src/leap/bitmask/gui/login.py | 91 +++------------------------ src/leap/bitmask/gui/mainwindow.py | 76 +++++++++++------------ src/leap/bitmask/gui/providers.py | 114 ++++++++++++++++++++++++++++++++++ src/leap/bitmask/gui/ui/login.ui | 25 ++------ src/leap/bitmask/gui/ui/mainwindow.ui | 39 ++++-------- 5 files changed, 177 insertions(+), 168 deletions(-) create mode 100644 src/leap/bitmask/gui/providers.py (limited to 'src') diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py index 0e64bbcf..2a79fafd 100644 --- a/src/leap/bitmask/gui/login.py +++ b/src/leap/bitmask/gui/login.py @@ -19,8 +19,6 @@ Login widget implementation """ import logging -from collections import deque - from PySide import QtCore, QtGui from ui_login import Ui_LoginWidget @@ -45,11 +43,6 @@ class LoginWidget(QtGui.QWidget): cancel_login = QtCore.Signal() logout = QtCore.Signal() - # Emitted when the user changes the provider combobox index. The object - # parameter is actually a boolean value that is True if "Other..." was - # selected, False otherwse - provider_changed = QtCore.Signal(object) - MAX_STATUS_WIDTH = 40 # Keyring @@ -68,9 +61,6 @@ class LoginWidget(QtGui.QWidget): self._settings = settings - self._providers_indexes = deque(maxlen=2) # previous and current - self._providers_indexes.append(-1) - self.ui = Ui_LoginWidget() self.ui.setupUi(self) @@ -85,9 +75,6 @@ class LoginWidget(QtGui.QWidget): self.ui.lnUser.returnPressed.connect(self._focus_password) - self.ui.cmbProviders.currentIndexChanged.connect( - self._current_provider_changed) - self.ui.btnLogout.clicked.connect( self.logout) @@ -116,42 +103,6 @@ class LoginWidget(QtGui.QWidget): enable = True if state == QtCore.Qt.Checked else False self._settings.set_remember(enable) - def set_providers(self, provider_list): - """ - Set the provider list to provider_list plus an "Other..." item - that triggers the wizard - - :param provider_list: list of providers - :type provider_list: list of str - """ - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.clear() - self.ui.cmbProviders.addItems(provider_list + [self.tr("Other...")]) - self.ui.cmbProviders.blockSignals(False) - - def select_provider_by_name(self, name): - """ - Given a provider name/domain, it selects it in the combobox - - :param name: name or domain for the provider - :type name: str - """ - provider_index = self.ui.cmbProviders.findText(name) - self._providers_indexes.append(provider_index) - - # block the signals during a combobox change since we don't want to - # trigger the default signal that makes the UI ask the user for - # confirmation - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.setCurrentIndex(provider_index) - self.ui.cmbProviders.blockSignals(False) - - def get_selected_provider(self): - """ - Returns the selected provider in the combobox - """ - return self.ui.cmbProviders.currentText() - def set_remember(self, value): """ Checks the remember user and password checkbox @@ -229,7 +180,6 @@ class LoginWidget(QtGui.QWidget): self.ui.lnUser.setEnabled(enabled) self.ui.lnPassword.setEnabled(enabled) self.ui.chkRemember.setEnabled(enabled and has_keyring()) - self.ui.cmbProviders.setEnabled(enabled) self._set_cancel(not enabled) @@ -270,45 +220,20 @@ class LoginWidget(QtGui.QWidget): """ self.ui.lnPassword.setFocus() - @QtCore.Slot(int) - def _current_provider_changed(self, idx): - """ - TRIGGERS: - self.ui.cmbProviders.currentIndexChanged - - :param idx: the index of the new selected item - :type idx: int - """ - self._providers_indexes.append(idx) - is_wizard = idx == (self.ui.cmbProviders.count() - 1) - self.provider_changed.emit(is_wizard) - if is_wizard: - self.restore_previous_provider() - - def restore_previous_provider(self): - """ - Set as selected provider the one that was selected previously. - """ - prev_provider = self._providers_indexes.popleft() - self._providers_indexes.append(prev_provider) - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.setCurrentIndex(prev_provider) - self.ui.cmbProviders.blockSignals(False) - - def start_login(self): + def start_login(self, provider): """ Setups the login widgets for actually performing the login and performs some basic checks. + :param provider: the domain of the current provider + :type provider: unicode str :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()) + self._enabled_services = self._settings.get_enabled_services(provider) if len(provider) == 0: self.set_status( @@ -347,14 +272,16 @@ class LoginWidget(QtGui.QWidget): % (e,)) return True - def logged_in(self): + def logged_in(self, provider): """ Sets the widgets to the logged in state + + :param provider: the domain of the current provider + :type provider: unicode str """ self.ui.login_widget.hide() self.ui.logged_widget.show() - self.ui.lblUser.setText(make_address( - self.get_user(), self.get_selected_provider())) + self.ui.lblUser.setText(make_address(self.get_user(), provider)) if flags.OFFLINE is False: self.logged_in_signal.emit() diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 03f91996..8ce7f2fc 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -45,6 +45,7 @@ from leap.bitmask.gui.mail_status import MailStatusWidget from leap.bitmask.gui.preferenceswindow import PreferencesWindow from leap.bitmask.gui.systray import SysTray from leap.bitmask.gui.wizard import Wizard +from leap.bitmask.gui.providers import Providers from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX from leap.bitmask.platform_init.initializers import init_platform @@ -148,13 +149,17 @@ class MainWindow(QtGui.QMainWindow): self._mail_status = MailStatusWidget(self) self.ui.mailLayout.addWidget(self._mail_status) + # Provider List + self._providers = Providers(self.ui.cmbProviders) + # Qt Signal Connections ##################################### # TODO separate logic from ui signals. self._login_widget.login.connect(self._login) self._login_widget.cancel_login.connect(self._cancel_login) self._login_widget.logout.connect(self._logout) - self._login_widget.provider_changed.connect(self._on_provider_changed) + + self._providers.connect_provider_changed(self._on_provider_changed) # EIP Control redux ######################################### self._eip_conductor = eip_conductor.EIPConductor( @@ -577,7 +582,7 @@ class MainWindow(QtGui.QMainWindow): Display the Advanced Key Management dialog. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() logged_user = "{0}@{1}".format(self._logged_user, domain) details = self._provider_details @@ -600,7 +605,7 @@ class MainWindow(QtGui.QMainWindow): Display the preferences window. """ user = self._logged_user - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() mx_provided = False if self._provider_details is not None: mx_provided = MX_SERVICE in self._provider_details['services'] @@ -717,7 +722,7 @@ class MainWindow(QtGui.QMainWindow): Display the EIP preferences window. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() pref = EIPPreferencesWindow(self, domain, self._backend, self._leap_signaler) pref.show() @@ -794,7 +799,7 @@ class MainWindow(QtGui.QMainWindow): # XXX: May be this can be divided into two methods? providers = self._settings.get_configured_providers() - self._login_widget.set_providers(providers) + self._providers.set_providers(providers) self._show_systray() if not self._start_hidden: @@ -810,12 +815,12 @@ class MainWindow(QtGui.QMainWindow): # select the configured provider in the combo box domain = self._wizard.get_domain() - self._login_widget.select_provider_by_name(domain) + self._providers.select_provider_by_name(domain) self._login_widget.set_remember(self._wizard.get_remember()) self._enabled_services = list(self._wizard.get_services()) self._settings.set_enabled_services( - self._login_widget.get_selected_provider(), + self._providers.get_selected_provider(), self._enabled_services) if possible_username is not None: self._login_widget.set_user(possible_username) @@ -832,7 +837,7 @@ class MainWindow(QtGui.QMainWindow): domain = self._settings.get_provider() if domain is not None: - self._login_widget.select_provider_by_name(domain) + self._providers.select_provider_by_name(domain) if not self._settings.get_remember(): # nothing to do here @@ -895,11 +900,7 @@ class MainWindow(QtGui.QMainWindow): """ Set the login label to reflect offline status. """ - provider = "" - if not self._logged_in_offline: - provider = self.ui.lblLoginProvider.text() - - self.ui.lblLoginProvider.setText(provider + self.tr(" (offline mode)")) + # TODO: figure out what widget to use for this. Maybe the window title? # # systray @@ -1159,7 +1160,7 @@ class MainWindow(QtGui.QMainWindow): emit the corresponding signals inmediately """ self._disconnect_scheduled_login() - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.provider_setup(provider=domain) @QtCore.Slot(dict) @@ -1176,7 +1177,7 @@ class MainWindow(QtGui.QMainWindow): :type data: dict """ if data[PASSED_KEY]: - selected_provider = self._login_widget.get_selected_provider() + selected_provider = self._providers.get_selected_provider() self._backend.provider_bootstrap(provider=selected_provider) else: logger.error(data[ERROR_KEY]) @@ -1230,7 +1231,7 @@ class MainWindow(QtGui.QMainWindow): def _on_provider_changed(self, wizard=True): """ TRIGGERS: - self._login.provider_changed + self._providers._provider_changed self.ui.action_create_new_account.triggered Ask the user if really wants to change provider since a services stop @@ -1250,12 +1251,9 @@ class MainWindow(QtGui.QMainWindow): return title = self.tr("Stop services") - text = self.tr("Do you want to stop all services?") + text = "" + self.tr("Do you want to stop all services?") + "" informative_text = self.tr("In order to change the provider, the " "running services needs to be stopped.") - if wizard: - informative_text = self.tr("In order to start the wizard, the " - "running services needs to be stopped.") msg = QtGui.QMessageBox(self) msg.setWindowTitle(title) @@ -1274,7 +1272,7 @@ class MainWindow(QtGui.QMainWindow): else: if not wizard: # if wizard, the widget restores itself - self._login_widget.restore_previous_provider() + self._providers.restore_previous_provider() @QtCore.Slot() def _login(self): @@ -1288,19 +1286,18 @@ class MainWindow(QtGui.QMainWindow): bootstrapping the EIP service """ # TODO most of this could ve handled by the login widget, - # but we'd have to move lblLoginProvider into the widget itself, - # instead of having it as a top-level attribute. + provider = self._providers.get_selected_provider() if flags.OFFLINE is True: logger.debug("OFFLINE mode! bypassing remote login") # TODO reminder, we're not handling logout for offline # mode. - self._login_widget.logged_in() + self._login_widget.logged_in(provider) self._logged_in_offline = True self._set_label_offline() self.offline_mode_bypass_login.emit() else: self.ui.action_create_new_account.setEnabled(False) - if self._login_widget.start_login(): + if self._login_widget.start_login(provider): if self._trying_to_start_eip: self._schedule_login() else: @@ -1380,7 +1377,7 @@ class MainWindow(QtGui.QMainWindow): self._show_hide_unsupported_services() - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.user_login(provider=domain, username=username, password=password) else: @@ -1400,7 +1397,7 @@ class MainWindow(QtGui.QMainWindow): self._logged_user = self._login_widget.get_user() user = self._logged_user - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() full_user_id = make_address(user, domain) self._mail_conductor.userid = full_user_id self._start_eip_bootstrap() @@ -1423,9 +1420,8 @@ class MainWindow(QtGui.QMainWindow): triggers the eip bootstrapping. """ - self._login_widget.logged_in() - domain = self._login_widget.get_selected_provider() - self.ui.lblLoginProvider.setText(domain) + domain = self._providers.get_selected_provider() + self._login_widget.logged_in(domain) self._enabled_services = self._settings.get_enabled_services(domain) @@ -1447,7 +1443,7 @@ class MainWindow(QtGui.QMainWindow): and enabled. This is triggered right after the provider has been set up. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() lang = QtCore.QLocale.system().name() self._backend.provider_get_details(domain=domain, lang=lang) @@ -1468,7 +1464,7 @@ class MainWindow(QtGui.QMainWindow): :returns: True if provides and is enabled, False otherwise :rtype: bool """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() enabled_services = self._settings.get_enabled_services(domain) mx_enabled = MX_SERVICE in enabled_services @@ -1485,7 +1481,7 @@ class MainWindow(QtGui.QMainWindow): :returns: True if provides and is enabled, False otherwise :rtype: bool """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() enabled_services = self._settings.get_enabled_services(domain) eip_enabled = EIP_SERVICE in enabled_services @@ -1506,7 +1502,7 @@ class MainWindow(QtGui.QMainWindow): username = self._login_widget.get_user() password = unicode(self._login_widget.get_password()) - provider_domain = self._login_widget.get_selected_provider() + provider_domain = self._providers.get_selected_provider() if flags.OFFLINE: full_user_id = make_address(username, provider_domain) @@ -1522,7 +1518,7 @@ class MainWindow(QtGui.QMainWindow): password=password, uuid=uuid) else: if self._logged_user is not None: - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.soledad_bootstrap(username=username, domain=domain, password=password) @@ -1606,7 +1602,7 @@ class MainWindow(QtGui.QMainWindow): """ self._already_started_eip = True - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._settings.set_defaultprovider(domain) self._backend.eip_get_gateway_country_code(domain=domain) @@ -1633,7 +1629,7 @@ class MainWindow(QtGui.QMainWindow): Set the current provider and country code in the eip status widget. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._eip_status.set_provider(domain, country_code) @QtCore.Slot() @@ -1641,7 +1637,7 @@ class MainWindow(QtGui.QMainWindow): """ Trigger this if we don't have a working DNS resolver. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() msg = self.tr( "The server at {0} can't be found, because the DNS lookup " "failed. DNS is the network service that translates a " @@ -1705,7 +1701,7 @@ class MainWindow(QtGui.QMainWindow): self._eip_status.eip_button.hide() self._eip_status.eip_button.setEnabled(False) - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.eip_setup(provider=domain) self._already_started_eip = True @@ -1796,7 +1792,6 @@ class MainWindow(QtGui.QMainWindow): Inform the user about a logout error. """ self._login_widget.done_logout() - self.ui.lblLoginProvider.setText(self.tr("Login")) self._login_widget.set_status( self.tr("Something went wrong with the logout.")) @@ -1810,7 +1805,6 @@ class MainWindow(QtGui.QMainWindow): logging out """ self._login_widget.done_logout() - self.ui.lblLoginProvider.setText(self.tr("Login")) self._logged_user = None self._login_widget.logged_out() diff --git a/src/leap/bitmask/gui/providers.py b/src/leap/bitmask/gui/providers.py new file mode 100644 index 00000000..b3eb8620 --- /dev/null +++ b/src/leap/bitmask/gui/providers.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013,2014 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 . +# + +""" +An instance of class Providers, held by mainwindow, is responsible for +managing the current provider and the combobox provider list. +""" + +from collections import deque +from PySide import QtCore + + +class Providers(QtCore.QObject): + + # Emitted when the user changes the provider combobox index. The object + # parameter is actually a boolean value that is True if "Other..." was + # selected, False otherwse + _provider_changed = QtCore.Signal(object) + + def __init__(self, providers_combo): + """ + :param providers_combo: combo widget that lists providers + :type providers_combo: QWidget + """ + QtCore.QObject.__init__(self) + self._providers_indexes = deque(maxlen=2) # previous and current + self._providers_indexes.append(-1) + self._combo = providers_combo + self._combo.currentIndexChanged.connect( + self._current_provider_changed) + + def set_providers(self, provider_list): + """ + Set the provider list to provider_list plus an "Other..." item + that triggers the wizard + + :param provider_list: list of providers + :type provider_list: list of str + """ + self._combo.blockSignals(True) + self._combo.clear() + self._combo.addItems(provider_list + [self.tr("Other...")]) + self._combo.blockSignals(False) + + def select_provider_by_name(self, name): + """ + Given a provider name/domain, it selects it in the combobox + + :param name: name or domain for the provider + :type name: unicode str + """ + provider_index = self._combo.findText(name) + self._providers_indexes.append(provider_index) + + # block the signals during a combobox change since we don't want to + # trigger the default signal that makes the UI ask the user for + # confirmation + self._combo.blockSignals(True) + self._combo.setCurrentIndex(provider_index) + self._combo.blockSignals(False) + + def get_selected_provider(self): + """ + Returns the selected provider in the combobox + + :rtype: unicode str + """ + return self._combo.currentText() + + def connect_provider_changed(self, callback): + """ + Connects callback to provider_changed signal + """ + self._provider_changed.connect(callback) + + def restore_previous_provider(self): + """ + Set as selected provider the one that was selected previously. + """ + prev_provider = self._providers_indexes.popleft() + self._providers_indexes.append(prev_provider) + self._combo.blockSignals(True) + self._combo.setCurrentIndex(prev_provider) + self._combo.blockSignals(False) + + @QtCore.Slot(int) + def _current_provider_changed(self, idx): + """ + TRIGGERS: + self._combo.currentIndexChanged + + :param idx: the index of the new selected item + :type idx: int + """ + self._providers_indexes.append(idx) + is_wizard = idx == (self._combo.count() - 1) + self._provider_changed.emit(is_wizard) + if is_wizard: + self.restore_previous_provider() diff --git a/src/leap/bitmask/gui/ui/login.ui b/src/leap/bitmask/gui/ui/login.ui index 26decc6d..bfd5f9c0 100644 --- a/src/leap/bitmask/gui/ui/login.ui +++ b/src/leap/bitmask/gui/ui/login.ui @@ -69,17 +69,7 @@ 24 - - - - <b>Provider:</b> - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - + @@ -92,7 +82,7 @@ - + @@ -116,10 +106,7 @@ - - - - + <b>Username:</b> @@ -129,10 +116,10 @@ - + - + <b>Password:</b> @@ -142,7 +129,7 @@ - + diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index 5dc48f29..92c13d15 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -75,7 +75,7 @@ 0 0 524 - 589 + 540 @@ -86,7 +86,7 @@ 0 - + 0 @@ -97,29 +97,16 @@ false - background-color: rgba(0,0,0,20); border-bottom: 1px solid rgba(0,0,0,30); + QFrame#providerFrame {background-color: rgba(0,0,0,20); border-bottom: 1px solid rgba(0,0,0,30);} - - 24 - - - 24 - - + - 75 - true + 12 - - background-color: rgba(255, 255, 255, 0); border: none; - - - Please Log In - @@ -186,7 +173,7 @@ - -1 + 6 12 @@ -224,18 +211,18 @@ 0 - - false - - - background-color: rgba(0,0,0,20); border-top: 1px solid rgba(0,0,0,30); - 0 16 + + false + + + background-color: rgba(0,0,0,20); border-top: 1px solid rgba(0,0,0,30); + @@ -319,7 +306,7 @@ 0 0 524 - 21 + 25 -- cgit v1.2.3