From 3795dedd26fc239e143ca2a29b7e16d433f964ba Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Tue, 10 Jun 2014 17:05:06 -0300
Subject: Separate app.py and frontend_app.py logics.

This prepares the scenario to run the frontend and the backend in
different processes.
---
 src/leap/bitmask/app.py          | 106 ++++++---------------------------------
 src/leap/bitmask/frontend_app.py | 103 +++++++++++++++++++++++++++++++++++++
 src/leap/bitmask/gui/__init__.py |   1 +
 3 files changed, 119 insertions(+), 91 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index d0906b7c..f1d87d18 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -39,17 +39,13 @@
 # M:::::::::::~NMMM7???7MMMM:::::::::::::::::::::::NMMMI??I7MMMM:::::::::::::M
 # M::::::::::::::7MMMMMMM+:::::::::::::::::::::::::::?MMMMMMMZ:::::::::::::::M
 #                (thanks to: http://www.glassgiant.com/ascii/)
-import signal
-import sys
+import multiprocessing
 import os
-
-from functools import partial
-
-from PySide import QtCore, QtGui
+import sys
 
 from leap.bitmask import __version__ as VERSION
 from leap.bitmask.config import flags
-from leap.bitmask.gui.mainwindow import MainWindow
+from leap.bitmask.frontend_app import run_frontend
 from leap.bitmask.logs.utils import create_logger
 from leap.bitmask.platform_init.locks import we_are_the_one_and_only
 from leap.bitmask.services.mail import plumber
@@ -59,9 +55,6 @@ from leap.bitmask.util.requirement_checker import check_requirements
 from leap.common.events import server as event_server
 from leap.mail import __version__ as MAIL_VERSION
 
-from twisted.internet import reactor
-from twisted.internet.task import LoopingCall
-
 import codecs
 codecs.register(lambda name: codecs.lookup('utf-8')
                 if name == 'cp65001' else None)
@@ -84,36 +77,7 @@ def kill_the_children():
 
 # XXX This is currently broken, but we need to fix it to avoid
 # orphaned processes in case of a crash.
-#atexit.register(kill_the_children)
-
-
-def sigint_handler(*args, **kwargs):
-    """
-    Signal handler for SIGINT
-    """
-    logger = kwargs.get('logger', None)
-    parentpid = kwargs.get('parentpid', None)
-    pid = os.getpid()
-    if parentpid == pid:
-        if logger:
-            logger.debug("SIGINT catched. shutting down...")
-        mainwindow = args[0]
-        mainwindow.quit()
-
-
-def sigterm_handler(*args, **kwargs):
-    """
-    Signal handler for SIGTERM.
-    This handler is actually passed to twisted reactor
-    """
-    logger = kwargs.get('logger', None)
-    parentpid = kwargs.get('parentpid', None)
-    pid = os.getpid()
-    if parentpid == pid:
-        if logger:
-            logger.debug("SIGTERM catched. shutting down...")
-        mainwindow = args[0]
-        mainwindow.quit()
+# atexit.register(kill_the_children)
 
 
 def do_display_version(opts):
@@ -141,7 +105,7 @@ def do_mail_plumbing(opts):
     # XXX catch when import is used w/o acct
 
 
-def main():
+def start_app():
     """
     Starts the main event loop and launches the main window.
     """
@@ -149,8 +113,12 @@ def main():
     opts = leap_argparse.get_options()
     do_display_version(opts)
 
-    bypass_checks = opts.danger
-    start_hidden = opts.start_hidden
+    options = {
+        'bypass_checks': opts.danger,
+        'start_hidden': opts.start_hidden,
+        'debug': opts.debug,
+        'log_file': opts.log_file,
+    }
 
     flags.STANDALONE = opts.standalone
     flags.OFFLINE = opts.offline
@@ -202,53 +170,9 @@ def main():
 
     logger.info('Starting app')
 
-    # We force the style if on KDE so that it doesn't load all the kde
-    # libs, which causes a compatibility issue in some systems.
-    # For more info, see issue #3194
-    if flags.STANDALONE and os.environ.get("KDE_SESSION_UID") is not None:
-        sys.argv.append("-style")
-        sys.argv.append("Cleanlooks")
-
-    app = QtGui.QApplication(sys.argv)
-
-    # To test:
-    # $ LANG=es ./app.py
-    locale = QtCore.QLocale.system().name()
-    qtTranslator = QtCore.QTranslator()
-    if qtTranslator.load("qt_%s" % locale, ":/translations"):
-        app.installTranslator(qtTranslator)
-    appTranslator = QtCore.QTranslator()
-    if appTranslator.load("%s.qm" % locale[:2], ":/translations"):
-        app.installTranslator(appTranslator)
-
-    # Needed for initializing qsettings it will write
-    # .config/leap/leap.conf top level app settings in a platform
-    # independent way
-    app.setOrganizationName("leap")
-    app.setApplicationName("leap")
-    app.setOrganizationDomain("leap.se")
-
-    window = MainWindow(bypass_checks=bypass_checks,
-                        start_hidden=start_hidden)
-
-    mainpid = os.getpid()
-    sigint_window = partial(sigint_handler, window,
-                            logger=logger, parentpid=mainpid)
-    signal.signal(signal.SIGINT, sigint_window)
-
-    # callable used in addSystemEventTrigger to handle SIGTERM
-    sigterm_window = partial(sigterm_handler, window,
-                             logger=logger, parentpid=mainpid)
-    # SIGTERM can't be handled the same way SIGINT is, since it's
-    # caught by twisted. See _handleSignals method in
-    # twisted/internet/base.py#L1150. So, addSystemEventTrigger
-    # reactor's method is used.
-    reactor.addSystemEventTrigger('before', 'shutdown', sigterm_window)
-
-    l = LoopingCall(QtCore.QCoreApplication.processEvents, 0, 10)
-    l.start(0.01)
-
-    reactor.run()
+    frontend = multiprocessing.Process(target=run_frontend, args=(options, ))
+    frontend.start()
+
 
 if __name__ == "__main__":
-    main()
+    start_app()
diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py
index e69de29b..ed67a77a 100644
--- a/src/leap/bitmask/frontend_app.py
+++ b/src/leap/bitmask/frontend_app.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+# frontend_app.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 <http://www.gnu.org/licenses/>.
+import signal
+import sys
+import os
+
+from functools import partial
+
+from PySide import QtCore, QtGui
+
+from leap.bitmask.config import flags
+from leap.bitmask.gui import locale_rc  # noqa - silence pylint
+from leap.bitmask.gui.mainwindow import MainWindow
+# from leap.bitmask.logs.utils import create_logger
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+def sigint_handler(*args, **kwargs):
+    """
+    Signal handler for SIGINT
+    """
+    logger = kwargs.get('logger', None)
+    if logger:
+        logger.debug("SIGINT catched. shutting down...")
+    mainwindow = args[0]
+    mainwindow.quit()
+
+
+def sigterm_handler(*args, **kwargs):
+    """
+    Signal handler for SIGTERM.
+    This handler is actually passed to twisted reactor
+    """
+    logger = kwargs.get('logger', None)
+    if logger:
+        logger.debug("SIGTERM catched. shutting down...")
+    mainwindow = args[0]
+    mainwindow.quit()
+
+
+def run_frontend(options):
+    """
+    Run the GUI for the application.
+
+    :param options: a dict of options parsed from the command line.
+    :type options: dict
+    """
+    bypass_checks = options["bypass_checks"]
+    start_hidden = options["start_hidden"]
+
+    # We force the style if on KDE so that it doesn't load all the kde
+    # libs, which causes a compatibility issue in some systems.
+    # For more info, see issue #3194
+    if flags.STANDALONE and os.environ.get("KDE_SESSION_UID") is not None:
+        sys.argv.append("-style")
+        sys.argv.append("Cleanlooks")
+
+    qApp = QtGui.QApplication(sys.argv)
+
+    # To test:
+    # $ LANG=es ./app.py
+    locale = QtCore.QLocale.system().name()
+    qtTranslator = QtCore.QTranslator()
+    if qtTranslator.load("qt_%s" % locale, ":/translations"):
+        qApp.installTranslator(qtTranslator)
+    appTranslator = QtCore.QTranslator()
+    if appTranslator.load("%s.qm" % locale[:2], ":/translations"):
+        qApp.installTranslator(appTranslator)
+
+    # Needed for initializing qsettings it will write
+    # .config/leap/leap.conf top level app settings in a platform
+    # independent way
+    qApp.setOrganizationName("leap")
+    qApp.setApplicationName("leap")
+    qApp.setOrganizationDomain("leap.se")
+
+    window = MainWindow(bypass_checks=bypass_checks,
+                        start_hidden=start_hidden)
+
+    sigint_window = partial(sigint_handler, window, logger=logger)
+    signal.signal(signal.SIGINT, sigint_window)
+
+    sys.exit(qApp.exec_())
+
+
+if __name__ == '__main__':
+    run_frontend()
diff --git a/src/leap/bitmask/gui/__init__.py b/src/leap/bitmask/gui/__init__.py
index 94bf1fd5..bba02061 100644
--- a/src/leap/bitmask/gui/__init__.py
+++ b/src/leap/bitmask/gui/__init__.py
@@ -19,5 +19,6 @@ init file for leap.gui
 """
 # This was added for coverage and testing, but when doing the osx
 # bundle with py2app it fails because of this, so commenting for now
+# Also creates conflicts with the new frontend/backend separation.
 # app = __import__("app", globals(), locals(), [], 2)
 # __all__ = [app]
-- 
cgit v1.2.3


From 1eae3af1906f95d9d2d76c205b61799d248f0e71 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Tue, 8 Jul 2014 16:45:43 -0300
Subject: Add base communication framework.

---
 src/leap/bitmask/backend/backend.py       | 196 ++++++++++++++++++++++++++++++
 src/leap/bitmask/backend/backend_proxy.py | 142 ++++++++++++++++++++++
 src/leap/bitmask/backend/signaler.py      | 140 +++++++++++++++++++++
 src/leap/bitmask/backend/signaler_qt.py   | 105 ++++++++++++++++
 src/leap/bitmask/backend/utils.py         |  43 +++++++
 5 files changed, 626 insertions(+)
 create mode 100644 src/leap/bitmask/backend/backend.py
 create mode 100644 src/leap/bitmask/backend/backend_proxy.py
 create mode 100644 src/leap/bitmask/backend/signaler.py
 create mode 100644 src/leap/bitmask/backend/signaler_qt.py
 create mode 100644 src/leap/bitmask/backend/utils.py

(limited to 'src')

diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py
new file mode 100644
index 00000000..26c547b6
--- /dev/null
+++ b/src/leap/bitmask/backend/backend.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python
+# encoding: utf-8
+import json
+import threading
+import time
+
+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.utils import get_backend_certificates
+from leap.bitmask.backend.signaler import Signaler
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+class Backend(object):
+    """
+    Backend server.
+    Receives signals from backend_proxy and emit signals if needed.
+    """
+    PORT = '5556'
+    BIND_ADDR = "tcp://127.0.0.1:%s" % PORT
+
+    def __init__(self):
+        """
+        Backend constructor, create needed instances.
+        """
+        self._signaler = Signaler()
+
+        self._do_work = threading.Event()  # used to stop the worker thread.
+        self._zmq_socket = None
+
+        self._ongoing_defers = []
+        self._init_zmq()
+
+    def _init_zmq(self):
+        """
+        Configure the zmq components and connection.
+        """
+        context = zmq.Context()
+        socket = context.socket(zmq.REP)
+
+        # Start an authenticator for this context.
+        auth = ThreadAuthenticator(context)
+        auth.start()
+        auth.allow('127.0.0.1')
+
+        # Tell authenticator to use the certificate in a directory
+        auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY)
+        public, secret = get_backend_certificates()
+        socket.curve_publickey = public
+        socket.curve_secretkey = secret
+        socket.curve_server = True  # must come before bind
+
+        socket.bind(self.BIND_ADDR)
+
+        self._zmq_socket = socket
+
+    def _worker(self):
+        """
+        Receive requests and send it to process.
+
+        Note: we use a simple while since is less resource consuming than a
+        Twisted's LoopingCall.
+        """
+        while self._do_work.is_set():
+            # Wait for next request from client
+            try:
+                request = self._zmq_socket.recv(zmq.NOBLOCK)
+                self._zmq_socket.send("OK")
+                logger.debug("Received request: '{0}'".format(request))
+                self._process_request(request)
+            except zmq.ZMQError as e:
+                if e.errno != zmq.EAGAIN:
+                    raise
+            time.sleep(0.01)
+
+    def _stop_reactor(self):
+        """
+        Stop the Twisted reactor, but first wait a little for some threads to
+        complete their work.
+
+        Note: this method needs to be run in a different thread so the
+        time.sleep() does not block and other threads can finish.
+        i.e.:
+            use threads.deferToThread(this_method) instead of this_method()
+        """
+        wait_max = 5  # seconds
+        wait_step = 0.5
+        wait = 0
+        while self._ongoing_defers and wait < wait_max:
+            time.sleep(wait_step)
+            wait += wait_step
+            msg = "Waiting for running threads to finish... {0}/{1}"
+            msg = msg.format(wait, wait_max)
+            logger.debug(msg)
+
+        # after a timeout we shut down the existing threads.
+        for d in self._ongoing_defers:
+            d.cancel()
+
+        reactor.stop()
+        logger.debug("Twisted reactor stopped.")
+
+    def run(self):
+        """
+        Start the ZMQ server and run the loop to handle requests.
+        """
+        self._signaler.start()
+        self._do_work.set()
+        threads.deferToThread(self._worker)
+        reactor.run()
+
+    def stop(self):
+        """
+        Stop the server and the zmq request parse loop.
+        """
+        logger.debug("STOP received.")
+        self._signaler.stop()
+        self._do_work.clear()
+        threads.deferToThread(self._stop_reactor)
+
+    def _process_request(self, request_json):
+        """
+        Process a request and call the according method with the given
+        parameters.
+
+        :param request_json: a json specification of a request.
+        :type request_json: str
+        """
+        try:
+            # request = zmq.utils.jsonapi.loads(request_json)
+            # We use stdlib's json to ensure that we get unicode strings
+            request = json.loads(request_json)
+            api_method = request['api_method']
+            kwargs = request['arguments'] or None
+        except Exception as e:
+            msg = "Malformed JSON data in Backend request '{0}'. Exc: {1!r}"
+            msg = msg.format(request_json, e)
+            msg = msg.format(request_json)
+            logger.critical(msg)
+            raise
+
+        if api_method not in API:
+            logger.error("Invalid API call '{0}'".format(api_method))
+            return
+
+        self._run_in_thread(api_method, kwargs)
+
+    def _run_in_thread(self, api_method, kwargs):
+        """
+        Run the method name in a thread with the given arguments.
+
+        :param api_method: the callable name to run in a thread.
+        :type api_method: str
+        :param kwargs: the arguments dict that will be sent to the callable.
+        :type kwargs: tuple
+        """
+        func = getattr(self, api_method)
+
+        method = func
+        if kwargs is not None:
+            method = lambda: func(**kwargs)
+
+        logger.debug("Running method: '{0}' "
+                     "with args: '{1}' in a thread".format(api_method, kwargs))
+
+        # run the action in a thread and keep track of it
+        d = threads.deferToThread(method)
+        d.addCallback(self._done_action, d)
+        d.addErrback(self._done_action, d)
+        self._ongoing_defers.append(d)
+
+    def _done_action(self, failure, d):
+        """
+        Remove the defer from the ongoing list.
+
+        :param failure: the failure that triggered the errback.
+                        None if no error.
+        :type failure: twisted.python.failure.Failure
+        :param d: defer to remove
+        :type d: twisted.internet.defer.Deferred
+        """
+        if failure is not None:
+            if failure.check(defer.CancelledError):
+                logger.debug("A defer was cancelled.")
+            else:
+                logger.error("There was a failure - {0!r}".format(failure))
+                logger.error(failure.getTraceback())
+
+        if d in self._ongoing_defers:
+            self._ongoing_defers.remove(d)
diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py
new file mode 100644
index 00000000..ae9cf5b1
--- /dev/null
+++ b/src/leap/bitmask/backend/backend_proxy.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+# encoding: utf-8
+import functools
+import Queue
+import threading
+import time
+
+import zmq
+
+from leap.bitmask.backend.api import API, STOP_REQUEST
+from leap.bitmask.backend.utils import get_backend_certificates
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+class BackendProxy(object):
+    """
+    The BackendProxy handles calls from the GUI and forwards (through ZMQ)
+    to the backend.
+    """
+    PORT = '5556'
+    SERVER = "tcp://localhost:%s" % PORT
+
+    def __init__(self):
+        self._socket = None
+
+        # initialize ZMQ stuff:
+        context = zmq.Context()
+        logger.debug("Connecting to server...")
+        socket = context.socket(zmq.REQ)
+
+        # public, secret = zmq.curve_keypair()
+        client_keys = zmq.curve_keypair()
+        socket.curve_publickey = client_keys[0]
+        socket.curve_secretkey = client_keys[1]
+
+        # The client must know the server's public key to make a CURVE
+        # connection.
+        public, _ = get_backend_certificates()
+        socket.curve_serverkey = public
+
+        socket.setsockopt(zmq.RCVTIMEO, 1000)
+        socket.connect(self.SERVER)
+        self._socket = socket
+
+        self._call_queue = Queue.Queue()
+        self._worker_caller = threading.Thread(target=self._worker)
+        self._worker_caller.start()
+
+    def _worker(self):
+        """
+        Worker loop that processes the Queue of pending requests to do.
+        """
+        while True:
+            try:
+                request = self._call_queue.get(block=False)
+                # break the loop after sending the 'stop' action to the
+                # backend.
+                if request == STOP_REQUEST:
+                    break
+
+                self._send_request(request)
+            except Queue.Empty:
+                pass
+            time.sleep(0.01)
+
+        logger.debug("BackendProxy worker stopped.")
+
+    def _api_call(self, *args, **kwargs):
+        """
+        Call the `api_method` method in backend (through zmq).
+
+        :param kwargs: named arguments to forward to the backend api method.
+        :type kwargs: dict
+
+        Note: is mandatory to have the kwarg 'api_method' defined.
+        """
+        if args:
+            # Use a custom message to be more clear about using kwargs *only*
+            raise Exception("All arguments need to be kwargs!")
+
+        api_method = kwargs.pop('api_method', None)
+        if api_method is None:
+            raise Exception("Missing argument, no method name specified.")
+
+        request = {
+            'api_method': api_method,
+            'arguments': kwargs,
+        }
+
+        try:
+            request_json = zmq.utils.jsonapi.dumps(request)
+        except Exception as e:
+            msg = ("Error serializing request into JSON.\n"
+                   "Exception: {0} Data: {1}")
+            msg = msg.format(e, request)
+            logger.critical(msg)
+            raise
+
+        # queue the call in order to handle the request in a thread safe way.
+        self._call_queue.put(request_json)
+
+        if api_method == STOP_REQUEST:
+            self._call_queue.put(STOP_REQUEST)
+
+    def _send_request(self, request):
+        """
+        Send the given request to the server.
+        This is used from a thread safe loop in order to avoid sending a
+        request without receiving a response from a previous one.
+
+        :param request: the request to send.
+        :type request: str
+        """
+        logger.debug("Sending request to backend: {0}".format(request))
+        self._socket.send(request)
+
+        try:
+            # Get the reply.
+            response = self._socket.recv()
+            msg = "Received reply for '{0}' -> '{1}'".format(request, response)
+            logger.debug(msg)
+        except zmq.error.Again as e:
+            msg = "Timeout error contacting backend. {0!r}".format(e)
+            logger.critical(msg)
+
+    def __getattribute__(self, name):
+        """
+        This allows the user to do:
+            bp = BackendProxy()
+            bp.some_method()
+
+        Just by having defined 'some_method' in the API
+
+        :param name: the attribute name that is requested.
+        :type name: str
+        """
+        if name in API:
+            return functools.partial(self._api_call, api_method=name)
+        else:
+            return object.__getattribute__(self, name)
diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py
new file mode 100644
index 00000000..d96015f4
--- /dev/null
+++ b/src/leap/bitmask/backend/signaler.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# encoding: utf-8
+import Queue
+import threading
+import time
+
+import zmq
+
+from leap.bitmask.backend.api import SIGNALS
+from leap.bitmask.backend.utils import get_frontend_certificates
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+class Signaler(object):
+    """
+    Signaler client.
+    Receives signals from the backend and sends to the signaling server.
+    """
+    PORT = "5667"
+    SERVER = "tcp://localhost:%s" % PORT
+
+    def __init__(self):
+        """
+        Initialize the ZMQ socket to talk to the signaling server.
+        """
+        context = zmq.Context()
+        logger.debug("Connecting to signaling server...")
+        socket = context.socket(zmq.REQ)
+
+        # public, secret = zmq.curve_keypair()
+        client_keys = zmq.curve_keypair()
+        socket.curve_publickey = client_keys[0]
+        socket.curve_secretkey = client_keys[1]
+
+        # The client must know the server's public key to make a CURVE
+        # connection.
+        public, _ = get_frontend_certificates()
+        socket.curve_serverkey = public
+
+        socket.setsockopt(zmq.RCVTIMEO, 1000)
+        socket.connect(self.SERVER)
+        self._socket = socket
+
+        self._signal_queue = Queue.Queue()
+
+        self._do_work = threading.Event()  # used to stop the worker thread.
+        self._worker_signaler = threading.Thread(target=self._worker)
+
+    def __getattribute__(self, name):
+        """
+        This allows the user to do:
+            S = Signaler()
+            S.SOME_SIGNAL
+
+        Just by having defined 'some_signal' in _SIGNALS
+
+        :param name: the attribute name that is requested.
+        :type name: str
+        """
+        if name in SIGNALS:
+            return name
+        else:
+            return object.__getattribute__(self, name)
+
+    def signal(self, signal, data=None):
+        """
+        Sends a signal to the signaling server.
+
+        :param signal: the signal to send.
+        :type signal: str
+        """
+        if signal not in SIGNALS:
+            raise Exception("Unknown signal: '{0}'".format(signal))
+
+        request = {
+            'signal': signal,
+            'data': data,
+        }
+
+        try:
+            request_json = zmq.utils.jsonapi.dumps(request)
+        except Exception as e:
+            msg = ("Error serializing request into JSON.\n"
+                   "Exception: {0} Data: {1}")
+            msg = msg.format(e, request)
+            logger.critical(msg)
+            raise
+
+        # queue the call in order to handle the request in a thread safe way.
+        self._signal_queue.put(request_json)
+
+    def _worker(self):
+        """
+        Worker loop that processes the Queue of pending requests to do.
+        """
+        while self._do_work.is_set():
+            try:
+                request = self._signal_queue.get(block=False)
+                self._send_request(request)
+            except Queue.Empty:
+                pass
+            time.sleep(0.01)
+
+        logger.debug("Signaler thread stopped.")
+
+    def start(self):
+        """
+        Start the Signaler worker.
+        """
+        self._do_work.set()
+        self._worker_signaler.start()
+
+    def stop(self):
+        """
+        Stop the Signaler worker.
+        """
+        self._do_work.clear()
+
+    def _send_request(self, request):
+        """
+        Send the given request to the server.
+        This is used from a thread safe loop in order to avoid sending a
+        request without receiving a response from a previous one.
+
+        :param request: the request to send.
+        :type request: str
+        """
+        logger.debug("Signaling '{0}'".format(request))
+        self._socket.send(request)
+
+        # Get the reply.
+        try:
+            response = self._socket.recv()
+            msg = "Received reply for '{0}' -> '{1}'".format(request, response)
+            logger.debug(msg)
+        except zmq.error.Again as e:
+            msg = "Timeout error contacting signaler. {0!r}".format(e)
+            logger.critical(msg)
diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py
new file mode 100644
index 00000000..cf49df91
--- /dev/null
+++ b/src/leap/bitmask/backend/signaler_qt.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+# encoding: utf-8
+import threading
+import time
+
+from PySide import QtCore
+
+import zmq
+from zmq.auth.thread import ThreadAuthenticator
+
+from leap.bitmask.backend.api import SIGNALS
+from leap.bitmask.backend.utils import get_frontend_certificates
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+class SignalerQt(QtCore.QThread):
+    """
+    Signaling server.
+    Receives signals from the signaling client and emit Qt signals for the GUI.
+    """
+    PORT = "5667"
+    BIND_ADDR = "tcp://127.0.0.1:%s" % PORT
+
+    def __init__(self):
+        QtCore.QThread.__init__(self)
+        self._do_work = threading.Event()
+        self._do_work.set()
+
+    def run(self):
+        """
+        Start a loop to process the ZMQ requests from the signaler client.
+        """
+        logger.debug("Running SignalerQt loop")
+        context = zmq.Context()
+        socket = context.socket(zmq.REP)
+
+        # Start an authenticator for this context.
+        auth = ThreadAuthenticator(context)
+        auth.start()
+        auth.allow('127.0.0.1')
+
+        # Tell authenticator to use the certificate in a directory
+        auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY)
+        public, secret = get_frontend_certificates()
+        socket.curve_publickey = public
+        socket.curve_secretkey = secret
+        socket.curve_server = True  # must come before bind
+
+        socket.bind(self.BIND_ADDR)
+
+        while self._do_work.is_set():
+            # Wait for next request from client
+            try:
+                request = socket.recv(zmq.NOBLOCK)
+                logger.debug("Received request: '{0}'".format(request))
+                socket.send("OK")
+                self._process_request(request)
+            except zmq.ZMQError as e:
+                if e.errno != zmq.EAGAIN:
+                    raise
+            time.sleep(0.01)
+
+        logger.debug("SignalerQt thread stopped.")
+
+    def stop(self):
+        """
+        Stop the SignalerQt blocking loop.
+        """
+        self._do_work.clear()
+
+    def _process_request(self, request_json):
+        """
+        Process a request and call the according method with the given
+        parameters.
+
+        :param request_json: a json specification of a request.
+        :type request_json: str
+        """
+        try:
+            request = zmq.utils.jsonapi.loads(request_json)
+            signal = request['signal']
+            data = request['data']
+        except Exception as e:
+            msg = "Malformed JSON data in Signaler request '{0}'. Exc: {1!r}"
+            msg = msg.format(request_json, e)
+            logger.critical(msg)
+            raise
+
+        if signal not in SIGNALS:
+            logger.error("Unknown signal received, '{0}'".format(signal))
+            return
+
+        try:
+            qt_signal = getattr(self, signal)
+        except Exception:
+            logger.warning("Signal not implemented, '{0}'".format(signal))
+            return
+
+        logger.debug("Emitting '{0}'".format(signal))
+        if data is None:
+            qt_signal.emit()
+        else:
+            qt_signal.emit(data)
diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py
new file mode 100644
index 00000000..5fe59a62
--- /dev/null
+++ b/src/leap/bitmask/backend/utils.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# encoding: utf-8
+import os
+import shutil
+
+import zmq.auth
+
+from leap.bitmask.util import get_path_prefix
+
+KEYS_DIR = os.path.join(get_path_prefix(), 'leap', 'zmq_certificates')
+
+
+def generate_certificates():
+    """
+    Generate client and server CURVE certificate files.
+    """
+    # Create directory for certificates, remove old content if necessary
+    if os.path.exists(KEYS_DIR):
+        shutil.rmtree(KEYS_DIR)
+    os.mkdir(KEYS_DIR)
+
+    # create new keys in certificates dir
+    # public_file, secret_file = create_certificates(...)
+    zmq.auth.create_certificates(KEYS_DIR, "frontend")
+    zmq.auth.create_certificates(KEYS_DIR, "backend")
+
+
+def get_frontend_certificates():
+    """
+    Return the frontend's public and secret certificates.
+    """
+    frontend_secret_file = os.path.join(KEYS_DIR, "frontend.key_secret")
+    public, secret = zmq.auth.load_certificate(frontend_secret_file)
+    return public, secret
+
+
+def get_backend_certificates(base_dir='.'):
+    """
+    Return the backend's public and secret certificates.
+    """
+    backend_secret_file = os.path.join(KEYS_DIR, "backend.key_secret")
+    public, secret = zmq.auth.load_certificate(backend_secret_file)
+    return public, secret
-- 
cgit v1.2.3


From 787c799077cd19f5f87b3c2f26c66df7e8b48023 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 25 Jun 2014 12:19:00 -0300
Subject: Add API/SIGNALs definition.

---
 src/leap/bitmask/backend/api.py | 130 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)
 create mode 100644 src/leap/bitmask/backend/api.py

(limited to 'src')

diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py
new file mode 100644
index 00000000..9e0f9ab8
--- /dev/null
+++ b/src/leap/bitmask/backend/api.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Backend available API and SIGNALS definition.
+"""
+STOP_REQUEST = "stop"
+
+API = (
+    STOP_REQUEST,  # this method needs to be defined in order to support the
+                   # backend stop action
+
+    "eip_can_start",
+    "eip_cancel_setup",
+    "eip_check_dns",
+    "eip_get_gateways_list",
+    "eip_get_initialized_providers",
+    "eip_setup",
+    "eip_start",
+    "eip_stop",
+    "eip_terminate",
+    "imap_start_service",
+    "imap_stop_service",
+    "keymanager_export_keys",
+    "keymanager_get_key_details",
+    "keymanager_list_keys",
+    "provider_bootstrap",
+    "provider_cancel_setup",
+    "provider_get_all_services",
+    "provider_get_details",
+    "provider_get_pinned_providers",
+    "provider_get_supported_services",
+    "provider_setup",
+    "smtp_start_service",
+    "smtp_stop_service",
+    "soledad_bootstrap",
+    "soledad_cancel_bootstrap",
+    "soledad_change_password",
+    "soledad_close",
+    "soledad_load_offline",
+    "tear_fw_down",
+    "user_cancel_login",
+    "user_change_password",
+    "user_get_logged_in_status",
+    "user_login",
+    "user_logout",
+    "user_register",
+)
+
+
+SIGNALS = (
+    "backend_bad_call",
+    "eip_alien_openvpn_already_running",
+    "eip_can_start",
+    "eip_cancelled_setup",
+    "eip_cannot_start",
+    "eip_client_certificate_ready",
+    "eip_config_ready",
+    "eip_connected",
+    "eip_connection_aborted",
+    "eip_connection_died",
+    "eip_disconnected",
+    "eip_dns_error",
+    "eip_dns_ok",
+    "eip_get_gateways_list",
+    "eip_get_gateways_list_error",
+    "eip_get_initialized_providers",
+    "eip_network_unreachable",
+    "eip_no_pkexec_error",
+    "eip_no_polkit_agent_error",
+    "eip_no_tun_kext_error",
+    "eip_openvpn_already_running",
+    "eip_openvpn_not_found_error",
+    "eip_process_finished",
+    "eip_process_restart_ping",
+    "eip_process_restart_tls",
+    "eip_state_changed",
+    "eip_status_changed",
+    "eip_stopped",
+    "eip_tear_fw_down",
+    "eip_uninitialized_provider",
+    "eip_vpn_launcher_exception",
+    "imap_stopped",
+    "keymanager_export_error",
+    "keymanager_export_ok",
+    "keymanager_import_addressmismatch",
+    "keymanager_import_datamismatch",
+    "keymanager_import_ioerror",
+    "keymanager_import_missingkey",
+    "keymanager_import_ok",
+    "keymanager_key_details",
+    "keymanager_keys_list",
+    "prov_cancelled_setup",
+    "prov_check_api_certificate",
+    "prov_check_ca_fingerprint",
+    "prov_download_ca_cert",
+    "prov_download_provider_info",
+    "prov_get_all_services",
+    "prov_get_details",
+    "prov_get_pinned_providers",
+    "prov_get_supported_services",
+    "prov_https_connection",
+    "prov_name_resolution",
+    "prov_problem_with_provider",
+    "prov_unsupported_api",
+    "prov_unsupported_client",
+    "soledad_bootstrap_failed",
+    "soledad_bootstrap_finished",
+    "soledad_cancelled_bootstrap",
+    "soledad_invalid_auth_token",
+    "soledad_offline_failed",
+    "soledad_offline_finished",
+    "soledad_password_change_error",
+    "soledad_password_change_ok",
+    "srp_auth_bad_user_or_password",
+    "srp_auth_connection_error",
+    "srp_auth_error",
+    "srp_auth_ok",
+    "srp_auth_server_error",
+    "srp_logout_error",
+    "srp_logout_ok",
+    "srp_not_logged_in_error",
+    "srp_password_change_badpw",
+    "srp_password_change_error",
+    "srp_password_change_ok",
+    "srp_registration_failed",
+    "srp_registration_finished",
+    "srp_registration_taken",
+    "srp_status_logged_in",
+    "srp_status_not_logged_in",
+)
-- 
cgit v1.2.3


From 4d5e56dacf33465df5d195ada2855c86ee23a21f Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Thu, 19 Jun 2014 16:54:34 -0300
Subject: Add license headers.

---
 src/leap/bitmask/backend/api.py           | 18 ++++++++++++++++--
 src/leap/bitmask/backend/backend.py       | 18 ++++++++++++++++--
 src/leap/bitmask/backend/backend_proxy.py | 18 ++++++++++++++++--
 src/leap/bitmask/backend/signaler.py      | 18 ++++++++++++++++--
 src/leap/bitmask/backend/signaler_qt.py   | 18 ++++++++++++++++--
 src/leap/bitmask/backend/utils.py         | 18 ++++++++++++++++--
 6 files changed, 96 insertions(+), 12 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py
index 9e0f9ab8..012b3cbc 100644
--- a/src/leap/bitmask/backend/api.py
+++ b/src/leap/bitmask/backend/api.py
@@ -1,5 +1,19 @@
-#!/usr/bin/env python
-# encoding: utf-8
+# -*- coding: utf-8 -*-
+# api.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 <http://www.gnu.org/licenses/>.
 """
 Backend available API and SIGNALS definition.
 """
diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py
index 26c547b6..5f696f75 100644
--- a/src/leap/bitmask/backend/backend.py
+++ b/src/leap/bitmask/backend/backend.py
@@ -1,5 +1,19 @@
-#!/usr/bin/env python
-# encoding: utf-8
+# -*- coding: utf-8 -*-
+# backend.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 <http://www.gnu.org/licenses/>.
 import json
 import threading
 import time
diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py
index ae9cf5b1..3c8e5d0f 100644
--- a/src/leap/bitmask/backend/backend_proxy.py
+++ b/src/leap/bitmask/backend/backend_proxy.py
@@ -1,5 +1,19 @@
-#!/usr/bin/env python
-# encoding: utf-8
+# -*- coding: utf-8 -*-
+# backend_proxy.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 <http://www.gnu.org/licenses/>.
 import functools
 import Queue
 import threading
diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py
index d96015f4..f8753771 100644
--- a/src/leap/bitmask/backend/signaler.py
+++ b/src/leap/bitmask/backend/signaler.py
@@ -1,5 +1,19 @@
-#!/usr/bin/env python
-# encoding: utf-8
+# -*- coding: utf-8 -*-
+# signaler.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 <http://www.gnu.org/licenses/>.
 import Queue
 import threading
 import time
diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py
index cf49df91..dabd6662 100644
--- a/src/leap/bitmask/backend/signaler_qt.py
+++ b/src/leap/bitmask/backend/signaler_qt.py
@@ -1,5 +1,19 @@
-#!/usr/bin/env python
-# encoding: utf-8
+# -*- coding: utf-8 -*-
+# signaler_qt.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 <http://www.gnu.org/licenses/>.
 import threading
 import time
 
diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py
index 5fe59a62..5d600689 100644
--- a/src/leap/bitmask/backend/utils.py
+++ b/src/leap/bitmask/backend/utils.py
@@ -1,5 +1,19 @@
-#!/usr/bin/env python
-# encoding: utf-8
+# -*- coding: utf-8 -*-
+# utils.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 <http://www.gnu.org/licenses/>.
 import os
 import shutil
 
-- 
cgit v1.2.3


From 8d5ca2dda0f014cc036768a5eef343e568bb292d Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Thu, 19 Jun 2014 14:58:43 -0300
Subject: Use new frontend/backend structure in LEAP implementation.

---
 src/leap/bitmask/backend/leapbackend.py  | 278 ++++++--------------
 src/leap/bitmask/backend/leapsignaler.py | 433 ++++++-------------------------
 2 files changed, 155 insertions(+), 556 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py
index 3c5222f4..cc7227ad 100644
--- a/src/leap/bitmask/backend/leapbackend.py
+++ b/src/leap/bitmask/backend/leapbackend.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # leapbackend.py
-# Copyright (C) 2013 LEAP
+# 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
@@ -15,178 +15,60 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
-Backend for GUI/Logic communication.
+Backend for everything
 """
 import logging
-
-from Queue import Queue, Empty
-
-from twisted.internet import reactor
-from twisted.internet import threads, defer
-from twisted.internet.task import LoopingCall
+import signal
 
 import zope.interface
 import zope.proxy
 
-from leap.bitmask.backend.leapsignaler import Signaler
 from leap.bitmask.backend import components
+from leap.bitmask.backend.backend import Backend
 
 logger = logging.getLogger(__name__)
 
 
-class Backend(object):
+class LeapBackend(Backend):
     """
-    Backend for everything, the UI should only use this class.
+    Backend server subclass, used to implement the API methods.
     """
-
-    PASSED_KEY = "passed"
-    ERROR_KEY = "error"
-
     def __init__(self, bypass_checks=False):
         """
         Constructor for the backend.
         """
-        # Components map for the commands received
-        self._components = {}
-
-        # Ongoing defers that will be cancelled at stop time
-        self._ongoing_defers = []
-
-        # Signaler object to translate commands into Qt signals
-        self._signaler = Signaler()
+        Backend.__init__(self)
 
         # Objects needed by several components, so we make a proxy and pass
         # them around
         self._soledad_proxy = zope.proxy.ProxyBase(None)
         self._keymanager_proxy = zope.proxy.ProxyBase(None)
 
-        # Component registration
-        self._register(components.Provider(self._signaler, bypass_checks))
-        self._register(components.Register(self._signaler))
-        self._register(components.Authenticate(self._signaler))
-        self._register(components.EIP(self._signaler))
-        self._register(components.Soledad(self._soledad_proxy,
-                                          self._keymanager_proxy,
-                                          self._signaler))
-        self._register(components.Keymanager(self._keymanager_proxy,
-                                             self._signaler))
-        self._register(components.Mail(self._soledad_proxy,
-                                       self._keymanager_proxy,
-                                       self._signaler))
-
-        # We have a looping call on a thread executing all the
-        # commands in queue. Right now this queue is an actual Queue
-        # object, but it'll become the zmq recv_multipart queue
-        self._lc = LoopingCall(threads.deferToThread, self._worker)
-
-        # Temporal call_queue for worker, will be replaced with
-        # recv_multipart os something equivalent in the loopingcall
-        self._call_queue = Queue()
-
-    @property
-    def signaler(self):
-        """
-        Public signaler access to let the UI connect to its signals.
-        """
-        return self._signaler
-
-    def start(self):
-        """
-        Starts the looping call
-        """
-        logger.debug("Starting worker...")
-        self._lc.start(0.01)
-
-    def stop(self):
-        """
-        Stops the looping call and tries to cancel all the defers.
-        """
-        reactor.callLater(2, self._stop)
-
-    def _stop(self):
-        """
-        Delayed stopping of worker. Called from `stop`.
-        """
-        logger.debug("Stopping worker...")
-        if self._lc.running:
-            self._lc.stop()
-        else:
-            logger.warning("Looping call is not running, cannot stop")
-
-        logger.debug("Cancelling ongoing defers...")
-        while len(self._ongoing_defers) > 0:
-            d = self._ongoing_defers.pop()
-            d.cancel()
-        logger.debug("Defers cancelled.")
-
-    def _register(self, component):
-        """
-        Registers a component in this backend
-
-        :param component: Component to register
-        :type component: any object that implements ILEAPComponent
-        """
-        # TODO: assert that the component implements the interfaces
-        # expected
-        try:
-            self._components[component.key] = component
-        except Exception:
-            logger.error("There was a problem registering %s" % (component,))
-
-    def _signal_back(self, _, signal):
-        """
-        Helper method to signal back (callback like behavior) to the
-        UI that an operation finished.
+        # Component instances creation
+        self._provider = components.Provider(self._signaler, bypass_checks)
+        self._register = components.Register(self._signaler)
+        self._authenticate = components.Authenticate(self._signaler)
+        self._eip = components.EIP(self._signaler)
+        self._soledad = components.Soledad(self._soledad_proxy,
+                                           self._keymanager_proxy,
+                                           self._signaler)
+        self._keymanager = components.Keymanager(self._keymanager_proxy,
+                                                 self._signaler)
+        self._mail = components.Mail(self._soledad_proxy,
+                                     self._keymanager_proxy,
+                                     self._signaler)
 
-        :param signal: signal name
-        :type signal: str
+    def _check_type(self, obj, expected_type):
         """
-        self._signaler.signal(signal)
+        Check the type of a parameter.
 
-    def _worker(self):
+        :param obj: object to check its type.
+        :type obj: any type
+        :param expected_type: the expected type of the object.
+        :type expected_type: type
         """
-        Worker method, called from a different thread and as a part of
-        a looping call
-        """
-        try:
-            # this'll become recv_multipart
-            cmd = self._call_queue.get(block=False)
-
-            # cmd is: component, method, signalback, *args
-            func = getattr(self._components[cmd[0]], cmd[1])
-            d = func(*cmd[3:])
-            if d is not None:  # d may be None if a defer chain is cancelled.
-                # A call might not have a callback signal, but if it does,
-                # we add it to the chain
-                if cmd[2] is not None:
-                    d.addCallbacks(self._signal_back, logger.error, cmd[2])
-                d.addCallbacks(self._done_action, logger.error,
-                               callbackKeywords={"d": d})
-                d.addErrback(logger.error)
-                self._ongoing_defers.append(d)
-        except Empty:
-            # If it's just empty we don't have anything to do.
-            pass
-        except defer.CancelledError:
-            logger.debug("defer cancelled somewhere (CancelledError).")
-        except Exception as e:
-            # But we log the rest
-            logger.exception("Unexpected exception: {0!r}".format(e))
-
-    def _done_action(self, _, d):
-        """
-        Remover of the defer once it's done
-
-        :param d: defer to remove
-        :type d: twisted.internet.defer.Deferred
-        """
-        if d in self._ongoing_defers:
-            self._ongoing_defers.remove(d)
-
-    # XXX: Temporal interface until we migrate to zmq
-    # We simulate the calls to zmq.send_multipart. Once we separate
-    # this in two processes, the methods bellow can be changed to
-    # send_multipart and this backend class will be really simple.
+        if not isinstance(obj, expected_type):
+            raise TypeError("The parameter type is incorrect.")
 
     def provider_setup(self, provider):
         """
@@ -202,13 +84,13 @@ class Backend(object):
             prov_https_connection       -> { PASSED_KEY: bool, ERROR_KEY: str }
             prov_download_provider_info -> { PASSED_KEY: bool, ERROR_KEY: str }
         """
-        self._call_queue.put(("provider", "setup_provider", None, provider))
+        self._provider.setup_provider(provider)
 
     def provider_cancel_setup(self):
         """
         Cancel the ongoing setup provider (if any).
         """
-        self._call_queue.put(("provider", "cancel_setup_provider", None))
+        self._provider.cancel_setup_provider()
 
     def provider_bootstrap(self, provider):
         """
@@ -223,7 +105,7 @@ class Backend(object):
             prov_check_ca_fingerprint  -> {PASSED_KEY: bool, ERROR_KEY: str}
             prov_check_api_certificate -> {PASSED_KEY: bool, ERROR_KEY: str}
         """
-        self._call_queue.put(("provider", "bootstrap", None, provider))
+        self._provider.bootstrap(provider)
 
     def provider_get_supported_services(self, domain):
         """
@@ -235,8 +117,7 @@ class Backend(object):
         Signals:
             prov_get_supported_services -> list of unicode
         """
-        self._call_queue.put(("provider", "get_supported_services", None,
-                              domain))
+        self._provider.get_supported_services(domain)
 
     def provider_get_all_services(self, providers):
         """
@@ -248,13 +129,11 @@ class Backend(object):
         Signals:
             prov_get_all_services -> list of unicode
         """
-        self._call_queue.put(("provider", "get_all_services", None,
-                              providers))
+        self._provider.get_all_services(providers)
 
     def provider_get_details(self, domain, lang):
         """
-        Signal a ProviderConfigLight object with the current ProviderConfig
-        settings.
+        Signal a dict with the current ProviderConfig settings.
 
         :param domain: the domain name of the provider.
         :type domain: str
@@ -262,9 +141,9 @@ class Backend(object):
         :type lang: str
 
         Signals:
-            prov_get_details -> ProviderConfigLight
+            prov_get_details -> dict
         """
-        self._call_queue.put(("provider", "get_details", None, domain, lang))
+        self._provider.get_details(domain, lang)
 
     def provider_get_pinned_providers(self):
         """
@@ -273,7 +152,7 @@ class Backend(object):
         Signals:
             prov_get_pinned_providers -> list of provider domains
         """
-        self._call_queue.put(("provider", "get_pinned_providers", None))
+        self._provider.get_pinned_providers()
 
     def user_register(self, provider, username, password):
         """
@@ -291,8 +170,7 @@ class Backend(object):
             srp_registration_taken
             srp_registration_failed
         """
-        self._call_queue.put(("register", "register_user", None, provider,
-                              username, password))
+        self._register.register_user(provider, username, password)
 
     def eip_setup(self, provider, skip_network=False):
         """
@@ -309,14 +187,13 @@ class Backend(object):
             eip_client_certificate_ready -> {PASSED_KEY: bool, ERROR_KEY: str}
             eip_cancelled_setup
         """
-        self._call_queue.put(("eip", "setup_eip", None, provider,
-                              skip_network))
+        self._eip.setup_eip(provider, skip_network)
 
     def eip_cancel_setup(self):
         """
         Cancel the ongoing setup EIP (if any).
         """
-        self._call_queue.put(("eip", "cancel_setup_eip", None))
+        self._eip.cancel_setup_eip()
 
     def eip_start(self, restart=False):
         """
@@ -343,7 +220,7 @@ class Backend(object):
         :param restart: whether is is a restart.
         :type restart: bool
         """
-        self._call_queue.put(("eip", "start", None, restart))
+        self._eip.start(restart)
 
     def eip_stop(self, shutdown=False, restart=False, failed=False):
         """
@@ -355,13 +232,13 @@ class Backend(object):
         :param restart: whether this is part of a restart.
         :type restart: bool
         """
-        self._call_queue.put(("eip", "stop", None, shutdown, restart))
+        self._eip.stop(shutdown, restart)
 
     def eip_terminate(self):
         """
         Terminate the EIP service, not necessarily in a nice way.
         """
-        self._call_queue.put(("eip", "terminate", None))
+        self._eip.terminate()
 
     def eip_get_gateways_list(self, domain):
         """
@@ -370,16 +247,12 @@ class Backend(object):
         :param domain: the domain to get the gateways.
         :type domain: str
 
-        # TODO discuss how to document the expected result object received of
-        # the signal
-        :signal type: list of str
-
         Signals:
             eip_get_gateways_list -> list of unicode
             eip_get_gateways_list_error
             eip_uninitialized_provider
         """
-        self._call_queue.put(("eip", "get_gateways_list", None, domain))
+        self._eip.get_gateways_list(domain)
 
     def eip_get_initialized_providers(self, domains):
         """
@@ -392,8 +265,7 @@ class Backend(object):
             eip_get_initialized_providers -> list of tuple(unicode, bool)
 
         """
-        self._call_queue.put(("eip", "get_initialized_providers",
-                              None, domains))
+        self._eip.get_initialized_providers(domains)
 
     def eip_can_start(self, domain):
         """
@@ -406,8 +278,7 @@ class Backend(object):
             eip_can_start
             eip_cannot_start
         """
-        self._call_queue.put(("eip", "can_start",
-                              None, domain))
+        self._eip.can_start(domain)
 
     def eip_check_dns(self, domain):
         """
@@ -420,13 +291,13 @@ class Backend(object):
             eip_dns_ok
             eip_dns_error
         """
-        self._call_queue.put(("eip", "check_dns", None, domain))
+        self._eip.check_dns(domain)
 
     def tear_fw_down(self):
         """
         Signal the need to tear the fw down.
         """
-        self._call_queue.put(("eip", "tear_fw_down", None))
+        self._eip.tear_fw_down()
 
     def user_login(self, provider, username, password):
         """
@@ -447,8 +318,7 @@ class Backend(object):
             srp_auth_connection_error
             srp_auth_error
         """
-        self._call_queue.put(("authenticate", "login", None, provider,
-                              username, password))
+        self._authenticate.login(provider, username, password)
 
     def user_logout(self):
         """
@@ -459,13 +329,13 @@ class Backend(object):
             srp_logout_error
             srp_not_logged_in_error
         """
-        self._call_queue.put(("authenticate", "logout", None))
+        self._authenticate.logout()
 
     def user_cancel_login(self):
         """
         Cancel the ongoing login (if any).
         """
-        self._call_queue.put(("authenticate", "cancel_login", None))
+        self._authenticate.cancel_login()
 
     def user_change_password(self, current_password, new_password):
         """
@@ -482,8 +352,7 @@ class Backend(object):
             srp_password_change_badpw
             srp_password_change_error
         """
-        self._call_queue.put(("authenticate", "change_password", None,
-                              current_password, new_password))
+        self._authenticate.change_password(current_password, new_password)
 
     def soledad_change_password(self, new_password):
         """
@@ -498,8 +367,7 @@ class Backend(object):
             srp_password_change_badpw
             srp_password_change_error
         """
-        self._call_queue.put(("soledad", "change_password", None,
-                              new_password))
+        self._soledad.change_password(new_password)
 
     def user_get_logged_in_status(self):
         """
@@ -509,7 +377,7 @@ class Backend(object):
             srp_status_logged_in
             srp_status_not_logged_in
         """
-        self._call_queue.put(("authenticate", "get_logged_in_status", None))
+        self._authenticate.get_logged_in_status()
 
     def soledad_bootstrap(self, username, domain, password):
         """
@@ -527,8 +395,10 @@ class Backend(object):
             soledad_bootstrap_failed
             soledad_invalid_auth_token
         """
-        self._call_queue.put(("soledad", "bootstrap", None,
-                              username, domain, password))
+        self._check_type(username, unicode)
+        self._check_type(domain, unicode)
+        self._check_type(password, unicode)
+        self._soledad.bootstrap(username, domain, password)
 
     def soledad_load_offline(self, username, password, uuid):
         """
@@ -543,20 +413,19 @@ class Backend(object):
 
         Signals:
         """
-        self._call_queue.put(("soledad", "load_offline", None,
-                              username, password, uuid))
+        self._soledad.load_offline(username, password, uuid)
 
     def soledad_cancel_bootstrap(self):
         """
         Cancel the ongoing soledad bootstrapping process (if any).
         """
-        self._call_queue.put(("soledad", "cancel_bootstrap", None))
+        self._soledad.cancel_bootstrap()
 
     def soledad_close(self):
         """
         Close soledad database.
         """
-        self._call_queue.put(("soledad", "close", None))
+        self._soledad.close()
 
     def keymanager_list_keys(self):
         """
@@ -565,7 +434,7 @@ class Backend(object):
         Signals:
             keymanager_keys_list -> list
         """
-        self._call_queue.put(("keymanager", "list_keys", None))
+        self._keymanager.list_keys()
 
     def keymanager_export_keys(self, username, filename):
         """
@@ -580,8 +449,7 @@ class Backend(object):
             keymanager_export_ok
             keymanager_export_error
         """
-        self._call_queue.put(("keymanager", "export_keys", None,
-                              username, filename))
+        self._keymanager.export_keys(username, filename)
 
     def keymanager_get_key_details(self, username):
         """
@@ -593,7 +461,7 @@ class Backend(object):
         Signals:
             keymanager_key_details
         """
-        self._call_queue.put(("keymanager", "get_key_details", None, username))
+        self._keymanager.get_key_details(username)
 
     def smtp_start_service(self, full_user_id, download_if_needed=False):
         """
@@ -605,8 +473,7 @@ class Backend(object):
                                    for the file
         :type download_if_needed: bool
         """
-        self._call_queue.put(("mail", "start_smtp_service", None,
-                              full_user_id, download_if_needed))
+        self._mail.start_smtp_service(full_user_id, download_if_needed)
 
     def imap_start_service(self, full_user_id, offline=False):
         """
@@ -617,14 +484,13 @@ class Backend(object):
         :param offline: whether imap should start in offline mode or not.
         :type offline: bool
         """
-        self._call_queue.put(("mail", "start_imap_service", None,
-                              full_user_id, offline))
+        self._mail.start_imap_service(full_user_id, offline)
 
     def smtp_stop_service(self):
         """
         Stop the SMTP service.
         """
-        self._call_queue.put(("mail", "stop_smtp_service", None))
+        self._mail.stop_smtp_service()
 
     def imap_stop_service(self):
         """
@@ -633,4 +499,12 @@ class Backend(object):
         Signals:
             imap_stopped
         """
-        self._call_queue.put(("mail", "stop_imap_service", None))
+        self._mail.stop_imap_service()
+
+
+def run_backend(bypass_checks=False):
+    # Ensure that the application quits using CTRL-C
+    signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+    backend = LeapBackend(bypass_checks=bypass_checks)
+    backend.run()
diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py
index da8908fd..47df0911 100644
--- a/src/leap/bitmask/backend/leapsignaler.py
+++ b/src/leap/bitmask/backend/leapsignaler.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# components.py
+# leapsignaler.py
 # Copyright (C) 2013 LEAP
 #
 # This program is free software: you can redistribute it and/or modify
@@ -14,372 +14,97 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
-"""
-Signaler for Backend/Frontend communication.
-"""
-import logging
-
 from PySide import QtCore
 
-logger = logging.getLogger(__name__)
+from leap.bitmask.backend.signaler_qt import SignalerQt
 
 
-class Signaler(QtCore.QObject):
+class LeapSignaler(SignalerQt):
     """
-    Signaler object, handles converting string commands to Qt signals.
-
-    This is intended for the separation in frontend/backend, this will
-    live in the frontend.
+    Signaling server subclass, used to defines the API signals.
     """
+    backend_bad_call = QtCore.Signal(object)
 
-    ####################
-    # These will only exist in the frontend
-    # Signals for the ProviderBootstrapper
-    prov_name_resolution = QtCore.Signal(object)
-    prov_https_connection = QtCore.Signal(object)
-    prov_download_provider_info = QtCore.Signal(object)
-
-    prov_download_ca_cert = QtCore.Signal(object)
-    prov_check_ca_fingerprint = QtCore.Signal(object)
-    prov_check_api_certificate = QtCore.Signal(object)
-
-    prov_problem_with_provider = QtCore.Signal(object)
-
-    prov_unsupported_client = QtCore.Signal(object)
-    prov_unsupported_api = QtCore.Signal(object)
-
-    prov_get_all_services = QtCore.Signal(object)
-    prov_get_supported_services = QtCore.Signal(object)
-    prov_get_details = QtCore.Signal(object)
-    prov_get_pinned_providers = QtCore.Signal(object)
-
-    prov_cancelled_setup = QtCore.Signal(object)
-
-    # Signals for SRPRegister
-    srp_registration_finished = QtCore.Signal(object)
-    srp_registration_failed = QtCore.Signal(object)
-    srp_registration_taken = QtCore.Signal(object)
-
-    # Signals for EIP bootstrapping
-    eip_config_ready = QtCore.Signal(object)
+    eip_alien_openvpn_already_running = QtCore.Signal()
+    eip_can_start = QtCore.Signal()
+    eip_cancelled_setup = QtCore.Signal()
+    eip_cannot_start = QtCore.Signal()
     eip_client_certificate_ready = QtCore.Signal(object)
-
-    eip_cancelled_setup = QtCore.Signal(object)
-
-    # Signals for SRPAuth
-    srp_auth_ok = QtCore.Signal(object)
-    srp_auth_error = QtCore.Signal(object)
-    srp_auth_server_error = QtCore.Signal(object)
-    srp_auth_connection_error = QtCore.Signal(object)
-    srp_auth_bad_user_or_password = QtCore.Signal(object)
-    srp_logout_ok = QtCore.Signal(object)
-    srp_logout_error = QtCore.Signal(object)
-    srp_password_change_ok = QtCore.Signal(object)
-    srp_password_change_error = QtCore.Signal(object)
-    srp_password_change_badpw = QtCore.Signal(object)
-    srp_not_logged_in_error = QtCore.Signal(object)
-    srp_status_logged_in = QtCore.Signal(object)
-    srp_status_not_logged_in = QtCore.Signal(object)
-
-    # Signals for EIP
-    eip_connected = QtCore.Signal(object)
-    eip_disconnected = QtCore.Signal(object)
+    eip_config_ready = QtCore.Signal(object)
+    eip_connected = QtCore.Signal()
+    eip_connection_aborted = QtCore.Signal()
     eip_connection_died = QtCore.Signal(object)
-    eip_connection_aborted = QtCore.Signal(object)
-    eip_stopped = QtCore.Signal(object)
-
-    eip_dns_ok = QtCore.Signal(object)
-    eip_dns_error = QtCore.Signal(object)
-
-    # EIP problems
-    eip_no_polkit_agent_error = QtCore.Signal(object)
-    eip_no_tun_kext_error = QtCore.Signal(object)
-    eip_no_pkexec_error = QtCore.Signal(object)
-    eip_openvpn_not_found_error = QtCore.Signal(object)
-    eip_openvpn_already_running = QtCore.Signal(object)
-    eip_alien_openvpn_already_running = QtCore.Signal(object)
-    eip_vpn_launcher_exception = QtCore.Signal(object)
-
+    eip_disconnected = QtCore.Signal(object)
+    eip_dns_error = QtCore.Signal()
+    eip_dns_ok = QtCore.Signal()
     eip_get_gateways_list = QtCore.Signal(object)
-    eip_get_gateways_list_error = QtCore.Signal(object)
-    eip_uninitialized_provider = QtCore.Signal(object)
+    eip_get_gateways_list_error = QtCore.Signal()
     eip_get_initialized_providers = QtCore.Signal(object)
-
-    # signals from parsing openvpn output
-    eip_network_unreachable = QtCore.Signal(object)
-    eip_process_restart_tls = QtCore.Signal(object)
-    eip_process_restart_ping = QtCore.Signal(object)
-
-    # signals from vpnprocess.py
+    eip_network_unreachable = QtCore.Signal()
+    eip_no_pkexec_error = QtCore.Signal()
+    eip_no_polkit_agent_error = QtCore.Signal()
+    eip_no_tun_kext_error = QtCore.Signal()
+    eip_openvpn_already_running = QtCore.Signal()
+    eip_openvpn_not_found_error = QtCore.Signal()
+    eip_process_finished = QtCore.Signal(int)
+    eip_process_restart_ping = QtCore.Signal()
+    eip_process_restart_tls = QtCore.Signal()
     eip_state_changed = QtCore.Signal(dict)
     eip_status_changed = QtCore.Signal(dict)
-    eip_process_finished = QtCore.Signal(int)
+    eip_stopped = QtCore.Signal()
     eip_tear_fw_down = QtCore.Signal(object)
-
-    # signals whether the needed files to start EIP exist or not
-    eip_can_start = QtCore.Signal(object)
-    eip_cannot_start = QtCore.Signal(object)
-
-    # Signals for Soledad
-    soledad_bootstrap_failed = QtCore.Signal(object)
-    soledad_bootstrap_finished = QtCore.Signal(object)
-    soledad_offline_failed = QtCore.Signal(object)
-    soledad_offline_finished = QtCore.Signal(object)
-    soledad_invalid_auth_token = QtCore.Signal(object)
-    soledad_cancelled_bootstrap = QtCore.Signal(object)
-    soledad_password_change_ok = QtCore.Signal(object)
-    soledad_password_change_error = QtCore.Signal(object)
-
-    # Keymanager signals
-    keymanager_export_ok = QtCore.Signal(object)
-    keymanager_export_error = QtCore.Signal(object)
-    keymanager_keys_list = QtCore.Signal(object)
-
-    keymanager_import_ioerror = QtCore.Signal(object)
-    keymanager_import_datamismatch = QtCore.Signal(object)
-    keymanager_import_missingkey = QtCore.Signal(object)
-    keymanager_import_addressmismatch = QtCore.Signal(object)
-    keymanager_import_ok = QtCore.Signal(object)
-
+    eip_uninitialized_provider = QtCore.Signal()
+    eip_vpn_launcher_exception = QtCore.Signal()
+
+    imap_stopped = QtCore.Signal()
+
+    keymanager_export_error = QtCore.Signal()
+    keymanager_export_ok = QtCore.Signal()
+    keymanager_import_addressmismatch = QtCore.Signal()
+    keymanager_import_datamismatch = QtCore.Signal()
+    keymanager_import_ioerror = QtCore.Signal()
+    keymanager_import_missingkey = QtCore.Signal()
+    keymanager_import_ok = QtCore.Signal()
     keymanager_key_details = QtCore.Signal(object)
+    keymanager_keys_list = QtCore.Signal(object)
 
-    # mail related signals
-    imap_stopped = QtCore.Signal(object)
-
-    # This signal is used to warn the backend user that is doing something
-    # wrong
-    backend_bad_call = QtCore.Signal(object)
-
-    ####################
-    # These will exist both in the backend AND the front end.
-    # The frontend might choose to not "interpret" all the signals
-    # from the backend, but the backend needs to have all the signals
-    # it's going to emit defined here
-    PROV_NAME_RESOLUTION_KEY = "prov_name_resolution"
-    PROV_HTTPS_CONNECTION_KEY = "prov_https_connection"
-    PROV_DOWNLOAD_PROVIDER_INFO_KEY = "prov_download_provider_info"
-    PROV_DOWNLOAD_CA_CERT_KEY = "prov_download_ca_cert"
-    PROV_CHECK_CA_FINGERPRINT_KEY = "prov_check_ca_fingerprint"
-    PROV_CHECK_API_CERTIFICATE_KEY = "prov_check_api_certificate"
-    PROV_PROBLEM_WITH_PROVIDER_KEY = "prov_problem_with_provider"
-    PROV_UNSUPPORTED_CLIENT = "prov_unsupported_client"
-    PROV_UNSUPPORTED_API = "prov_unsupported_api"
-    PROV_CANCELLED_SETUP = "prov_cancelled_setup"
-    PROV_GET_ALL_SERVICES = "prov_get_all_services"
-    PROV_GET_SUPPORTED_SERVICES = "prov_get_supported_services"
-    PROV_GET_DETAILS = "prov_get_details"
-    PROV_GET_PINNED_PROVIDERS = "prov_get_pinned_providers"
-
-    SRP_REGISTRATION_FINISHED = "srp_registration_finished"
-    SRP_REGISTRATION_FAILED = "srp_registration_failed"
-    SRP_REGISTRATION_TAKEN = "srp_registration_taken"
-    SRP_AUTH_OK = "srp_auth_ok"
-    SRP_AUTH_ERROR = "srp_auth_error"
-    SRP_AUTH_SERVER_ERROR = "srp_auth_server_error"
-    SRP_AUTH_CONNECTION_ERROR = "srp_auth_connection_error"
-    SRP_AUTH_BAD_USER_OR_PASSWORD = "srp_auth_bad_user_or_password"
-    SRP_LOGOUT_OK = "srp_logout_ok"
-    SRP_LOGOUT_ERROR = "srp_logout_error"
-    SRP_PASSWORD_CHANGE_OK = "srp_password_change_ok"
-    SRP_PASSWORD_CHANGE_ERROR = "srp_password_change_error"
-    SRP_PASSWORD_CHANGE_BADPW = "srp_password_change_badpw"
-    SRP_NOT_LOGGED_IN_ERROR = "srp_not_logged_in_error"
-    SRP_STATUS_LOGGED_IN = "srp_status_logged_in"
-    SRP_STATUS_NOT_LOGGED_IN = "srp_status_not_logged_in"
-
-    EIP_CONFIG_READY = "eip_config_ready"
-    EIP_CLIENT_CERTIFICATE_READY = "eip_client_certificate_ready"
-    EIP_CANCELLED_SETUP = "eip_cancelled_setup"
-
-    EIP_CONNECTED = "eip_connected"
-    EIP_DISCONNECTED = "eip_disconnected"
-    EIP_CONNECTION_DIED = "eip_connection_died"
-    EIP_CONNECTION_ABORTED = "eip_connection_aborted"
-    EIP_STOPPED = "eip_stopped"
-
-    EIP_NO_POLKIT_AGENT_ERROR = "eip_no_polkit_agent_error"
-    EIP_NO_TUN_KEXT_ERROR = "eip_no_tun_kext_error"
-    EIP_NO_PKEXEC_ERROR = "eip_no_pkexec_error"
-    EIP_OPENVPN_NOT_FOUND_ERROR = "eip_openvpn_not_found_error"
-    EIP_OPENVPN_ALREADY_RUNNING = "eip_openvpn_already_running"
-    EIP_ALIEN_OPENVPN_ALREADY_RUNNING = "eip_alien_openvpn_already_running"
-    EIP_VPN_LAUNCHER_EXCEPTION = "eip_vpn_launcher_exception"
-
-    EIP_GET_GATEWAYS_LIST = "eip_get_gateways_list"
-    EIP_GET_GATEWAYS_LIST_ERROR = "eip_get_gateways_list_error"
-    EIP_UNINITIALIZED_PROVIDER = "eip_uninitialized_provider"
-    EIP_GET_INITIALIZED_PROVIDERS = "eip_get_initialized_providers"
-
-    EIP_NETWORK_UNREACHABLE = "eip_network_unreachable"
-    EIP_PROCESS_RESTART_TLS = "eip_process_restart_tls"
-    EIP_PROCESS_RESTART_PING = "eip_process_restart_ping"
-
-    EIP_STATE_CHANGED = "eip_state_changed"
-    EIP_STATUS_CHANGED = "eip_status_changed"
-    EIP_PROCESS_FINISHED = "eip_process_finished"
-    EIP_TEAR_FW_DOWN = "eip_tear_fw_down"
-
-    EIP_CAN_START = "eip_can_start"
-    EIP_CANNOT_START = "eip_cannot_start"
-
-    EIP_DNS_OK = "eip_dns_ok"
-    EIP_DNS_ERROR = "eip_dns_error"
-
-    SOLEDAD_BOOTSTRAP_FAILED = "soledad_bootstrap_failed"
-    SOLEDAD_BOOTSTRAP_FINISHED = "soledad_bootstrap_finished"
-    SOLEDAD_OFFLINE_FAILED = "soledad_offline_failed"
-    SOLEDAD_OFFLINE_FINISHED = "soledad_offline_finished"
-    SOLEDAD_INVALID_AUTH_TOKEN = "soledad_invalid_auth_token"
-
-    SOLEDAD_PASSWORD_CHANGE_OK = "soledad_password_change_ok"
-    SOLEDAD_PASSWORD_CHANGE_ERROR = "soledad_password_change_error"
-
-    SOLEDAD_CANCELLED_BOOTSTRAP = "soledad_cancelled_bootstrap"
-
-    KEYMANAGER_EXPORT_OK = "keymanager_export_ok"
-    KEYMANAGER_EXPORT_ERROR = "keymanager_export_error"
-    KEYMANAGER_KEYS_LIST = "keymanager_keys_list"
-
-    KEYMANAGER_IMPORT_IOERROR = "keymanager_import_ioerror"
-    KEYMANAGER_IMPORT_DATAMISMATCH = "keymanager_import_datamismatch"
-    KEYMANAGER_IMPORT_MISSINGKEY = "keymanager_import_missingkey"
-    KEYMANAGER_IMPORT_ADDRESSMISMATCH = "keymanager_import_addressmismatch"
-    KEYMANAGER_IMPORT_OK = "keymanager_import_ok"
-    KEYMANAGER_KEY_DETAILS = "keymanager_key_details"
-
-    IMAP_STOPPED = "imap_stopped"
-
-    BACKEND_BAD_CALL = "backend_bad_call"
-
-    def __init__(self):
-        """
-        Constructor for the Signaler
-        """
-        QtCore.QObject.__init__(self)
-        self._signals = {}
-
-        signals = [
-            self.PROV_NAME_RESOLUTION_KEY,
-            self.PROV_HTTPS_CONNECTION_KEY,
-            self.PROV_DOWNLOAD_PROVIDER_INFO_KEY,
-            self.PROV_DOWNLOAD_CA_CERT_KEY,
-            self.PROV_CHECK_CA_FINGERPRINT_KEY,
-            self.PROV_CHECK_API_CERTIFICATE_KEY,
-            self.PROV_PROBLEM_WITH_PROVIDER_KEY,
-            self.PROV_UNSUPPORTED_CLIENT,
-            self.PROV_UNSUPPORTED_API,
-            self.PROV_CANCELLED_SETUP,
-            self.PROV_GET_ALL_SERVICES,
-            self.PROV_GET_SUPPORTED_SERVICES,
-            self.PROV_GET_DETAILS,
-            self.PROV_GET_PINNED_PROVIDERS,
-
-            self.SRP_REGISTRATION_FINISHED,
-            self.SRP_REGISTRATION_FAILED,
-            self.SRP_REGISTRATION_TAKEN,
-
-            self.EIP_CONFIG_READY,
-            self.EIP_CLIENT_CERTIFICATE_READY,
-            self.EIP_CANCELLED_SETUP,
-
-            self.EIP_CONNECTED,
-            self.EIP_DISCONNECTED,
-            self.EIP_CONNECTION_DIED,
-            self.EIP_CONNECTION_ABORTED,
-            self.EIP_STOPPED,
-
-            self.EIP_NO_POLKIT_AGENT_ERROR,
-            self.EIP_NO_TUN_KEXT_ERROR,
-            self.EIP_NO_PKEXEC_ERROR,
-            self.EIP_OPENVPN_NOT_FOUND_ERROR,
-            self.EIP_OPENVPN_ALREADY_RUNNING,
-            self.EIP_ALIEN_OPENVPN_ALREADY_RUNNING,
-            self.EIP_VPN_LAUNCHER_EXCEPTION,
-
-            self.EIP_GET_GATEWAYS_LIST,
-            self.EIP_GET_GATEWAYS_LIST_ERROR,
-            self.EIP_UNINITIALIZED_PROVIDER,
-            self.EIP_GET_INITIALIZED_PROVIDERS,
-
-            self.EIP_NETWORK_UNREACHABLE,
-            self.EIP_PROCESS_RESTART_TLS,
-            self.EIP_PROCESS_RESTART_PING,
-
-            self.EIP_STATE_CHANGED,
-            self.EIP_STATUS_CHANGED,
-            self.EIP_PROCESS_FINISHED,
-
-            self.EIP_CAN_START,
-            self.EIP_CANNOT_START,
-
-            self.EIP_DNS_OK,
-            self.EIP_DNS_ERROR,
-
-            self.SRP_AUTH_OK,
-            self.SRP_AUTH_ERROR,
-            self.SRP_AUTH_SERVER_ERROR,
-            self.SRP_AUTH_CONNECTION_ERROR,
-            self.SRP_AUTH_BAD_USER_OR_PASSWORD,
-            self.SRP_LOGOUT_OK,
-            self.SRP_LOGOUT_ERROR,
-            self.SRP_PASSWORD_CHANGE_OK,
-            self.SRP_PASSWORD_CHANGE_ERROR,
-            self.SRP_PASSWORD_CHANGE_BADPW,
-            self.SRP_NOT_LOGGED_IN_ERROR,
-            self.SRP_STATUS_LOGGED_IN,
-            self.SRP_STATUS_NOT_LOGGED_IN,
-
-            self.SOLEDAD_BOOTSTRAP_FAILED,
-            self.SOLEDAD_BOOTSTRAP_FINISHED,
-            self.SOLEDAD_OFFLINE_FAILED,
-            self.SOLEDAD_OFFLINE_FINISHED,
-            self.SOLEDAD_INVALID_AUTH_TOKEN,
-            self.SOLEDAD_CANCELLED_BOOTSTRAP,
-
-            self.SOLEDAD_PASSWORD_CHANGE_OK,
-            self.SOLEDAD_PASSWORD_CHANGE_ERROR,
-
-            self.KEYMANAGER_EXPORT_OK,
-            self.KEYMANAGER_EXPORT_ERROR,
-            self.KEYMANAGER_KEYS_LIST,
-
-            self.KEYMANAGER_IMPORT_IOERROR,
-            self.KEYMANAGER_IMPORT_DATAMISMATCH,
-            self.KEYMANAGER_IMPORT_MISSINGKEY,
-            self.KEYMANAGER_IMPORT_ADDRESSMISMATCH,
-            self.KEYMANAGER_IMPORT_OK,
-            self.KEYMANAGER_KEY_DETAILS,
-
-            self.IMAP_STOPPED,
-
-            self.BACKEND_BAD_CALL,
-        ]
-
-        for sig in signals:
-            self._signals[sig] = getattr(self, sig)
-
-    def signal(self, key, data=None):
-        """
-        Emits a Qt signal based on the key provided, with the data if provided.
-
-        :param key: string identifying the signal to emit
-        :type key: str
-        :param data: object to send with the data
-        :type data: object
-
-        NOTE: The data object will be a serialized str in the backend,
-        and an unserialized object in the frontend, but for now we
-        just care about objects.
-        """
-        # Right now it emits Qt signals. The backend version of this
-        # will do zmq.send_multipart, and the frontend version will be
-        # similar to this
-
-        # for some reason emitting 'None' gives a segmentation fault.
-        if data is None:
-            data = ''
-
-        try:
-            self._signals[key].emit(data)
-        except KeyError:
-            logger.error("Unknown key for signal %s!" % (key,))
+    prov_cancelled_setup = QtCore.Signal()
+    prov_check_api_certificate = QtCore.Signal(object)
+    prov_check_ca_fingerprint = QtCore.Signal(object)
+    prov_download_ca_cert = QtCore.Signal(object)
+    prov_download_provider_info = QtCore.Signal(object)
+    prov_get_all_services = QtCore.Signal(object)
+    prov_get_details = QtCore.Signal(object)
+    prov_get_pinned_providers = QtCore.Signal(object)
+    prov_get_supported_services = QtCore.Signal(object)
+    prov_https_connection = QtCore.Signal(object)
+    prov_name_resolution = QtCore.Signal(object)
+    prov_problem_with_provider = QtCore.Signal()
+    prov_unsupported_api = QtCore.Signal()
+    prov_unsupported_client = QtCore.Signal()
+
+    soledad_bootstrap_failed = QtCore.Signal()
+    soledad_bootstrap_finished = QtCore.Signal()
+    soledad_cancelled_bootstrap = QtCore.Signal()
+    soledad_invalid_auth_token = QtCore.Signal()
+    soledad_offline_failed = QtCore.Signal()
+    soledad_offline_finished = QtCore.Signal()
+    soledad_password_change_error = QtCore.Signal()
+    soledad_password_change_ok = QtCore.Signal()
+
+    srp_auth_bad_user_or_password = QtCore.Signal()
+    srp_auth_connection_error = QtCore.Signal()
+    srp_auth_error = QtCore.Signal()
+    srp_auth_ok = QtCore.Signal()
+    srp_auth_server_error = QtCore.Signal()
+    srp_logout_error = QtCore.Signal()
+    srp_logout_ok = QtCore.Signal()
+    srp_not_logged_in_error = QtCore.Signal()
+    srp_password_change_badpw = QtCore.Signal()
+    srp_password_change_error = QtCore.Signal()
+    srp_password_change_ok = QtCore.Signal()
+    srp_registration_failed = QtCore.Signal()
+    srp_registration_finished = QtCore.Signal()
+    srp_registration_taken = QtCore.Signal()
+    srp_status_logged_in = QtCore.Signal()
+    srp_status_not_logged_in = QtCore.Signal()
-- 
cgit v1.2.3


From 6dbd52e2f0d75ad9bf7c2f11e3384d8bab0520c9 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 18 Jun 2014 12:37:23 -0300
Subject: Use new backend/signaler and start logic in processes.

---
 src/leap/bitmask/app.py                       | 15 +++++++--
 src/leap/bitmask/frontend_app.py              |  5 +--
 src/leap/bitmask/gui/eip_preferenceswindow.py |  5 +--
 src/leap/bitmask/gui/eip_status.py            |  6 ++--
 src/leap/bitmask/gui/mainwindow.py            | 45 ++++++++++++++-------------
 src/leap/bitmask/gui/preferenceswindow.py     |  6 ++--
 src/leap/bitmask/gui/wizard.py                | 10 +++---
 src/leap/bitmask/services/eip/conductor.py    |  5 +--
 8 files changed, 54 insertions(+), 43 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index f1d87d18..9afe41be 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -43,9 +43,12 @@ import multiprocessing
 import os
 import sys
 
+from leap.bitmask.backend.utils import generate_certificates
+
 from leap.bitmask import __version__ as VERSION
 from leap.bitmask.config import flags
 from leap.bitmask.frontend_app import run_frontend
+from leap.bitmask.backend.leapbackend import run_backend
 from leap.bitmask.logs.utils import create_logger
 from leap.bitmask.platform_init.locks import we_are_the_one_and_only
 from leap.bitmask.services.mail import plumber
@@ -114,7 +117,6 @@ def start_app():
     do_display_version(opts)
 
     options = {
-        'bypass_checks': opts.danger,
         'start_hidden': opts.start_hidden,
         'debug': opts.debug,
         'log_file': opts.log_file,
@@ -170,8 +172,15 @@ def start_app():
 
     logger.info('Starting app')
 
-    frontend = multiprocessing.Process(target=run_frontend, args=(options, ))
-    frontend.start()
+    generate_certificates()
+
+    app = lambda: run_frontend(options=options)
+    gui_process = multiprocessing.Process(target=app)
+    gui_process.start()
+
+    backend = lambda: run_backend(bypass_checks=opts.danger)
+    backend_process = multiprocessing.Process(target=backend)
+    backend_process.start()
 
 
 if __name__ == "__main__":
diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py
index ed67a77a..12703518 100644
--- a/src/leap/bitmask/frontend_app.py
+++ b/src/leap/bitmask/frontend_app.py
@@ -25,7 +25,6 @@ from PySide import QtCore, QtGui
 from leap.bitmask.config import flags
 from leap.bitmask.gui import locale_rc  # noqa - silence pylint
 from leap.bitmask.gui.mainwindow import MainWindow
-# from leap.bitmask.logs.utils import create_logger
 
 import logging
 logger = logging.getLogger(__name__)
@@ -61,7 +60,6 @@ def run_frontend(options):
     :param options: a dict of options parsed from the command line.
     :type options: dict
     """
-    bypass_checks = options["bypass_checks"]
     start_hidden = options["start_hidden"]
 
     # We force the style if on KDE so that it doesn't load all the kde
@@ -90,8 +88,7 @@ def run_frontend(options):
     qApp.setApplicationName("leap")
     qApp.setOrganizationDomain("leap.se")
 
-    window = MainWindow(bypass_checks=bypass_checks,
-                        start_hidden=start_hidden)
+    window = MainWindow(start_hidden=start_hidden)
 
     sigint_window = partial(sigint_handler, window, logger=logger)
     signal.signal(signal.SIGINT, sigint_window)
diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py
index 530cd38d..caf663b1 100644
--- a/src/leap/bitmask/gui/eip_preferenceswindow.py
+++ b/src/leap/bitmask/gui/eip_preferenceswindow.py
@@ -33,7 +33,7 @@ class EIPPreferencesWindow(QtGui.QDialog):
     """
     Window that displays the EIP preferences.
     """
-    def __init__(self, parent, domain, backend):
+    def __init__(self, parent, domain, backend, leap_signaler):
         """
         :param parent: parent object of the EIPPreferencesWindow.
         :type parent: QWidget
@@ -46,6 +46,7 @@ class EIPPreferencesWindow(QtGui.QDialog):
         self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic")
 
         self._settings = LeapSettings()
+        self._leap_signaler = leap_signaler
         self._backend = backend
 
         # Load UI
@@ -248,7 +249,7 @@ class EIPPreferencesWindow(QtGui.QDialog):
         self.ui.cbGateways.setEnabled(False)
 
     def _backend_connect(self):
-        sig = self._backend.signaler
+        sig = self._leap_signaler
         sig.eip_get_gateways_list.connect(self._update_gateways_list)
         sig.eip_get_gateways_list_error.connect(self._gateways_list_error)
         sig.eip_uninitialized_provider.connect(
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
index bd569343..01966d82 100644
--- a/src/leap/bitmask/gui/eip_status.py
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -44,7 +44,7 @@ class EIPStatusWidget(QtGui.QWidget):
     RATE_STR = "%1.2f KB/s"
     TOTAL_STR = "%1.2f Kb"
 
-    def __init__(self, parent=None, eip_conductor=None):
+    def __init__(self, parent, eip_conductor, leap_signaler):
         """
         :param parent: the parent of the widget.
         :type parent: QObject
@@ -60,6 +60,8 @@ class EIPStatusWidget(QtGui.QWidget):
         self.ui = Ui_EIPStatus()
         self.ui.setupUi(self)
 
+        self._leap_signaler = leap_signaler
+
         self.eip_conductor = eip_conductor
         self.eipconnection = eip_conductor.eip_connection
 
@@ -98,7 +100,7 @@ class EIPStatusWidget(QtGui.QWidget):
         """
         Connect backend signals.
         """
-        signaler = self.eip_conductor._backend.signaler
+        signaler = self._leap_signaler
 
         signaler.eip_openvpn_already_running.connect(
             self._on_eip_openvpn_already_running)
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index e53ab7f3..4b5d1c83 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -43,7 +43,8 @@ from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX
 from leap.bitmask.platform_init.initializers import init_platform
 from leap.bitmask.platform_init.initializers import init_signals
 
-from leap.bitmask.backend import leapbackend
+from leap.bitmask.backend.backend_proxy import BackendProxy
+from leap.bitmask.backend.leapsignaler import LeapSignaler
 
 from leap.bitmask.services.eip import conductor as eip_conductor
 from leap.bitmask.services.mail import conductor as mail_conductor
@@ -91,13 +92,10 @@ 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, bypass_checks=False, start_hidden=False):
+    def __init__(self, start_hidden=False):
         """
         Constructor for the client main window
 
-        :param bypass_checks: Set to true if the app should bypass first round
-                              of checks for CA certificates at bootstrap
-        :type bypass_checks: bool
         :param start_hidden: Set to true if the app should not show the window
                              but just the tray.
         :type start_hidden: bool
@@ -119,15 +117,16 @@ class MainWindow(QtGui.QMainWindow):
         self.ui = Ui_MainWindow()
         self.ui.setupUi(self)
         self.menuBar().setNativeMenuBar(not IS_LINUX)
-        self._backend = leapbackend.Backend(bypass_checks)
-        self._backend.start()
+
+        self._backend = BackendProxy()
+
+        self._leap_signaler = LeapSignaler()
+        self._leap_signaler.start()
 
         self._settings = LeapSettings()
 
         # Login Widget
-        self._login_widget = LoginWidget(
-            self._settings,
-            self)
+        self._login_widget = LoginWidget(self._settings, self)
         self.ui.loginLayout.addWidget(self._login_widget)
 
         # Mail Widget
@@ -144,8 +143,9 @@ class MainWindow(QtGui.QMainWindow):
 
         # EIP Control redux #########################################
         self._eip_conductor = eip_conductor.EIPConductor(
-            self._settings, self._backend)
-        self._eip_status = EIPStatusWidget(self, self._eip_conductor)
+            self._settings, self._backend, self._leap_signaler)
+        self._eip_status = EIPStatusWidget(self, self._eip_conductor,
+                                           self._leap_signaler)
 
         init_signals.eip_missing_helpers.connect(
             self._disable_eip_missing_helpers)
@@ -258,7 +258,6 @@ class MainWindow(QtGui.QMainWindow):
 
         self._logger_window = None
 
-        self._bypass_checks = bypass_checks
         self._start_hidden = start_hidden
 
         self._mail_conductor = mail_conductor.MailConductor(self._backend)
@@ -283,7 +282,7 @@ class MainWindow(QtGui.QMainWindow):
             self._wizard_firstrun = True
             self._disconnect_and_untrack()
             self._wizard = Wizard(backend=self._backend,
-                                  bypass_checks=bypass_checks)
+                                  leap_signaler=self._leap_signaler)
             # Give this window time to finish init and then show the wizard
             QtDelayedCall(1, self._launch_wizard)
             self._wizard.accepted.connect(self._finish_init)
@@ -342,7 +341,7 @@ class MainWindow(QtGui.QMainWindow):
                              that we are tracking to disconnect later.
         :type only_tracked: bool
         """
-        sig = self._backend.signaler
+        sig = self._leap_signaler
         conntrack = self._connect_and_track
         auth_err = self._authentication_error
 
@@ -480,7 +479,7 @@ class MainWindow(QtGui.QMainWindow):
         if self._wizard is None:
             self._disconnect_and_untrack()
             self._wizard = Wizard(backend=self._backend,
-                                  bypass_checks=self._bypass_checks)
+                                  leap_signaler=self._leap_signaler)
             self._wizard.accepted.connect(self._finish_init)
             self._wizard.rejected.connect(self._rejected_wizard)
 
@@ -575,7 +574,8 @@ class MainWindow(QtGui.QMainWindow):
         if self._provider_details is not None:
             mx_provided = MX_SERVICE in self._provider_details['services']
         preferences = PreferencesWindow(self, user, domain, self._backend,
-                                        self._soledad_started, mx_provided)
+                                        self._soledad_started, mx_provided,
+                                        self._leap_signaler)
 
         self.soledad_ready.connect(preferences.set_soledad_ready)
         preferences.show()
@@ -686,7 +686,9 @@ class MainWindow(QtGui.QMainWindow):
         Displays the EIP preferences window.
         """
         domain = self._login_widget.get_selected_provider()
-        EIPPreferencesWindow(self, domain, self._backend).show()
+        pref = EIPPreferencesWindow(self, domain,
+                                    self._backend, self._leap_signaler)
+        pref.show()
 
     #
     # updates
@@ -1277,7 +1279,7 @@ class MainWindow(QtGui.QMainWindow):
         if MX_SERVICE in self._enabled_services:
             btn_enabled = self._login_widget.set_logout_btn_enabled
             btn_enabled(False)
-            sig = self._backend.signaler
+            sig = self._leap_signaler
             sig.soledad_bootstrap_failed.connect(lambda: btn_enabled(True))
             sig.soledad_bootstrap_finished.connect(lambda: btn_enabled(True))
 
@@ -1711,10 +1713,10 @@ class MainWindow(QtGui.QMainWindow):
         self._services_being_stopped = set(('imap', 'eip'))
 
         imap_stopped = lambda: self._remove_service('imap')
-        self._backend.signaler.imap_stopped.connect(imap_stopped)
+        self._leap_signaler.imap_stopped.connect(imap_stopped)
 
         eip_stopped = lambda: self._remove_service('eip')
-        self._backend.signaler.eip_stopped.connect(eip_stopped)
+        self._leap_signaler.eip_stopped.connect(eip_stopped)
 
         logger.debug('Stopping mail services')
         self._backend.imap_stop_service()
@@ -1804,7 +1806,6 @@ class MainWindow(QtGui.QMainWindow):
         if IS_WIN:
             WindowsLock.release_all_locks()
 
-        self._backend.stop()
         self.close()
 
         QtDelayedCall(100, twisted_main.quit)
diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py
index a3b81d38..8cf8752e 100644
--- a/src/leap/bitmask/gui/preferenceswindow.py
+++ b/src/leap/bitmask/gui/preferenceswindow.py
@@ -38,7 +38,8 @@ class PreferencesWindow(QtGui.QDialog):
     """
     preferences_saved = QtCore.Signal()
 
-    def __init__(self, parent, username, domain, backend, soledad_started, mx):
+    def __init__(self, parent, username, domain, backend, soledad_started, mx,
+                 leap_signaler):
         """
         :param parent: parent object of the PreferencesWindow.
         :parent type: QWidget
@@ -58,6 +59,7 @@ class PreferencesWindow(QtGui.QDialog):
 
         self._username = username
         self._domain = domain
+        self._leap_signaler = leap_signaler
         self._backend = backend
         self._soledad_started = soledad_started
         self._mx_provided = mx
@@ -423,7 +425,7 @@ class PreferencesWindow(QtGui.QDialog):
         """
         Helper to connect to backend signals
         """
-        sig = self._backend.signaler
+        sig = self._leap_signaler
 
         sig.prov_get_supported_services.connect(self._load_services)
 
diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py
index 4f67958f..79cccc44 100644
--- a/src/leap/bitmask/gui/wizard.py
+++ b/src/leap/bitmask/gui/wizard.py
@@ -49,16 +49,12 @@ class Wizard(QtGui.QWizard):
     REGISTER_USER_PAGE = 4
     SERVICES_PAGE = 5
 
-    def __init__(self, backend, bypass_checks=False):
+    def __init__(self, backend, leap_signaler):
         """
         Constructor for the main Wizard.
 
         :param backend: Backend being used
         :type backend: Backend
-        :param bypass_checks: Set to true if the app should bypass
-                              first round of checks for CA
-                              certificates at bootstrap
-        :type bypass_checks: bool
         """
         QtGui.QWizard.__init__(self)
 
@@ -86,6 +82,8 @@ class Wizard(QtGui.QWizard):
         self._connect_and_track(self.ui.lnProvider.returnPressed,
                                 self._check_provider)
 
+        self._leap_signaler = leap_signaler
+
         self._backend = backend
         self._backend_connect()
 
@@ -789,7 +787,7 @@ class Wizard(QtGui.QWizard):
         """
         Connects all the backend signals with the wizard.
         """
-        sig = self._backend.signaler
+        sig = self._leap_signaler
         conntrack = self._connect_and_track
         conntrack(sig.prov_name_resolution, self._name_resolution)
         conntrack(sig.prov_https_connection, self._https_connection)
diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py
index a8821160..dfd27f3d 100644
--- a/src/leap/bitmask/services/eip/conductor.py
+++ b/src/leap/bitmask/services/eip/conductor.py
@@ -33,7 +33,7 @@ logger = logging.getLogger(__name__)
 
 class EIPConductor(object):
 
-    def __init__(self, settings, backend, **kwargs):
+    def __init__(self, settings, backend, leap_signaler, **kwargs):
         """
         Initializes EIP Conductor.
 
@@ -46,6 +46,7 @@ class EIPConductor(object):
         self.eip_connection = EIPConnection()
         self.eip_name = get_service_display_name(EIP_SERVICE)
         self._settings = settings
+        self._leap_signaler = leap_signaler
         self._backend = backend
 
         self._eip_status = None
@@ -76,7 +77,7 @@ class EIPConductor(object):
         """
         Connect to backend signals.
         """
-        signaler = self._backend.signaler
+        signaler = self._leap_signaler
 
         # for conductor
         signaler.eip_process_restart_tls.connect(self._do_eip_restart)
-- 
cgit v1.2.3


From 5b34d32682188f4849a1e2a4aa8cf8b4c900b8d8 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 25 Jun 2014 12:35:04 -0300
Subject: Properly stop backend.

---
 src/leap/bitmask/gui/mainwindow.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 4b5d1c83..9b6dc8bd 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -18,6 +18,7 @@
 Main window for Bitmask.
 """
 import logging
+import time
 
 from datetime import datetime
 
@@ -1788,7 +1789,6 @@ class MainWindow(QtGui.QMainWindow):
         Final steps to quit the app, starting from here we don't care about
         running services or user interaction, just quitting.
         """
-
         # We can reach here because all the services are stopped or because a
         # timeout was triggered. Since we want to run this only once, we exit
         # if this is called twice.
@@ -1801,6 +1801,10 @@ class MainWindow(QtGui.QMainWindow):
         self._backend.soledad_close()
         logger.debug('Final quit...')
 
+        self._leap_signaler.stop()
+        self._backend.stop()
+        time.sleep(0.05)  # give the thread a little time to finish.
+
         # Remove lockfiles on a clean shutdown.
         logger.debug('Cleaning pidfiles')
         if IS_WIN:
-- 
cgit v1.2.3


From b66c1643eeb094a0f54d621ec3bf2c93173b767d Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 11 Jun 2014 15:35:10 -0300
Subject: Lowercase signals names.

---
 src/leap/bitmask/backend/components.py             | 86 +++++++++++-----------
 src/leap/bitmask/crypto/srpauth.py                 | 20 ++---
 src/leap/bitmask/crypto/srpregister.py             |  6 +-
 src/leap/bitmask/provider/providerbootstrapper.py  | 18 ++---
 src/leap/bitmask/services/eip/eipbootstrapper.py   |  6 +-
 src/leap/bitmask/services/eip/vpnprocess.py        | 14 ++--
 .../services/soledad/soledadbootstrapper.py        | 16 ++--
 7 files changed, 83 insertions(+), 83 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py
index 19fcf283..5357bed5 100644
--- a/src/leap/bitmask/backend/components.py
+++ b/src/leap/bitmask/backend/components.py
@@ -197,7 +197,7 @@ class Provider(object):
         else:
             if self._signaler is not None:
                 self._signaler.signal(
-                    self._signaler.PROV_PROBLEM_WITH_PROVIDER_KEY)
+                    self._signaler.prov_problem_with_provider)
             logger.error("Could not load provider configuration.")
             self._login_widget.set_enabled(True)
 
@@ -234,7 +234,7 @@ class Provider(object):
         services = get_supported(self._get_services(domain))
 
         self._signaler.signal(
-            self._signaler.PROV_GET_SUPPORTED_SERVICES, services)
+            self._signaler.prov_get_supported_services, services)
 
     def get_all_services(self, providers):
         """
@@ -253,7 +253,7 @@ class Provider(object):
             services_all = services_all.union(set(services))
 
         self._signaler.signal(
-            self._signaler.PROV_GET_ALL_SERVICES, services_all)
+            self._signaler.prov_get_all_services, list(services_all))
 
     def get_details(self, domain, lang=None):
         """
@@ -268,7 +268,7 @@ class Provider(object):
             prov_get_details -> dict
         """
         self._signaler.signal(
-            self._signaler.PROV_GET_DETAILS,
+            self._signaler.prov_get_details,
             self._provider_config.get_light_config(domain, lang))
 
     def get_pinned_providers(self):
@@ -279,7 +279,7 @@ class Provider(object):
             prov_get_pinned_providers -> list of provider domains
         """
         self._signaler.signal(
-            self._signaler.PROV_GET_PINNED_PROVIDERS,
+            self._signaler.prov_get_pinned_providers,
             PinnedProviders.domains())
 
 
@@ -324,7 +324,7 @@ class Register(object):
                 partial(srpregister.register_user, username, password))
         else:
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.SRP_REGISTRATION_FAILED)
+                self._signaler.signal(self._signaler.srp_registration_failed)
             logger.error("Could not load provider configuration.")
 
 
@@ -401,12 +401,12 @@ class EIP(object):
 
         if not self._can_start(domain):
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.EIP_CONNECTION_ABORTED)
+                self._signaler.signal(self._signaler.eip_connection_aborted)
             return
 
         if not loaded:
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.EIP_CONNECTION_ABORTED)
+                self._signaler.signal(self._signaler.eip_connection_aborted)
             logger.error("Tried to start EIP but cannot find any "
                          "available provider!")
             return
@@ -425,28 +425,28 @@ class EIP(object):
 
         if not self._provider_config.loaded():
             # This means that the user didn't call setup_eip first.
-            self._signaler.signal(signaler.BACKEND_BAD_CALL, "EIP.start(), "
+            self._signaler.signal(signaler.backend_bad_call, "EIP.start(), "
                                   "no provider loaded")
             return
 
         try:
             self._start_eip(*args, **kwargs)
         except vpnprocess.OpenVPNAlreadyRunning:
-            signaler.signal(signaler.EIP_OPENVPN_ALREADY_RUNNING)
+            signaler.signal(signaler.eip_openvpn_already_running)
         except vpnprocess.AlienOpenVPNAlreadyRunning:
-            signaler.signal(signaler.EIP_ALIEN_OPENVPN_ALREADY_RUNNING)
+            signaler.signal(signaler.eip_alien_openvpn_already_running)
         except vpnlauncher.OpenVPNNotFoundException:
-            signaler.signal(signaler.EIP_OPENVPN_NOT_FOUND_ERROR)
+            signaler.signal(signaler.eip_openvpn_not_found_error)
         except vpnlauncher.VPNLauncherException:
             # TODO: this seems to be used for 'gateway not found' only.
             #       see vpnlauncher.py
-            signaler.signal(signaler.EIP_VPN_LAUNCHER_EXCEPTION)
+            signaler.signal(signaler.eip_vpn_launcher_exception)
         except linuxvpnlauncher.EIPNoPolkitAuthAgentAvailable:
-            signaler.signal(signaler.EIP_NO_POLKIT_AGENT_ERROR)
+            signaler.signal(signaler.eip_no_polkit_agent_error)
         except linuxvpnlauncher.EIPNoPkexecAvailable:
-            signaler.signal(signaler.EIP_NO_PKEXEC_ERROR)
+            signaler.signal(signaler.eip_no_pkexec_error)
         except darwinvpnlauncher.EIPNoTunKextLoaded:
-            signaler.signal(signaler.EIP_NO_TUN_KEXT_ERROR)
+            signaler.signal(signaler.eip_no_tun_kext_error)
         except Exception as e:
             logger.error("Unexpected problem: {0!r}".format(e))
         else:
@@ -482,7 +482,7 @@ class EIP(object):
 
         while retry <= MAX_FW_WAIT_RETRIES:
             if self._vpn.is_fw_down():
-                self._signaler.signal(self._signaler.EIP_STOPPED)
+                self._signaler.signal(self._signaler.eip_stopped)
                 return
             else:
                 #msg = "Firewall is not down yet, waiting... {0} of {1}"
@@ -542,7 +542,7 @@ class EIP(object):
             filtered_domains.append((domain, is_initialized))
 
         if self._signaler is not None:
-            self._signaler.signal(self._signaler.EIP_GET_INITIALIZED_PROVIDERS,
+            self._signaler.signal(self._signaler.eip_get_initialized_providers,
                                   filtered_domains)
 
     def tear_fw_down(self):
@@ -566,7 +566,7 @@ class EIP(object):
         if not self._provider_is_initialized(domain):
             if self._signaler is not None:
                 self._signaler.signal(
-                    self._signaler.EIP_UNINITIALIZED_PROVIDER)
+                    self._signaler.eip_uninitialized_provider)
             return
 
         eip_config = eipconfig.EIPConfig()
@@ -580,14 +580,14 @@ class EIP(object):
         if not eip_loaded or provider_config is None:
             if self._signaler is not None:
                 self._signaler.signal(
-                    self._signaler.EIP_GET_GATEWAYS_LIST_ERROR)
+                    self._signaler.eip_get_gateways_list_error)
             return
 
         gateways = eipconfig.VPNGatewaySelector(eip_config).get_gateways_list()
 
         if self._signaler is not None:
             self._signaler.signal(
-                self._signaler.EIP_GET_GATEWAYS_LIST, gateways)
+                self._signaler.eip_get_gateways_list, gateways)
 
     def _can_start(self, domain):
         """
@@ -643,10 +643,10 @@ class EIP(object):
         """
         if self._can_start(domain):
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.EIP_CAN_START)
+                self._signaler.signal(self._signaler.eip_can_start)
         else:
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.EIP_CANNOT_START)
+                self._signaler.signal(self._signaler.eip_cannot_start)
 
     def check_dns(self, domain):
         """
@@ -665,7 +665,7 @@ class EIP(object):
             """
             Callback handler for `do_check`.
             """
-            self._signaler.signal(self._signaler.EIP_DNS_OK)
+            self._signaler.signal(self._signaler.eip_dns_ok)
             logger.debug("DNS check OK")
 
         def check_err(failure):
@@ -677,7 +677,7 @@ class EIP(object):
             """
             logger.debug("Can't resolve hostname. {0!r}".format(failure))
 
-            self._signaler.signal(self._signaler.EIP_DNS_ERROR)
+            self._signaler.signal(self._signaler.eip_dns_error)
 
             # python 2.7.4 raises socket.error
             # python 2.7.5 raises socket.gaierror
@@ -737,7 +737,7 @@ class Soledad(object):
             self._soledad_defer.addCallback(self._set_proxies_cb)
         else:
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.SOLEDAD_BOOTSTRAP_FAILED)
+                self._signaler.signal(self._signaler.soledad_bootstrap_failed)
             logger.error("Could not load provider configuration.")
 
         return self._soledad_defer
@@ -793,7 +793,7 @@ class Soledad(object):
         Password change callback.
         """
         if self._signaler is not None:
-            self._signaler.signal(self._signaler.SOLEDAD_PASSWORD_CHANGE_OK)
+            self._signaler.signal(self._signaler.soledad_password_change_ok)
 
     def _change_password_error(self, failure):
         """
@@ -808,7 +808,7 @@ class Soledad(object):
             logger.error("Passphrase too short.")
 
         if self._signaler is not None:
-            self._signaler.signal(self._signaler.SOLEDAD_PASSWORD_CHANGE_ERROR)
+            self._signaler.signal(self._signaler.soledad_password_change_error)
 
     def change_password(self, new_password):
         """
@@ -866,7 +866,7 @@ class Keymanager(object):
                 new_key = keys_file.read()
         except IOError as e:
             logger.error("IOError importing key. {0!r}".format(e))
-            signal = self._signaler.KEYMANAGER_IMPORT_IOERROR
+            signal = self._signaler.keymanager_import_ioerror
             self._signaler.signal(signal)
             return
 
@@ -876,19 +876,19 @@ class Keymanager(object):
                 new_key)
         except (KeyAddressMismatch, KeyFingerprintMismatch) as e:
             logger.error(repr(e))
-            signal = self._signaler.KEYMANAGER_IMPORT_DATAMISMATCH
+            signal = self._signaler.keymanager_import_datamismatch
             self._signaler.signal(signal)
             return
 
         if public_key is None or private_key is None:
-            signal = self._signaler.KEYMANAGER_IMPORT_MISSINGKEY
+            signal = self._signaler.keymanager_import_missingkey
             self._signaler.signal(signal)
             return
 
         current_public_key = keymanager.get_key(username, openpgp.OpenPGPKey)
         if public_key.address != current_public_key.address:
             logger.error("The key does not match the ID")
-            signal = self._signaler.KEYMANAGER_IMPORT_ADDRESSMISMATCH
+            signal = self._signaler.keymanager_import_addressmismatch
             self._signaler.signal(signal)
             return
 
@@ -899,7 +899,7 @@ class Keymanager(object):
         keymanager.send_key(openpgp.OpenPGPKey)
 
         logger.debug('Import ok')
-        signal = self._signaler.KEYMANAGER_IMPORT_OK
+        signal = self._signaler.keymanager_import_ok
 
         self._signaler.signal(signal)
 
@@ -923,17 +923,17 @@ class Keymanager(object):
                 keys_file.write(private_key.key_data)
 
             logger.debug('Export ok')
-            self._signaler.signal(self._signaler.KEYMANAGER_EXPORT_OK)
+            self._signaler.signal(self._signaler.keymanager_export_ok)
         except IOError as e:
             logger.error("IOError exporting key. {0!r}".format(e))
-            self._signaler.signal(self._signaler.KEYMANAGER_EXPORT_ERROR)
+            self._signaler.signal(self._signaler.keymanager_export_error)
 
     def list_keys(self):
         """
         List all the keys stored in the local DB.
         """
         keys = self._keymanager_proxy.get_all_keys_in_local_db()
-        self._signaler.signal(self._signaler.KEYMANAGER_KEYS_LIST, keys)
+        self._signaler.signal(self._signaler.keymanager_keys_list, keys)
 
     def get_key_details(self, username):
         """
@@ -942,7 +942,7 @@ class Keymanager(object):
         public_key = self._keymanager_proxy.get_key(username,
                                                     openpgp.OpenPGPKey)
         details = (public_key.key_id, public_key.fingerprint)
-        self._signaler.signal(self._signaler.KEYMANAGER_KEY_DETAILS, details)
+        self._signaler.signal(self._signaler.keymanager_key_details, details)
 
 
 class Mail(object):
@@ -1027,7 +1027,7 @@ class Mail(object):
         logger.debug('Waiting for imap service to stop.')
         cv.wait(self.SERVICE_STOP_TIMEOUT)
         logger.debug('IMAP stopped')
-        self._signaler.signal(self._signaler.IMAP_STOPPED)
+        self._signaler.signal(self._signaler.imap_stopped)
 
     def stop_imap_service(self):
         """
@@ -1080,7 +1080,7 @@ class Authenticate(object):
             return self._login_defer
         else:
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.SRP_AUTH_ERROR)
+                self._signaler.signal(self._signaler.srp_auth_error)
             logger.error("Could not load provider configuration.")
 
     def cancel_login(self):
@@ -1105,7 +1105,7 @@ class Authenticate(object):
         """
         if not self._is_logged_in():
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.SRP_NOT_LOGGED_IN_ERROR)
+                self._signaler.signal(self._signaler.srp_not_logged_in_error)
             return
 
         return self._srp_auth.change_password(current_password, new_password)
@@ -1117,7 +1117,7 @@ class Authenticate(object):
         """
         if not self._is_logged_in():
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.SRP_NOT_LOGGED_IN_ERROR)
+                self._signaler.signal(self._signaler.srp_not_logged_in_error)
             return
 
         self._srp_auth.logout()
@@ -1140,8 +1140,8 @@ class Authenticate(object):
 
         signal = None
         if self._is_logged_in():
-            signal = self._signaler.SRP_STATUS_LOGGED_IN
+            signal = self._signaler.srp_status_logged_in
         else:
-            signal = self._signaler.SRP_STATUS_NOT_LOGGED_IN
+            signal = self._signaler.srp_status_not_logged_in
 
         self._signaler.signal(signal)
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py
index 192a9d5c..856d2c81 100644
--- a/src/leap/bitmask/crypto/srpauth.py
+++ b/src/leap/bitmask/crypto/srpauth.py
@@ -523,7 +523,7 @@ class SRPAuth(object):
             Password change callback.
             """
             if self._signaler is not None:
-                self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_OK)
+                self._signaler.signal(self._signaler.srp_password_change_ok)
 
         def _change_password_error(self, failure):
             """
@@ -535,9 +535,9 @@ class SRPAuth(object):
                 return
 
             if failure.check(SRPAuthBadUserOrPassword):
-                self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_BADPW)
+                self._signaler.signal(self._signaler.srp_password_change_badpw)
             else:
-                self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_ERROR)
+                self._signaler.signal(self._signaler.srp_password_change_error)
 
         def authenticate(self, username, password):
             """
@@ -591,7 +591,7 @@ class SRPAuth(object):
             :type _: IGNORED
             """
             logger.debug("Successful login!")
-            self._signaler.signal(self._signaler.SRP_AUTH_OK)
+            self._signaler.signal(self._signaler.srp_auth_ok)
 
         def _authenticate_error(self, failure):
             """
@@ -612,13 +612,13 @@ class SRPAuth(object):
                 return
 
             if failure.check(SRPAuthBadUserOrPassword):
-                signal = self._signaler.SRP_AUTH_BAD_USER_OR_PASSWORD
+                signal = self._signaler.srp_auth_bad_user_or_password
             elif failure.check(SRPAuthConnectionError):
-                signal = self._signaler.SRP_AUTH_CONNECTION_ERROR
+                signal = self._signaler.srp_auth_connection_error
             elif failure.check(SRPAuthenticationError):
-                signal = self._signaler.SRP_AUTH_SERVER_ERROR
+                signal = self._signaler.srp_auth_server_error
             else:
-                signal = self._signaler.SRP_AUTH_ERROR
+                signal = self._signaler.srp_auth_error
 
             self._signaler.signal(signal)
 
@@ -647,7 +647,7 @@ class SRPAuth(object):
                 logger.warning("Something went wrong with the logout: %r" %
                                (e,))
                 if self._signaler is not None:
-                    self._signaler.signal(self._signaler.SRP_LOGOUT_ERROR)
+                    self._signaler.signal(self._signaler.srp_logout_error)
                 raise
             else:
                 self.set_session_id(None)
@@ -657,7 +657,7 @@ class SRPAuth(object):
                 self._session = self._fetcher.session()
                 logger.debug("Successfully logged out.")
                 if self._signaler is not None:
-                    self._signaler.signal(self._signaler.SRP_LOGOUT_OK)
+                    self._signaler.signal(self._signaler.srp_logout_ok)
 
         def set_session_id(self, session_id):
             with self._session_id_lock:
diff --git a/src/leap/bitmask/crypto/srpregister.py b/src/leap/bitmask/crypto/srpregister.py
index f03dc469..86510de1 100644
--- a/src/leap/bitmask/crypto/srpregister.py
+++ b/src/leap/bitmask/crypto/srpregister.py
@@ -179,11 +179,11 @@ class SRPRegister(QtCore.QObject):
             return
 
         if status_code in self.STATUS_OK:
-            self._signaler.signal(self._signaler.SRP_REGISTRATION_FINISHED)
+            self._signaler.signal(self._signaler.srp_registration_finished)
         elif status_code == self.STATUS_TAKEN:
-            self._signaler.signal(self._signaler.SRP_REGISTRATION_TAKEN)
+            self._signaler.signal(self._signaler.srp_registration_taken)
         else:
-            self._signaler.signal(self._signaler.SRP_REGISTRATION_FAILED)
+            self._signaler.signal(self._signaler.srp_registration_failed)
 
 
 if __name__ == "__main__":
diff --git a/src/leap/bitmask/provider/providerbootstrapper.py b/src/leap/bitmask/provider/providerbootstrapper.py
index 8c96a8b5..5064f6a4 100644
--- a/src/leap/bitmask/provider/providerbootstrapper.py
+++ b/src/leap/bitmask/provider/providerbootstrapper.py
@@ -90,7 +90,7 @@ class ProviderBootstrapper(AbstractBootstrapper):
         self._provider_config = None
         self._download_if_needed = False
         if signaler is not None:
-            self._cancel_signal = signaler.PROV_CANCELLED_SETUP
+            self._cancel_signal = signaler.prov_cancelled_setup
 
     @property
     def verify(self):
@@ -228,7 +228,7 @@ class ProviderBootstrapper(AbstractBootstrapper):
                 # TODO split
                 if not provider.supports_client(min_client_version):
                     self._signaler.signal(
-                        self._signaler.PROV_UNSUPPORTED_CLIENT)
+                        self._signaler.prov_unsupported_client)
                     raise UnsupportedClientVersionError()
 
             provider_definition, mtime = get_content(res)
@@ -250,7 +250,7 @@ class ProviderBootstrapper(AbstractBootstrapper):
                              'Found: {1}.').format(api_supported, api_version)
 
                     logger.error(error)
-                    self._signaler.signal(self._signaler.PROV_UNSUPPORTED_API)
+                    self._signaler.signal(self._signaler.prov_unsupported_api)
                     raise UnsupportedProviderAPI(error)
 
     def run_provider_select_checks(self, domain, download_if_needed=False):
@@ -271,10 +271,10 @@ class ProviderBootstrapper(AbstractBootstrapper):
 
         cb_chain = [
             (self._check_name_resolution,
-             self._signaler.PROV_NAME_RESOLUTION_KEY),
-            (self._check_https, self._signaler.PROV_HTTPS_CONNECTION_KEY),
+             self._signaler.prov_name_resolution),
+            (self._check_https, self._signaler.prov_https_connection),
             (self._download_provider_info,
-             self._signaler.PROV_DOWNLOAD_PROVIDER_INFO_KEY)
+             self._signaler.prov_download_provider_info)
         ]
 
         return self.addCallbackChain(cb_chain)
@@ -401,11 +401,11 @@ class ProviderBootstrapper(AbstractBootstrapper):
         self._download_if_needed = download_if_needed
 
         cb_chain = [
-            (self._download_ca_cert, self._signaler.PROV_DOWNLOAD_CA_CERT_KEY),
+            (self._download_ca_cert, self._signaler.prov_download_ca_cert),
             (self._check_ca_fingerprint,
-             self._signaler.PROV_CHECK_CA_FINGERPRINT_KEY),
+             self._signaler.prov_check_ca_fingerprint),
             (self._check_api_certificate,
-             self._signaler.PROV_CHECK_API_CERTIFICATE_KEY)
+             self._signaler.prov_check_api_certificate)
         ]
 
         return self.addCallbackChain(cb_chain)
diff --git a/src/leap/bitmask/services/eip/eipbootstrapper.py b/src/leap/bitmask/services/eip/eipbootstrapper.py
index c77977ce..264eac2e 100644
--- a/src/leap/bitmask/services/eip/eipbootstrapper.py
+++ b/src/leap/bitmask/services/eip/eipbootstrapper.py
@@ -53,7 +53,7 @@ class EIPBootstrapper(AbstractBootstrapper):
         self._eip_config = None
         self._download_if_needed = False
         if signaler is not None:
-            self._cancel_signal = signaler.EIP_CANCELLED_SETUP
+            self._cancel_signal = signaler.eip_cancelled_setup
 
     def _download_config(self, *args):
         """
@@ -116,9 +116,9 @@ class EIPBootstrapper(AbstractBootstrapper):
         self._download_if_needed = download_if_needed
 
         cb_chain = [
-            (self._download_config, self._signaler.EIP_CONFIG_READY),
+            (self._download_config, self._signaler.eip_config_ready),
             (self._download_client_certificates,
-             self._signaler.EIP_CLIENT_CERTIFICATE_READY)
+             self._signaler.eip_client_certificate_ready)
         ]
 
         return self.addCallbackChain(cb_chain)
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index b54f2925..3bda3059 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -118,10 +118,10 @@ class VPNObserver(object):
         """
         sig = self._signaler
         signals = {
-            "network_unreachable": sig.EIP_NETWORK_UNREACHABLE,
-            "process_restart_tls": sig.EIP_PROCESS_RESTART_TLS,
-            "process_restart_ping": sig.EIP_PROCESS_RESTART_PING,
-            "initialization_completed": sig.EIP_CONNECTED
+            "network_unreachable": sig.eip_network_unreachable,
+            "process_restart_tls": sig.eip_process_restart_tls,
+            "process_restart_ping": sig.eip_process_restart_ping,
+            "initialization_completed": sig.eip_connected
         }
         return signals.get(event.lower())
 
@@ -594,7 +594,7 @@ class VPNManager(object):
 
             state = status_step
             if state != self._last_state:
-                self._signaler.signal(self._signaler.EIP_STATE_CHANGED, state)
+                self._signaler.signal(self._signaler.eip_state_changed, state)
                 self._last_state = state
 
     def _parse_status_and_notify(self, output):
@@ -632,7 +632,7 @@ class VPNManager(object):
 
         status = (tun_tap_read, tun_tap_write)
         if status != self._last_status:
-            self._signaler.signal(self._signaler.EIP_STATUS_CHANGED, status)
+            self._signaler.signal(self._signaler.eip_status_changed, status)
             self._last_status = status
 
     def get_state(self):
@@ -869,7 +869,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
         if isinstance(exit_code, int):
             logger.debug("processExited, status %d" % (exit_code,))
         self._signaler.signal(
-            self._signaler.EIP_PROCESS_FINISHED, exit_code)
+            self._signaler.eip_process_finished, exit_code)
         self._alive = False
 
     def processEnded(self, reason):
diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
index b9243add..a5904dce 100644
--- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py
+++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
@@ -141,7 +141,7 @@ class SoledadBootstrapper(AbstractBootstrapper):
         AbstractBootstrapper.__init__(self, signaler)
 
         if signaler is not None:
-            self._cancel_signal = signaler.SOLEDAD_CANCELLED_BOOTSTRAP
+            self._cancel_signal = signaler.soledad_cancelled_bootstrap
 
         self._provider_config = None
         self._soledad_config = None
@@ -190,11 +190,11 @@ class SoledadBootstrapper(AbstractBootstrapper):
         self._uuid = uuid
         try:
             self.load_and_sync_soledad(uuid, offline=True)
-            self._signaler.signal(self._signaler.SOLEDAD_OFFLINE_FINISHED)
+            self._signaler.signal(self._signaler.soledad_offline_finished)
         except Exception as e:
             # TODO: we should handle more specific exceptions in here
             logger.exception(e)
-            self._signaler.signal(self._signaler.SOLEDAD_OFFLINE_FAILED)
+            self._signaler.signal(self._signaler.soledad_offline_failed)
 
     def _get_soledad_local_params(self, uuid, offline=False):
         """
@@ -390,7 +390,7 @@ class SoledadBootstrapper(AbstractBootstrapper):
                 continue
             except InvalidAuthTokenError:
                 self._signaler.signal(
-                    self._signaler.SOLEDAD_INVALID_AUTH_TOKEN)
+                    self._signaler.soledad_invalid_auth_token)
                 raise
             except Exception as e:
                 # XXX release syncing lock
@@ -649,11 +649,11 @@ class SoledadBootstrapper(AbstractBootstrapper):
         self._password = password
 
         if flags.OFFLINE:
-            signal_finished = self._signaler.SOLEDAD_OFFLINE_FINISHED
-            signal_failed = self._signaler.SOLEDAD_OFFLINE_FAILED
+            signal_finished = self._signaler.soledad_offline_finished
+            signal_failed = self._signaler.soledad_offline_failed
         else:
-            signal_finished = self._signaler.SOLEDAD_BOOTSTRAP_FINISHED
-            signal_failed = self._signaler.SOLEDAD_BOOTSTRAP_FAILED
+            signal_finished = self._signaler.soledad_bootstrap_finished
+            signal_failed = self._signaler.soledad_bootstrap_failed
 
         try:
             self._download_config()
-- 
cgit v1.2.3


From d35f12b00629d6578039a11ce5e18d0c58e3fa73 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Tue, 17 Jun 2014 18:42:37 -0300
Subject: Do backend calls using kwargs.

---
 src/leap/bitmask/gui/eip_preferenceswindow.py |  4 ++--
 src/leap/bitmask/gui/mainwindow.py            | 27 ++++++++++++++++-----------
 src/leap/bitmask/gui/preferenceswindow.py     |  7 ++++---
 src/leap/bitmask/gui/wizard.py                |  9 +++++----
 src/leap/bitmask/services/mail/conductor.py   |  6 ++++--
 5 files changed, 31 insertions(+), 22 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py
index caf663b1..306fdb8c 100644
--- a/src/leap/bitmask/gui/eip_preferenceswindow.py
+++ b/src/leap/bitmask/gui/eip_preferenceswindow.py
@@ -97,7 +97,7 @@ class EIPPreferencesWindow(QtGui.QDialog):
         if not providers:
             return
 
-        self._backend.eip_get_initialized_providers(providers)
+        self._backend.eip_get_initialized_providers(domains=providers)
 
     @QtCore.Slot(list)
     def _load_providers_in_combo(self, providers):
@@ -175,7 +175,7 @@ class EIPPreferencesWindow(QtGui.QDialog):
         domain = self.ui.cbProvidersGateway.itemData(domain_idx)
         self._selected_domain = domain
 
-        self._backend.eip_get_gateways_list(domain)
+        self._backend.eip_get_gateways_list(domain=domain)
 
     @QtCore.Slot(list)
     def _update_gateways_list(self, gateways):
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 9b6dc8bd..24915d4f 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -605,12 +605,13 @@ class MainWindow(QtGui.QMainWindow):
             return
 
         self._trying_to_start_eip = settings.get_autostart_eip()
-        self._backend.eip_can_start(default_provider)
+        self._backend.eip_can_start(domain=default_provider)
 
         # If we don't want to start eip, we leave everything
         # initialized to quickly start it
         if not self._trying_to_start_eip:
-            self._backend.eip_setup(default_provider, skip_network=True)
+            self._backend.eip_setup(provider=default_provider,
+                                    skip_network=True)
 
     def _backend_can_start_eip(self):
         """
@@ -824,7 +825,7 @@ class MainWindow(QtGui.QMainWindow):
         """
         providers = self._settings.get_configured_providers()
 
-        self._backend.provider_get_all_services(providers)
+        self._backend.provider_get_all_services(providers=providers)
 
     def _provider_get_all_services(self, services):
         self._set_eip_visible(EIP_SERVICE in services)
@@ -1124,7 +1125,7 @@ class MainWindow(QtGui.QMainWindow):
         emit the corresponding signals inmediately
         """
         domain = self._login_widget.get_selected_provider()
-        self._backend.provider_setup(domain)
+        self._backend.provider_setup(provider=domain)
 
     @QtCore.Slot(dict)
     def _load_provider_config(self, data):
@@ -1141,7 +1142,7 @@ class MainWindow(QtGui.QMainWindow):
         """
         if data[self._backend.PASSED_KEY]:
             selected_provider = self._login_widget.get_selected_provider()
-            self._backend.provider_bootstrap(selected_provider)
+            self._backend.provider_bootstrap(provider=selected_provider)
         else:
             logger.error(data[self._backend.ERROR_KEY])
             self._login_problem_provider()
@@ -1252,7 +1253,8 @@ class MainWindow(QtGui.QMainWindow):
             self._show_hide_unsupported_services()
 
             domain = self._login_widget.get_selected_provider()
-            self._backend.user_login(domain, username, password)
+            self._backend.user_login(provider=domain,
+                                     username=username, password=password)
         else:
             logger.error(data[self._backend.ERROR_KEY])
             self._login_problem_provider()
@@ -1319,7 +1321,7 @@ class MainWindow(QtGui.QMainWindow):
         """
         domain = self._login_widget.get_selected_provider()
         lang = QtCore.QLocale.system().name()
-        self._backend.provider_get_details(domain, lang)
+        self._backend.provider_get_details(domain=domain, lang=lang)
 
     @QtCore.Slot()
     def _provider_get_details(self, details):
@@ -1388,11 +1390,14 @@ class MainWindow(QtGui.QMainWindow):
                 # this is mostly for internal use/debug for now.
                 logger.warning("Sorry! Log-in at least one time.")
                 return
-            self._backend.soledad_load_offline(full_user_id, password, uuid)
+            self._backend.soledad_load_offline(username=full_user_id,
+                                               password=password, uuid=uuid)
         else:
             if self._logged_user is not None:
                 domain = self._login_widget.get_selected_provider()
-                self._backend.soledad_bootstrap(username, domain, password)
+                self._backend.soledad_bootstrap(username=username,
+                                                domain=domain,
+                                                password=password)
 
     ###################################################################
     # Service control methods: soledad
@@ -1478,7 +1483,7 @@ class MainWindow(QtGui.QMainWindow):
         self._already_started_eip = True
 
         # check for connectivity
-        self._backend.eip_check_dns(domain)
+        self._backend.eip_check_dns(domain=domain)
 
     @QtCore.Slot()
     def _eip_dns_error(self):
@@ -1542,7 +1547,7 @@ class MainWindow(QtGui.QMainWindow):
             self._eip_status.eip_button.setEnabled(False)
 
             domain = self._login_widget.get_selected_provider()
-            self._backend.eip_setup(domain)
+            self._backend.eip_setup(provider=domain)
 
             self._already_started_eip = True
             # we want to start soledad anyway after a certain timeout if eip
diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py
index 8cf8752e..3c9cd5d0 100644
--- a/src/leap/bitmask/gui/preferenceswindow.py
+++ b/src/leap/bitmask/gui/preferenceswindow.py
@@ -196,7 +196,8 @@ class PreferencesWindow(QtGui.QDialog):
             return
 
         self._set_changing_password(True)
-        self._backend.user_change_password(current_password, new_password)
+        self._backend.user_change_password(current_password=current_password,
+                                           new_password=new_password)
 
     @QtCore.Slot()
     def _srp_change_password_ok(self):
@@ -210,7 +211,7 @@ class PreferencesWindow(QtGui.QDialog):
         logger.debug("SRP password changed successfully.")
 
         if self._mx_provided:
-            self._backend.soledad_change_password(new_password)
+            self._backend.soledad_change_password(new_password=new_password)
         else:
             self._change_password_success()
 
@@ -359,7 +360,7 @@ class PreferencesWindow(QtGui.QDialog):
         save_services = partial(self._save_enabled_services, domain)
         self.ui.pbSaveServices.clicked.connect(save_services)
 
-        self._backend.provider_get_supported_services(domain)
+        self._backend.provider_get_supported_services(domain=domain)
 
     @QtCore.Slot(str)
     def _load_services(self, services):
diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py
index 79cccc44..a20ef9fe 100644
--- a/src/leap/bitmask/gui/wizard.py
+++ b/src/leap/bitmask/gui/wizard.py
@@ -323,7 +323,8 @@ class Wizard(QtGui.QWizard):
         if user_ok and pass_ok:
             self._set_register_status(self.tr("Starting registration..."))
 
-            self._backend.user_register(self._domain, username, password)
+            self._backend.user_register(provider=self._domain,
+                                        username=username, password=password)
             self._username = username
             self._password = password
         else:
@@ -475,7 +476,7 @@ class Wizard(QtGui.QWizard):
 
         self.ui.lblNameResolution.setPixmap(self.QUESTION_ICON)
         self._provider_select_defer = self._backend.\
-            provider_setup(self._domain)
+            provider_setup(provider=self._domain)
 
     @QtCore.Slot(bool)
     def _skip_provider_checks(self, skip):
@@ -576,7 +577,7 @@ class Wizard(QtGui.QWizard):
                                 True, self.SELECT_PROVIDER_PAGE)
             self._provider_checks_ok = True
             lang = QtCore.QLocale.system().name()
-            self._backend.provider_get_details(self._domain, lang)
+            self._backend.provider_get_details(domain=self._domain, lang=lang)
         else:
             new_data = {
                 self._backend.PASSED_KEY: False,
@@ -724,7 +725,7 @@ class Wizard(QtGui.QWizard):
                 self.page(pageId).setSubTitle(sub_title)
                 self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON)
                 self._provider_setup_defer = self._backend.\
-                    provider_bootstrap(self._domain)
+                    provider_bootstrap(provider=self._domain)
 
         if pageId == self.PRESENT_PROVIDER_PAGE:
             sub_title = self.tr("Description of services offered by {0}")
diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py
index 98b40929..5e85368f 100644
--- a/src/leap/bitmask/services/mail/conductor.py
+++ b/src/leap/bitmask/services/mail/conductor.py
@@ -64,7 +64,8 @@ class IMAPControl(object):
         """
         Start imap service.
         """
-        self._backend.imap_start_service(self.userid, flags.OFFLINE)
+        self._backend.imap_start_service(full_user_id=self.userid,
+                                         offline=flags.OFFLINE)
 
     def stop_imap_service(self):
         """
@@ -146,7 +147,8 @@ class SMTPControl(object):
         :type download_if_needed: bool
         """
         self.smtp_connection.qtsigs.connecting_signal.emit()
-        self._backend.smtp_start_service(self.userid, download_if_needed)
+        self._backend.smtp_start_service(full_user_id=self.userid,
+                                         download_if_needed=download_if_needed)
 
     def stop_smtp_service(self):
         """
-- 
cgit v1.2.3


From c46a93e290194cdeb1b4e1776d4bf0edde303072 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 25 Jun 2014 12:36:25 -0300
Subject: Add SIGINT handler.

---
 src/leap/bitmask/app.py          |  4 ++++
 src/leap/bitmask/frontend_app.py | 22 +++++-----------------
 2 files changed, 9 insertions(+), 17 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index 9afe41be..eda4073c 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -41,6 +41,7 @@
 #                (thanks to: http://www.glassgiant.com/ascii/)
 import multiprocessing
 import os
+import signal
 import sys
 
 from leap.bitmask.backend.utils import generate_certificates
@@ -112,6 +113,9 @@ def start_app():
     """
     Starts the main event loop and launches the main window.
     """
+    # Ensure that the application quits using CTRL-C
+    signal.signal(signal.SIGINT, signal.SIG_DFL)
+
     # Parse arguments and store them
     opts = leap_argparse.get_options()
     do_display_version(opts)
diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py
index 12703518..60f20e3c 100644
--- a/src/leap/bitmask/frontend_app.py
+++ b/src/leap/bitmask/frontend_app.py
@@ -18,8 +18,6 @@ import signal
 import sys
 import os
 
-from functools import partial
-
 from PySide import QtCore, QtGui
 
 from leap.bitmask.config import flags
@@ -41,18 +39,6 @@ def sigint_handler(*args, **kwargs):
     mainwindow.quit()
 
 
-def sigterm_handler(*args, **kwargs):
-    """
-    Signal handler for SIGTERM.
-    This handler is actually passed to twisted reactor
-    """
-    logger = kwargs.get('logger', None)
-    if logger:
-        logger.debug("SIGTERM catched. shutting down...")
-    mainwindow = args[0]
-    mainwindow.quit()
-
-
 def run_frontend(options):
     """
     Run the GUI for the application.
@@ -88,10 +74,12 @@ def run_frontend(options):
     qApp.setApplicationName("leap")
     qApp.setOrganizationDomain("leap.se")
 
-    window = MainWindow(start_hidden=start_hidden)
+    MainWindow(start_hidden=start_hidden)
 
-    sigint_window = partial(sigint_handler, window, logger=logger)
-    signal.signal(signal.SIGINT, sigint_window)
+    # sigint_window = partial(sigint_handler, window, logger=logger)
+    # signal.signal(signal.SIGINT, sigint_window)
+    # Ensure that the application quits using CTRL-C
+    signal.signal(signal.SIGINT, signal.SIG_DFL)
 
     sys.exit(qApp.exec_())
 
-- 
cgit v1.2.3


From 4a5e136f3b6e68d65df4a5be83504e05043aeaa1 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Thu, 19 Jun 2014 16:13:42 -0300
Subject: Add missing error/passed keys.

---
 src/leap/bitmask/backend/leapbackend.py |  3 +++
 src/leap/bitmask/gui/mainwindow.py      | 25 +++++++++++++++----------
 src/leap/bitmask/gui/wizard.py          | 27 +++++++++++++++------------
 3 files changed, 33 insertions(+), 22 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py
index cc7227ad..d6b0954a 100644
--- a/src/leap/bitmask/backend/leapbackend.py
+++ b/src/leap/bitmask/backend/leapbackend.py
@@ -28,6 +28,9 @@ from leap.bitmask.backend.backend import Backend
 
 logger = logging.getLogger(__name__)
 
+ERROR_KEY = "error"
+PASSED_KEY = "passed"
+
 
 class LeapBackend(Backend):
     """
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 24915d4f..a77f0215 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -26,6 +26,11 @@ from PySide import QtCore, QtGui
 
 from leap.bitmask import __version__ as VERSION
 from leap.bitmask import __version_hash__ as VERSION_HASH
+
+# TODO: we should use a more granular signaling instead of passing error/ok as
+# a result.
+from leap.bitmask.backend.leapbackend import ERROR_KEY, PASSED_KEY
+
 from leap.bitmask.config import flags
 from leap.bitmask.config.leapsettings import LeapSettings
 
@@ -1140,11 +1145,11 @@ class MainWindow(QtGui.QMainWindow):
                      backend.provider_setup()
         :type data: dict
         """
-        if data[self._backend.PASSED_KEY]:
+        if data[PASSED_KEY]:
             selected_provider = self._login_widget.get_selected_provider()
             self._backend.provider_bootstrap(provider=selected_provider)
         else:
-            logger.error(data[self._backend.ERROR_KEY])
+            logger.error(data[ERROR_KEY])
             self._login_problem_provider()
 
     @QtCore.Slot()
@@ -1246,7 +1251,7 @@ class MainWindow(QtGui.QMainWindow):
         Once the provider configuration is loaded, this starts the SRP
         authentication
         """
-        if data[self._backend.PASSED_KEY]:
+        if data[PASSED_KEY]:
             username = self._login_widget.get_user()
             password = self._login_widget.get_password()
 
@@ -1256,7 +1261,7 @@ class MainWindow(QtGui.QMainWindow):
             self._backend.user_login(provider=domain,
                                      username=username, password=password)
         else:
-            logger.error(data[self._backend.ERROR_KEY])
+            logger.error(data[ERROR_KEY])
             self._login_problem_provider()
 
     @QtCore.Slot()
@@ -1579,12 +1584,12 @@ class MainWindow(QtGui.QMainWindow):
         Start the VPN thread if the eip configuration is properly
         loaded.
         """
-        passed = data[self._backend.PASSED_KEY]
+        passed = data[PASSED_KEY]
 
         if not passed:
             error_msg = self.tr("There was a problem with the provider")
             self._eip_status.set_eip_status(error_msg, error=True)
-            logger.error(data[self._backend.ERROR_KEY])
+            logger.error(data[ERROR_KEY])
             self._already_started_eip = False
             return
 
@@ -1602,11 +1607,11 @@ class MainWindow(QtGui.QMainWindow):
         This is used for intermediate bootstrapping stages, in case
         they fail.
         """
-        passed = data[self._backend.PASSED_KEY]
+        passed = data[PASSED_KEY]
         if not passed:
             self._login_widget.set_status(
                 self.tr("Unable to connect: Problem with provider"))
-            logger.error(data[self._backend.ERROR_KEY])
+            logger.error(data[ERROR_KEY])
             self._already_started_eip = False
             self._eip_status.aborted()
 
@@ -1671,9 +1676,9 @@ class MainWindow(QtGui.QMainWindow):
         This is used for intermediate bootstrapping stages, in case
         they fail.
         """
-        passed = data[self._backend.PASSED_KEY]
+        passed = data[PASSED_KEY]
         if not passed:
-            logger.error(data[self._backend.ERROR_KEY])
+            logger.error(data[ERROR_KEY])
             self._login_problem_provider()
 
     #
diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py
index a20ef9fe..be5bde52 100644
--- a/src/leap/bitmask/gui/wizard.py
+++ b/src/leap/bitmask/gui/wizard.py
@@ -24,6 +24,10 @@ from functools import partial
 
 from PySide import QtCore, QtGui
 
+# TODO: we should use a more granular signaling instead of passing error/ok as
+# a result.
+from leap.bitmask.backend.leapbackend import ERROR_KEY, PASSED_KEY
+
 from leap.bitmask.config import flags
 from leap.bitmask.config.leapsettings import LeapSettings
 from leap.bitmask.services import get_service_display_name, get_supported
@@ -511,8 +515,8 @@ class Wizard(QtGui.QWizard):
         :param complete_page: page id to complete
         :type complete_page: int
         """
-        passed = data[self._backend.PASSED_KEY]
-        error = data[self._backend.ERROR_KEY]
+        passed = data[PASSED_KEY]
+        error = data[ERROR_KEY]
         if passed:
             label.setPixmap(self.OK_ICON)
             if complete:
@@ -532,7 +536,7 @@ class Wizard(QtGui.QWizard):
         """
         self._complete_task(data, self.ui.lblNameResolution)
         status = ""
-        passed = data[self._backend.PASSED_KEY]
+        passed = data[PASSED_KEY]
         if not passed:
             status = self.tr("<font color='red'><b>Non-existent "
                              "provider</b></font>")
@@ -552,10 +556,10 @@ class Wizard(QtGui.QWizard):
         """
         self._complete_task(data, self.ui.lblHTTPS)
         status = ""
-        passed = data[self._backend.PASSED_KEY]
+        passed = data[PASSED_KEY]
         if not passed:
             status = self.tr("<font color='red'><b>%s</b></font>") \
-                % (data[self._backend.ERROR_KEY])
+                % (data[ERROR_KEY])
             self.ui.lblProviderSelectStatus.setText(status)
         else:
             self.ui.lblProviderInfo.setPixmap(self.QUESTION_ICON)
@@ -572,7 +576,7 @@ class Wizard(QtGui.QWizard):
         check. Since this check is the last of this set, it also
         completes the page if passed
         """
-        if data[self._backend.PASSED_KEY]:
+        if data[PASSED_KEY]:
             self._complete_task(data, self.ui.lblProviderInfo,
                                 True, self.SELECT_PROVIDER_PAGE)
             self._provider_checks_ok = True
@@ -580,14 +584,13 @@ class Wizard(QtGui.QWizard):
             self._backend.provider_get_details(domain=self._domain, lang=lang)
         else:
             new_data = {
-                self._backend.PASSED_KEY: False,
-                self._backend.ERROR_KEY:
-                self.tr("Unable to load provider configuration")
+                PASSED_KEY: False,
+                ERROR_KEY: self.tr("Unable to load provider configuration")
             }
             self._complete_task(new_data, self.ui.lblProviderInfo)
 
         status = ""
-        if not data[self._backend.PASSED_KEY]:
+        if not data[PASSED_KEY]:
             status = self.tr("<font color='red'><b>Not a valid provider"
                              "</b></font>")
             self.ui.lblProviderSelectStatus.setText(status)
@@ -618,7 +621,7 @@ class Wizard(QtGui.QWizard):
         Sets the status for the download of the CA certificate check
         """
         self._complete_task(data, self.ui.lblDownloadCaCert)
-        passed = data[self._backend.PASSED_KEY]
+        passed = data[PASSED_KEY]
         if passed:
             self.ui.lblCheckCaFpr.setPixmap(self.QUESTION_ICON)
 
@@ -631,7 +634,7 @@ class Wizard(QtGui.QWizard):
         Sets the status for the CA fingerprint check
         """
         self._complete_task(data, self.ui.lblCheckCaFpr)
-        passed = data[self._backend.PASSED_KEY]
+        passed = data[PASSED_KEY]
         if passed:
             self.ui.lblCheckApiCert.setPixmap(self.QUESTION_ICON)
 
-- 
cgit v1.2.3


From cf75e3575c33249a6f756dceb423c6ec7f6cd50e Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 2 Jul 2014 12:14:22 -0300
Subject: Move the backend starter to its own file.

---
 src/leap/bitmask/app.py                 |  2 +-
 src/leap/bitmask/backend/leapbackend.py |  9 ---------
 src/leap/bitmask/backend_app.py         | 27 +++++++++++++++++++++++++++
 3 files changed, 28 insertions(+), 10 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index eda4073c..43dabad3 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -49,7 +49,7 @@ from leap.bitmask.backend.utils import generate_certificates
 from leap.bitmask import __version__ as VERSION
 from leap.bitmask.config import flags
 from leap.bitmask.frontend_app import run_frontend
-from leap.bitmask.backend.leapbackend import run_backend
+from leap.bitmask.backend_app import run_backend
 from leap.bitmask.logs.utils import create_logger
 from leap.bitmask.platform_init.locks import we_are_the_one_and_only
 from leap.bitmask.services.mail import plumber
diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py
index d6b0954a..4794d988 100644
--- a/src/leap/bitmask/backend/leapbackend.py
+++ b/src/leap/bitmask/backend/leapbackend.py
@@ -18,7 +18,6 @@
 Backend for everything
 """
 import logging
-import signal
 
 import zope.interface
 import zope.proxy
@@ -503,11 +502,3 @@ class LeapBackend(Backend):
             imap_stopped
         """
         self._mail.stop_imap_service()
-
-
-def run_backend(bypass_checks=False):
-    # Ensure that the application quits using CTRL-C
-    signal.signal(signal.SIGINT, signal.SIG_DFL)
-
-    backend = LeapBackend(bypass_checks=bypass_checks)
-    backend.run()
diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py
index e69de29b..bd3b8a1f 100644
--- a/src/leap/bitmask/backend_app.py
+++ b/src/leap/bitmask/backend_app.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# backend_app.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 <http://www.gnu.org/licenses/>.
+import signal
+
+from leap.bitmask.backend.leapbackend import LeapBackend
+
+
+def run_backend(bypass_checks=False):
+    # Ensure that the application quits using CTRL-C
+    signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+    backend = LeapBackend(bypass_checks=bypass_checks)
+    backend.run()
-- 
cgit v1.2.3


From 13c0b7cac822a33f7395e3f099a2d37251e2c759 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 2 Jul 2014 12:14:59 -0300
Subject: Ask the backend for the country code.

Remove global variable in favor of a helper method that returns the
country code.
Needed in order to split backend/frontend.
---
 src/leap/bitmask/backend/api.py              |  3 ++
 src/leap/bitmask/backend/components.py       | 42 ++++++++++++++++++++++++++++
 src/leap/bitmask/backend/leapbackend.py      | 13 +++++++++
 src/leap/bitmask/backend/leapsignaler.py     |  2 ++
 src/leap/bitmask/config/flags.py             |  2 --
 src/leap/bitmask/gui/eip_status.py           | 15 +++++++---
 src/leap/bitmask/gui/mainwindow.py           | 22 +++++++++++++--
 src/leap/bitmask/services/eip/vpnlauncher.py |  6 ----
 8 files changed, 90 insertions(+), 15 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py
index 012b3cbc..f8b8c699 100644
--- a/src/leap/bitmask/backend/api.py
+++ b/src/leap/bitmask/backend/api.py
@@ -26,6 +26,7 @@ API = (
     "eip_can_start",
     "eip_cancel_setup",
     "eip_check_dns",
+    "eip_get_gateway_country_code",
     "eip_get_gateways_list",
     "eip_get_initialized_providers",
     "eip_setup",
@@ -75,10 +76,12 @@ SIGNALS = (
     "eip_disconnected",
     "eip_dns_error",
     "eip_dns_ok",
+    "eip_get_gateway_country_code",
     "eip_get_gateways_list",
     "eip_get_gateways_list_error",
     "eip_get_initialized_providers",
     "eip_network_unreachable",
+    "eip_no_gateway",
     "eip_no_pkexec_error",
     "eip_no_polkit_agent_error",
     "eip_no_tun_kext_error",
diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py
index 5357bed5..fe7b566a 100644
--- a/src/leap/bitmask/backend/components.py
+++ b/src/leap/bitmask/backend/components.py
@@ -31,6 +31,7 @@ from twisted.python import log
 import zope.interface
 import zope.proxy
 
+from leap.bitmask.config.leapsettings import LeapSettings
 from leap.bitmask.config.providerconfig import ProviderConfig
 from leap.bitmask.crypto.srpauth import SRPAuth
 from leap.bitmask.crypto.srpregister import SRPRegister
@@ -589,6 +590,47 @@ class EIP(object):
             self._signaler.signal(
                 self._signaler.eip_get_gateways_list, gateways)
 
+    def get_gateway_country_code(self, domain):
+        """
+        Signal the country code for the currently used gateway for the given
+        provider.
+
+        :param domain: the domain to get country code.
+        :type domain: str
+
+        Signals:
+            eip_get_gateway_country_code -> str
+            eip_no_gateway
+        """
+        leap_settings = LeapSettings()
+
+        eip_config = eipconfig.EIPConfig()
+        provider_config = ProviderConfig.get_provider_config(domain)
+
+        api_version = provider_config.get_api_version()
+        eip_config.set_api_version(api_version)
+        eip_config.load(eipconfig.get_eipconfig_path(domain))
+
+        gateway_selector = eipconfig.VPNGatewaySelector(eip_config)
+        gateway_conf = leap_settings.get_selected_gateway(domain)
+
+        if gateway_conf == leap_settings.GATEWAY_AUTOMATIC:
+            gateways = gateway_selector.get_gateways()
+        else:
+            gateways = [gateway_conf]
+
+        if not gateways:
+            self._signaler.signal(self._signaler.eip_no_gateway)
+            return
+
+        # this only works for selecting the first gateway, as we're
+        # currently doing.
+        ccodes = gateway_selector.get_gateways_country_code()
+        gateway_ccode = ccodes[gateways[0]]
+
+        self._signaler.signal(self._signaler.eip_get_gateway_country_code,
+                              gateway_ccode)
+
     def _can_start(self, domain):
         """
         Returns True if it has everything that is needed to run EIP,
diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py
index 4794d988..3bc7a513 100644
--- a/src/leap/bitmask/backend/leapbackend.py
+++ b/src/leap/bitmask/backend/leapbackend.py
@@ -256,6 +256,19 @@ class LeapBackend(Backend):
         """
         self._eip.get_gateways_list(domain)
 
+    def eip_get_gateway_country_code(self, domain):
+        """
+        Signal a list of gateways for the given provider.
+
+        :param domain: the domain to get the gateways.
+        :type domain: str
+
+        Signals:
+            eip_get_gateways_list -> str
+            eip_no_gateway
+        """
+        self._eip.get_gateway_country_code(domain)
+
     def eip_get_initialized_providers(self, domains):
         """
         Signal a list of the given domains and if they are initialized or not.
diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py
index 47df0911..7912fc20 100644
--- a/src/leap/bitmask/backend/leapsignaler.py
+++ b/src/leap/bitmask/backend/leapsignaler.py
@@ -37,10 +37,12 @@ class LeapSignaler(SignalerQt):
     eip_disconnected = QtCore.Signal(object)
     eip_dns_error = QtCore.Signal()
     eip_dns_ok = QtCore.Signal()
+    eip_get_gateway_country_code = QtCore.Signal(object)
     eip_get_gateways_list = QtCore.Signal(object)
     eip_get_gateways_list_error = QtCore.Signal()
     eip_get_initialized_providers = QtCore.Signal(object)
     eip_network_unreachable = QtCore.Signal()
+    eip_no_gateway = QtCore.Signal()
     eip_no_pkexec_error = QtCore.Signal()
     eip_no_polkit_agent_error = QtCore.Signal()
     eip_no_tun_kext_error = QtCore.Signal()
diff --git a/src/leap/bitmask/config/flags.py b/src/leap/bitmask/config/flags.py
index 2f3fdde4..6b70659d 100644
--- a/src/leap/bitmask/config/flags.py
+++ b/src/leap/bitmask/config/flags.py
@@ -55,5 +55,3 @@ OPENVPN_VERBOSITY = 1
 
 # Skip the checks in the wizard, use for testing purposes only!
 SKIP_WIZARD_CHECKS = False
-
-CURRENT_VPN_COUNTRY = None
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
index 01966d82..df9f3741 100644
--- a/src/leap/bitmask/gui/eip_status.py
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -589,16 +589,23 @@ class EIPStatusWidget(QtGui.QWidget):
         self._systray.setIcon(QtGui.QIcon(selected_pixmap_tray))
         self._eip_status_menu.setTitle(tray_message)
 
-    def set_provider(self, provider):
+    def set_provider(self, provider, country_code):
+        """
+        Set the provider used right now, name and flag (if available).
+
+        :param provider: the provider in use.
+        :type provider: str
+        :param country_code: the country code of the gateway in use.
+        :type country_code: str
+        """
         self._provider = provider
 
         self.ui.lblEIPMessage.setText(
             self.tr("Routing traffic through: <b>{0}</b>").format(
                 provider))
 
-        ccode = flags.CURRENT_VPN_COUNTRY
-        if ccode is not None:
-            self.set_country_code(ccode)
+        if country_code is not None:
+            self.set_country_code(country_code)
 
     def set_country_code(self, code):
         """
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index a77f0215..5549c9cb 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -412,6 +412,9 @@ class MainWindow(QtGui.QMainWindow):
 
         sig.eip_dns_error.connect(self._eip_dns_error)
 
+        sig.eip_get_gateway_country_code.connect(self._set_eip_provider)
+        sig.eip_no_gateway.connect(self._set_eip_provider)
+
         # ==================================================================
 
         # Soledad signals
@@ -1481,15 +1484,28 @@ class MainWindow(QtGui.QMainWindow):
         signal that currently is beeing processed under status_panel.
         After the refactor to EIPConductor this should not be necessary.
         """
-        domain = self._login_widget.get_selected_provider()
+        self._already_started_eip = True
 
-        self._eip_status.set_provider(domain)
+        domain = self._login_widget.get_selected_provider()
         self._settings.set_defaultprovider(domain)
-        self._already_started_eip = True
+
+        self._backend.eip_get_gateway_country_code(domain=domain)
 
         # check for connectivity
         self._backend.eip_check_dns(domain=domain)
 
+    @QtCore.Slot()
+    def _set_eip_provider(self, country_code=None):
+        """
+        TRIGGERS:
+            Signaler.eip_get_gateway_country_code
+            Signaler.eip_no_gateway
+
+        Set the current provider and country code in the eip status widget.
+        """
+        domain = self._login_widget.get_selected_provider()
+        self._eip_status.set_provider(domain, country_code)
+
     @QtCore.Slot()
     def _eip_dns_error(self):
         """
diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py
index 0731bee3..5e2a4743 100644
--- a/src/leap/bitmask/services/eip/vpnlauncher.py
+++ b/src/leap/bitmask/services/eip/vpnlauncher.py
@@ -136,12 +136,6 @@ class VPNLauncher(object):
             logger.error('No gateway was found!')
             raise VPNLauncherException('No gateway was found!')
 
-        # this only works for selecting the first gateway, as we're
-        # currently doing.
-        ccodes = gateway_selector.get_gateways_country_code()
-        gateway_ccode = ccodes[gateways[0]]
-        flags.CURRENT_VPN_COUNTRY = gateway_ccode
-
         logger.debug("Using gateways ips: {0}".format(', '.join(gateways)))
         return gateways
 
-- 
cgit v1.2.3


From 0cab909f9518273d95e371e5fb1061fb9b0a92fd Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 2 Jul 2014 12:52:31 -0300
Subject: Send the flag module values to the processes.

Add serialize/deserialize to dict helper.
---
 src/leap/bitmask/app.py           |  8 +++++---
 src/leap/bitmask/backend_app.py   | 13 ++++++++++++-
 src/leap/bitmask/frontend_app.py  |  7 ++++++-
 src/leap/bitmask/util/__init__.py | 25 +++++++++++++++++++++++++
 4 files changed, 48 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index 43dabad3..d1a2a111 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -53,7 +53,7 @@ from leap.bitmask.backend_app import run_backend
 from leap.bitmask.logs.utils import create_logger
 from leap.bitmask.platform_init.locks import we_are_the_one_and_only
 from leap.bitmask.services.mail import plumber
-from leap.bitmask.util import leap_argparse
+from leap.bitmask.util import leap_argparse, flags_to_dict
 from leap.bitmask.util.requirement_checker import check_requirements
 
 from leap.common.events import server as event_server
@@ -178,11 +178,13 @@ def start_app():
 
     generate_certificates()
 
-    app = lambda: run_frontend(options=options)
+    flags_dict = flags_to_dict()
+
+    app = lambda: run_frontend(options, flags_dict)
     gui_process = multiprocessing.Process(target=app)
     gui_process.start()
 
-    backend = lambda: run_backend(bypass_checks=opts.danger)
+    backend = lambda: run_backend(opts.danger, flags_dict)
     backend_process = multiprocessing.Process(target=backend)
     backend_process.start()
 
diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py
index bd3b8a1f..d4815d82 100644
--- a/src/leap/bitmask/backend_app.py
+++ b/src/leap/bitmask/backend_app.py
@@ -17,11 +17,22 @@
 import signal
 
 from leap.bitmask.backend.leapbackend import LeapBackend
+from leap.bitmask.util import dict_to_flags
 
 
-def run_backend(bypass_checks=False):
+def run_backend(bypass_checks, flags_dict):
+    """
+    Run the backend for the application.
+
+    :param bypass_checks: whether we should bypass the checks or not
+    :type bypass_checks: bool
+    :param flags_dict: a dict containing the flag values set on app start.
+    :type flags_dict: dict
+    """
     # Ensure that the application quits using CTRL-C
     signal.signal(signal.SIGINT, signal.SIG_DFL)
 
+    dict_to_flags(flags_dict)
+
     backend = LeapBackend(bypass_checks=bypass_checks)
     backend.run()
diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py
index 60f20e3c..1fe4cd0a 100644
--- a/src/leap/bitmask/frontend_app.py
+++ b/src/leap/bitmask/frontend_app.py
@@ -23,6 +23,7 @@ from PySide import QtCore, QtGui
 from leap.bitmask.config import flags
 from leap.bitmask.gui import locale_rc  # noqa - silence pylint
 from leap.bitmask.gui.mainwindow import MainWindow
+from leap.bitmask.util import dict_to_flags
 
 import logging
 logger = logging.getLogger(__name__)
@@ -39,13 +40,17 @@ def sigint_handler(*args, **kwargs):
     mainwindow.quit()
 
 
-def run_frontend(options):
+def run_frontend(options, flags_dict):
     """
     Run the GUI for the application.
 
     :param options: a dict of options parsed from the command line.
     :type options: dict
+    :param flags_dict: a dict containing the flag values set on app start.
+    :type flags_dict: dict
     """
+    dict_to_flags(flags_dict)
+
     start_hidden = options["start_hidden"]
 
     # We force the style if on KDE so that it doesn't load all the kde
diff --git a/src/leap/bitmask/util/__init__.py b/src/leap/bitmask/util/__init__.py
index 25b86874..caa94ec7 100644
--- a/src/leap/bitmask/util/__init__.py
+++ b/src/leap/bitmask/util/__init__.py
@@ -129,3 +129,28 @@ def force_eval(items):
         return map(do_eval, items)
     else:
         return do_eval(items)
+
+
+def dict_to_flags(values):
+    """
+    Set the flags values given in the values dict.
+    If a value isn't provided then use the already existing one.
+
+    :param values: the values to set.
+    :type values: dict.
+    """
+    for k, v in values.items():
+        setattr(flags, k, v)
+
+
+def flags_to_dict():
+    """
+    Get the flags values in a dict.
+
+    :return: the values of flags into a dict.
+    :rtype: dict.
+    """
+    items = [i for i in dir(flags) if i[0] != '_']
+    values = {i: getattr(flags, i) for i in items}
+
+    return values
-- 
cgit v1.2.3


From eab69607ba4a65acf5c7745134d74917c76c6bf8 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 2 Jul 2014 16:43:07 -0300
Subject: Remove twisted stopper from the GUI.

---
 src/leap/bitmask/gui/mainwindow.py   |  3 ---
 src/leap/bitmask/gui/twisted_main.py | 43 ------------------------------------
 2 files changed, 46 deletions(-)
 delete mode 100644 src/leap/bitmask/gui/twisted_main.py

(limited to 'src')

diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 5549c9cb..9be6f15c 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -43,7 +43,6 @@ 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 import twisted_main
 
 from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX
 from leap.bitmask.platform_init.initializers import init_platform
@@ -1837,5 +1836,3 @@ class MainWindow(QtGui.QMainWindow):
             WindowsLock.release_all_locks()
 
         self.close()
-
-        QtDelayedCall(100, twisted_main.quit)
diff --git a/src/leap/bitmask/gui/twisted_main.py b/src/leap/bitmask/gui/twisted_main.py
deleted file mode 100644
index b1ce0ead..00000000
--- a/src/leap/bitmask/gui/twisted_main.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-# twisted_main.py
-# Copyright (C) 2013 LEAP
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-"""
-Main functions for integration of twisted reactor
-"""
-import logging
-
-from twisted.internet import error, reactor
-from PySide import QtCore
-
-logger = logging.getLogger(__name__)
-
-
-def stop():
-    QtCore.QCoreApplication.sendPostedEvents()
-    QtCore.QCoreApplication.flush()
-    try:
-        reactor.stop()
-        logger.debug('Twisted reactor stopped')
-    except error.ReactorNotRunning:
-        logger.debug('Twisted reactor not running')
-    logger.debug("Done stopping all the things.")
-
-
-def quit():
-    """
-    Stop the mainloop.
-    """
-    reactor.callLater(0, stop)
-- 
cgit v1.2.3


From c3f485e194eb32939755178b11d472e1e69a94ad Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 2 Jul 2014 16:43:58 -0300
Subject: Handle SIGINT/SIGTERM in processes.

---
 src/leap/bitmask/app.py          | 36 +++++++++++++++++++++++++++++----
 src/leap/bitmask/backend_app.py  | 26 ++++++++++++++++++++++--
 src/leap/bitmask/frontend_app.py | 43 ++++++++++++++++++++++++++++------------
 3 files changed, 86 insertions(+), 19 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index d1a2a111..fa244470 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -44,6 +44,8 @@ import os
 import signal
 import sys
 
+from functools import partial
+
 from leap.bitmask.backend.utils import generate_certificates
 
 from leap.bitmask import __version__ as VERSION
@@ -109,12 +111,33 @@ def do_mail_plumbing(opts):
     # XXX catch when import is used w/o acct
 
 
+def sigterm_handler(logger, gui_process, backend_process, signum, frame):
+    """
+    Signal handler that quits the running app cleanly.
+
+    :param logger: the configured logger object.
+    :type logger: logging.Logger
+    :param gui_process: the GUI process
+    :type gui_process: multiprocessing.Process
+    :param backend_process: the backend process
+    :type backend_process: multiprocessing.Process
+    :param signum: number of the signal received (e.g. SIGINT -> 2)
+    :type signum: int
+    :param frame: current stack frame
+    :type frame: frame or None
+    """
+    logger.debug("SIGTERM catched, terminating processes.")
+    gui_process.terminate()
+    # Don't terminate the backend, the frontend takes care of that.
+    # backend_process.terminate()
+
+
 def start_app():
     """
     Starts the main event loop and launches the main window.
     """
-    # Ensure that the application quits using CTRL-C
-    signal.signal(signal.SIGINT, signal.SIG_DFL)
+    # Ignore the signals since we handle them in the subprocesses
+    # signal.signal(signal.SIGINT, signal.SIG_IGN)
 
     # Parse arguments and store them
     opts = leap_argparse.get_options()
@@ -181,13 +204,18 @@ def start_app():
     flags_dict = flags_to_dict()
 
     app = lambda: run_frontend(options, flags_dict)
-    gui_process = multiprocessing.Process(target=app)
+    gui_process = multiprocessing.Process(target=app, name='Frontend')
     gui_process.start()
 
     backend = lambda: run_backend(opts.danger, flags_dict)
-    backend_process = multiprocessing.Process(target=backend)
+    backend_process = multiprocessing.Process(target=backend, name='Backend')
     backend_process.start()
 
+    handle_sigterm = partial(sigterm_handler, logger,
+                             gui_process, backend_process)
+    signal.signal(signal.SIGTERM, handle_sigterm)
+    signal.signal(signal.SIGINT, handle_sigterm)
+
 
 if __name__ == "__main__":
     start_app()
diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py
index d4815d82..b6d00f2d 100644
--- a/src/leap/bitmask/backend_app.py
+++ b/src/leap/bitmask/backend_app.py
@@ -14,11 +14,32 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+import logging
+import multiprocessing
 import signal
 
 from leap.bitmask.backend.leapbackend import LeapBackend
 from leap.bitmask.util import dict_to_flags
 
+logger = logging.getLogger(__name__)
+
+
+def signal_handler(signum, frame):
+    """
+    Signal handler that quits the running app cleanly.
+
+    :param signum: number of the signal received (e.g. SIGINT -> 2)
+    :type signum: int
+    :param frame: current stack frame
+    :type frame: frame or None
+    """
+    # Note: we don't stop the backend in here since the frontend signal handler
+    # will take care of that.
+    # In the future we may need to do the stop in here when the frontend and
+    # the backend are run separately (without multiprocessing)
+    pname = multiprocessing.current_process().name
+    logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum))
+
 
 def run_backend(bypass_checks, flags_dict):
     """
@@ -29,8 +50,9 @@ def run_backend(bypass_checks, flags_dict):
     :param flags_dict: a dict containing the flag values set on app start.
     :type flags_dict: dict
     """
-    # Ensure that the application quits using CTRL-C
-    signal.signal(signal.SIGINT, signal.SIG_DFL)
+    # ignore SIGINT since app.py takes care of signaling SIGTERM to us.
+    signal.signal(signal.SIGINT, signal.SIG_IGN)
+    signal.signal(signal.SIGTERM, signal_handler)
 
     dict_to_flags(flags_dict)
 
diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py
index 1fe4cd0a..5dc42287 100644
--- a/src/leap/bitmask/frontend_app.py
+++ b/src/leap/bitmask/frontend_app.py
@@ -14,10 +14,13 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+import multiprocessing
 import signal
 import sys
 import os
 
+from functools import partial
+
 from PySide import QtCore, QtGui
 
 from leap.bitmask.config import flags
@@ -29,15 +32,20 @@ import logging
 logger = logging.getLogger(__name__)
 
 
-def sigint_handler(*args, **kwargs):
+def signal_handler(window, signum, frame):
     """
-    Signal handler for SIGINT
+    Signal handler that quits the running app cleanly.
+
+    :param window: a window with a `quit` callable
+    :type window: MainWindow
+    :param signum: number of the signal received (e.g. SIGINT -> 2)
+    :type signum: int
+    :param frame: current stack frame
+    :type frame: frame or None
     """
-    logger = kwargs.get('logger', None)
-    if logger:
-        logger.debug("SIGINT catched. shutting down...")
-    mainwindow = args[0]
-    mainwindow.quit()
+    pname = multiprocessing.current_process().name
+    logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum))
+    window.quit()
 
 
 def run_frontend(options, flags_dict):
@@ -79,12 +87,21 @@ def run_frontend(options, flags_dict):
     qApp.setApplicationName("leap")
     qApp.setOrganizationDomain("leap.se")
 
-    MainWindow(start_hidden=start_hidden)
-
-    # sigint_window = partial(sigint_handler, window, logger=logger)
-    # signal.signal(signal.SIGINT, sigint_window)
-    # Ensure that the application quits using CTRL-C
-    signal.signal(signal.SIGINT, signal.SIG_DFL)
+    # HACK:
+    # We need to do some 'python work' once in a while, otherwise, no python
+    # code will be called and the Qt event loop will prevent the signal
+    # handlers for SIGINT/SIGTERM to be called.
+    # see: http://stackoverflow.com/a/4939113/687989
+    timer = QtCore.QTimer()
+    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)
+
+    sigterm_handler = partial(signal_handler, window)
+    # ignore SIGINT since app.py takes care of signaling SIGTERM to us.
+    signal.signal(signal.SIGINT, signal.SIG_IGN)
+    signal.signal(signal.SIGTERM, sigterm_handler)
 
     sys.exit(qApp.exec_())
 
-- 
cgit v1.2.3


From d33e9a2bc07ccd983a1321b254cc27ca6be989a3 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Tue, 8 Jul 2014 17:01:18 -0300
Subject: Add file docstrings.

---
 src/leap/bitmask/backend/backend_proxy.py | 4 ++++
 src/leap/bitmask/backend/leapsignaler.py  | 5 ++++-
 src/leap/bitmask/backend/signaler.py      | 4 ++++
 src/leap/bitmask/backend/signaler_qt.py   | 4 ++++
 src/leap/bitmask/backend/utils.py         | 3 +++
 src/leap/bitmask/backend_app.py           | 3 +++
 src/leap/bitmask/frontend_app.py          | 3 +++
 7 files changed, 25 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py
index 3c8e5d0f..39ed322e 100644
--- a/src/leap/bitmask/backend/backend_proxy.py
+++ b/src/leap/bitmask/backend/backend_proxy.py
@@ -14,6 +14,10 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+The BackendProxy handles calls from the GUI and forwards (through ZMQ)
+to the backend.
+"""
 import functools
 import Queue
 import threading
diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py
index 7912fc20..a36e6fdc 100644
--- a/src/leap/bitmask/backend/leapsignaler.py
+++ b/src/leap/bitmask/backend/leapsignaler.py
@@ -14,6 +14,9 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Signaling server, used to define the API signals.
+"""
 from PySide import QtCore
 
 from leap.bitmask.backend.signaler_qt import SignalerQt
@@ -21,7 +24,7 @@ from leap.bitmask.backend.signaler_qt import SignalerQt
 
 class LeapSignaler(SignalerQt):
     """
-    Signaling server subclass, used to defines the API signals.
+    Signaling server subclass, used to define the API signals.
     """
     backend_bad_call = QtCore.Signal(object)
 
diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py
index f8753771..6a0ec88a 100644
--- a/src/leap/bitmask/backend/signaler.py
+++ b/src/leap/bitmask/backend/signaler.py
@@ -14,6 +14,10 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Signaler client.
+Receives signals from the backend and sends to the signaling server.
+"""
 import Queue
 import threading
 import time
diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py
index dabd6662..ce9c24f5 100644
--- a/src/leap/bitmask/backend/signaler_qt.py
+++ b/src/leap/bitmask/backend/signaler_qt.py
@@ -14,6 +14,10 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Signaling server.
+Receives signals from the signaling client and emit Qt signals for the GUI.
+"""
 import threading
 import time
 
diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py
index 5d600689..b71fab9e 100644
--- a/src/leap/bitmask/backend/utils.py
+++ b/src/leap/bitmask/backend/utils.py
@@ -14,6 +14,9 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Backend utilities to handle ZMQ certificates.
+"""
 import os
 import shutil
 
diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py
index b6d00f2d..5c0e4803 100644
--- a/src/leap/bitmask/backend_app.py
+++ b/src/leap/bitmask/backend_app.py
@@ -14,6 +14,9 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Start point for the Backend.
+"""
 import logging
 import multiprocessing
 import signal
diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py
index 5dc42287..95d36538 100644
--- a/src/leap/bitmask/frontend_app.py
+++ b/src/leap/bitmask/frontend_app.py
@@ -14,6 +14,9 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Start point for the Frontend.
+"""
 import multiprocessing
 import signal
 import sys
-- 
cgit v1.2.3


From d8152277022eedf5a88c84cc5f099b2fc9ad6e46 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 9 Jul 2014 16:14:58 -0300
Subject: Comment out overly verbose logs for communication.

---
 src/leap/bitmask/backend/backend.py       |  6 +++---
 src/leap/bitmask/backend/backend_proxy.py | 10 ++++++----
 src/leap/bitmask/backend/signaler.py      | 10 ++++++----
 src/leap/bitmask/backend/signaler_qt.py   |  4 ++--
 4 files changed, 17 insertions(+), 13 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py
index 5f696f75..833f4368 100644
--- a/src/leap/bitmask/backend/backend.py
+++ b/src/leap/bitmask/backend/backend.py
@@ -86,7 +86,7 @@ class Backend(object):
             try:
                 request = self._zmq_socket.recv(zmq.NOBLOCK)
                 self._zmq_socket.send("OK")
-                logger.debug("Received request: '{0}'".format(request))
+                # logger.debug("Received request: '{0}'".format(request))
                 self._process_request(request)
             except zmq.ZMQError as e:
                 if e.errno != zmq.EAGAIN:
@@ -180,8 +180,8 @@ class Backend(object):
         if kwargs is not None:
             method = lambda: func(**kwargs)
 
-        logger.debug("Running method: '{0}' "
-                     "with args: '{1}' in a thread".format(api_method, kwargs))
+        # logger.debug("Running method: '{0}' "
+        #            "with args: '{1}' in a thread".format(api_method, kwargs))
 
         # run the action in a thread and keep track of it
         d = threads.deferToThread(method)
diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py
index 39ed322e..f683e465 100644
--- a/src/leap/bitmask/backend/backend_proxy.py
+++ b/src/leap/bitmask/backend/backend_proxy.py
@@ -131,14 +131,16 @@ class BackendProxy(object):
         :param request: the request to send.
         :type request: str
         """
-        logger.debug("Sending request to backend: {0}".format(request))
+        # logger.debug("Sending request to backend: {0}".format(request))
         self._socket.send(request)
 
         try:
             # Get the reply.
-            response = self._socket.recv()
-            msg = "Received reply for '{0}' -> '{1}'".format(request, response)
-            logger.debug(msg)
+            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)
             logger.critical(msg)
diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py
index 6a0ec88a..f21f0998 100644
--- a/src/leap/bitmask/backend/signaler.py
+++ b/src/leap/bitmask/backend/signaler.py
@@ -145,14 +145,16 @@ class Signaler(object):
         :param request: the request to send.
         :type request: str
         """
-        logger.debug("Signaling '{0}'".format(request))
+        # logger.debug("Signaling '{0}'".format(request))
         self._socket.send(request)
 
         # Get the reply.
         try:
-            response = self._socket.recv()
-            msg = "Received reply for '{0}' -> '{1}'".format(request, response)
-            logger.debug(msg)
+            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 signaler. {0!r}".format(e)
             logger.critical(msg)
diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py
index ce9c24f5..4ec27a1e 100644
--- a/src/leap/bitmask/backend/signaler_qt.py
+++ b/src/leap/bitmask/backend/signaler_qt.py
@@ -72,7 +72,7 @@ class SignalerQt(QtCore.QThread):
             # Wait for next request from client
             try:
                 request = socket.recv(zmq.NOBLOCK)
-                logger.debug("Received request: '{0}'".format(request))
+                # logger.debug("Received request: '{0}'".format(request))
                 socket.send("OK")
                 self._process_request(request)
             except zmq.ZMQError as e:
@@ -116,7 +116,7 @@ class SignalerQt(QtCore.QThread):
             logger.warning("Signal not implemented, '{0}'".format(signal))
             return
 
-        logger.debug("Emitting '{0}'".format(signal))
+        # logger.debug("Emitting '{0}'".format(signal))
         if data is None:
             qt_signal.emit()
         else:
-- 
cgit v1.2.3


From 525433088d6fbe3392af90942272dfd5dd2511d6 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Fri, 11 Jul 2014 12:28:20 -0300
Subject: Use main process to run frontend.

Running the GUI in a child process gives problems on OSX.
Also, change signal handling since we have less processes.
---
 src/leap/bitmask/app.py          | 34 +++-------------------------------
 src/leap/bitmask/frontend_app.py |  7 +++----
 2 files changed, 6 insertions(+), 35 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index fa244470..e80b9dd1 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -41,10 +41,8 @@
 #                (thanks to: http://www.glassgiant.com/ascii/)
 import multiprocessing
 import os
-import signal
 import sys
 
-from functools import partial
 
 from leap.bitmask.backend.utils import generate_certificates
 
@@ -111,27 +109,6 @@ def do_mail_plumbing(opts):
     # XXX catch when import is used w/o acct
 
 
-def sigterm_handler(logger, gui_process, backend_process, signum, frame):
-    """
-    Signal handler that quits the running app cleanly.
-
-    :param logger: the configured logger object.
-    :type logger: logging.Logger
-    :param gui_process: the GUI process
-    :type gui_process: multiprocessing.Process
-    :param backend_process: the backend process
-    :type backend_process: multiprocessing.Process
-    :param signum: number of the signal received (e.g. SIGINT -> 2)
-    :type signum: int
-    :param frame: current stack frame
-    :type frame: frame or None
-    """
-    logger.debug("SIGTERM catched, terminating processes.")
-    gui_process.terminate()
-    # Don't terminate the backend, the frontend takes care of that.
-    # backend_process.terminate()
-
-
 def start_app():
     """
     Starts the main event loop and launches the main window.
@@ -203,18 +180,13 @@ def start_app():
 
     flags_dict = flags_to_dict()
 
-    app = lambda: run_frontend(options, flags_dict)
-    gui_process = multiprocessing.Process(target=app, name='Frontend')
-    gui_process.start()
-
     backend = lambda: run_backend(opts.danger, flags_dict)
     backend_process = multiprocessing.Process(target=backend, name='Backend')
+    backend_process.daemon = True
     backend_process.start()
 
-    handle_sigterm = partial(sigterm_handler, logger,
-                             gui_process, backend_process)
-    signal.signal(signal.SIGTERM, handle_sigterm)
-    signal.signal(signal.SIGINT, handle_sigterm)
+    run_frontend(options, flags_dict)
+
 
 
 if __name__ == "__main__":
diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py
index 95d36538..ffcb61ad 100644
--- a/src/leap/bitmask/frontend_app.py
+++ b/src/leap/bitmask/frontend_app.py
@@ -101,10 +101,9 @@ def run_frontend(options, flags_dict):
 
     window = MainWindow(start_hidden=start_hidden)
 
-    sigterm_handler = partial(signal_handler, window)
-    # ignore SIGINT since app.py takes care of signaling SIGTERM to us.
-    signal.signal(signal.SIGINT, signal.SIG_IGN)
-    signal.signal(signal.SIGTERM, sigterm_handler)
+    sig_handler = partial(signal_handler, window)
+    signal.signal(signal.SIGINT, sig_handler)
+    signal.signal(signal.SIGTERM, sig_handler)
 
     sys.exit(qApp.exec_())
 
-- 
cgit v1.2.3


From 0aee7d6cbc3f2c0b764056966eeddc4057eafd08 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Fri, 11 Jul 2014 17:24:20 -0300
Subject: Use specific settings for backend.

This way we get rid of Qt on the backend side.
The use of QSettings in the backend was breaking the app on OSX.
---
 src/leap/bitmask/backend/api.py               |   1 +
 src/leap/bitmask/backend/components.py        |   8 +-
 src/leap/bitmask/backend/leapbackend.py       |  14 +++
 src/leap/bitmask/backend/settings.py          | 158 ++++++++++++++++++++++++++
 src/leap/bitmask/crypto/srpauth.py            |   4 +-
 src/leap/bitmask/gui/eip_preferenceswindow.py |   2 +
 src/leap/bitmask/gui/mainwindow.py            |   2 +
 src/leap/bitmask/services/eip/vpnlauncher.py  |   8 +-
 src/leap/bitmask/services/mail/plumber.py     |   4 +-
 9 files changed, 189 insertions(+), 12 deletions(-)
 create mode 100644 src/leap/bitmask/backend/settings.py

(limited to 'src')

diff --git a/src/leap/bitmask/backend/api.py b/src/leap/bitmask/backend/api.py
index f8b8c699..b8533f36 100644
--- a/src/leap/bitmask/backend/api.py
+++ b/src/leap/bitmask/backend/api.py
@@ -45,6 +45,7 @@ API = (
     "provider_get_pinned_providers",
     "provider_get_supported_services",
     "provider_setup",
+    "settings_set_selected_gateway",
     "smtp_start_service",
     "smtp_stop_service",
     "soledad_bootstrap",
diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py
index fe7b566a..8b471b14 100644
--- a/src/leap/bitmask/backend/components.py
+++ b/src/leap/bitmask/backend/components.py
@@ -31,7 +31,7 @@ from twisted.python import log
 import zope.interface
 import zope.proxy
 
-from leap.bitmask.config.leapsettings import LeapSettings
+from leap.bitmask.backend.settings import Settings, GATEWAY_AUTOMATIC
 from leap.bitmask.config.providerconfig import ProviderConfig
 from leap.bitmask.crypto.srpauth import SRPAuth
 from leap.bitmask.crypto.srpregister import SRPRegister
@@ -602,7 +602,7 @@ class EIP(object):
             eip_get_gateway_country_code -> str
             eip_no_gateway
         """
-        leap_settings = LeapSettings()
+        settings = Settings()
 
         eip_config = eipconfig.EIPConfig()
         provider_config = ProviderConfig.get_provider_config(domain)
@@ -612,9 +612,9 @@ class EIP(object):
         eip_config.load(eipconfig.get_eipconfig_path(domain))
 
         gateway_selector = eipconfig.VPNGatewaySelector(eip_config)
-        gateway_conf = leap_settings.get_selected_gateway(domain)
+        gateway_conf = settings.get_selected_gateway(domain)
 
-        if gateway_conf == leap_settings.GATEWAY_AUTOMATIC:
+        if gateway_conf == GATEWAY_AUTOMATIC:
             gateways = gateway_selector.get_gateways()
         else:
             gateways = [gateway_conf]
diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py
index 3bc7a513..d3c4fcda 100644
--- a/src/leap/bitmask/backend/leapbackend.py
+++ b/src/leap/bitmask/backend/leapbackend.py
@@ -24,6 +24,7 @@ import zope.proxy
 
 from leap.bitmask.backend import components
 from leap.bitmask.backend.backend import Backend
+from leap.bitmask.backend.settings import Settings
 
 logger = logging.getLogger(__name__)
 
@@ -41,6 +42,8 @@ class LeapBackend(Backend):
         """
         Backend.__init__(self)
 
+        self._settings = Settings()
+
         # Objects needed by several components, so we make a proxy and pass
         # them around
         self._soledad_proxy = zope.proxy.ProxyBase(None)
@@ -515,3 +518,14 @@ class LeapBackend(Backend):
             imap_stopped
         """
         self._mail.stop_imap_service()
+
+    def settings_set_selected_gateway(self, provider, gateway):
+        """
+        Set the selected gateway for a given provider.
+
+        :param provider: provider domain
+        :type provider: str
+        :param gateway: gateway to use as default
+        :type gateway: str
+        """
+        self._settings.set_selected_gateway(provider, gateway)
diff --git a/src/leap/bitmask/backend/settings.py b/src/leap/bitmask/backend/settings.py
new file mode 100644
index 00000000..5cb4c616
--- /dev/null
+++ b/src/leap/bitmask/backend/settings.py
@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+# settings.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 <http://www.gnu.org/licenses/>.
+"""
+Backend settings
+"""
+import ConfigParser
+import logging
+import os
+
+from leap.bitmask.util import get_path_prefix
+from leap.common.check import leap_assert, leap_assert_type
+
+logger = logging.getLogger(__name__)
+
+# We need this one available for the default decorator
+GATEWAY_AUTOMATIC = "Automatic"
+GENERAL_SECTION = "General"
+
+
+class Settings(object):
+    """
+    Leap backend settings hanler.
+    """
+    CONFIG_NAME = "leap-backend.conf"
+
+    # keys
+    GATEWAY_KEY = "Gateway"
+
+    def __init__(self):
+        """
+        Create the ConfigParser object and read it.
+        """
+        self._settings_path = os.path.join(get_path_prefix(),
+                                           "leap", self.CONFIG_NAME)
+
+        self._settings = ConfigParser.ConfigParser()
+        self._settings.read(self._settings_path)
+
+        self._add_section(GENERAL_SECTION)
+
+    def _add_section(self, section):
+        """
+        Add `section` to the config file and don't fail if already exists.
+
+        :param section: the section to add.
+        :type section: str
+        """
+        self._settings.read(self._settings_path)
+        try:
+            self._settings.add_section(section)
+        except ConfigParser.DuplicateSectionError:
+            pass
+
+    def _save(self):
+        """
+        Save the current state to the config file.
+        """
+        with open(self._settings_path, 'wb') as f:
+            self._settings.write(f)
+
+    def _get_value(self, section, key, default):
+        """
+        Return the value for the fiven `key` in `section`.
+        If there's no such section/key, `default` is returned.
+
+        :param section: the section to get the value from.
+        :type section: str
+        :param key: the key which value we want to get.
+        :type key: str
+        :param default: the value to return if there is no section/key.
+        :type default: object
+
+        :rtype: object
+        """
+        try:
+            return self._settings.get(section, key)
+        except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
+            return default
+
+    def get_selected_gateway(self, provider):
+        """
+        Return the configured gateway for the given `provider`.
+
+        :param provider: provider domain
+        :type provider: str
+
+        :rtype: str
+        """
+        leap_assert(len(provider) > 0, "We need a nonempty provider")
+        return self._get_value(provider, self.GATEWAY_KEY, GATEWAY_AUTOMATIC)
+
+    def set_selected_gateway(self, provider, gateway):
+        """
+        Saves the configured gateway for the given provider
+
+        :param provider: provider domain
+        :type provider: str
+
+        :param gateway: gateway to use as default
+        :type gateway: str
+        """
+
+        leap_assert(len(provider) > 0, "We need a nonempty provider")
+        leap_assert_type(gateway, (str, unicode))
+
+        self._add_section(provider)
+
+        self._settings.set(provider, self.GATEWAY_KEY, gateway)
+        self._save()
+
+    def get_uuid(self, username):
+        """
+        Gets the uuid for a given username.
+
+        :param username: the full user identifier in the form user@provider
+        :type username: basestring
+        """
+        leap_assert("@" in username,
+                    "Expected username in the form user@provider")
+        user, provider = username.split('@')
+
+        return self._get_value(provider, username, "")
+
+    def set_uuid(self, username, value):
+        """
+        Sets the uuid for a given username.
+
+        :param username: the full user identifier in the form user@provider
+        :type username: str or unicode
+        :param value: the uuid to save or None to remove it
+        :type value: str or unicode or None
+        """
+        leap_assert("@" in username,
+                    "Expected username in the form user@provider")
+        user, provider = username.split('@')
+
+        if value is None:
+            self._settings.remove_option(provider, username)
+        else:
+            leap_assert(len(value) > 0, "We cannot save an empty uuid")
+            self._add_section(provider)
+            self._settings.set(provider, username, value)
+
+        self._save()
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py
index 856d2c81..67c686b0 100644
--- a/src/leap/bitmask/crypto/srpauth.py
+++ b/src/leap/bitmask/crypto/srpauth.py
@@ -32,7 +32,7 @@ from requests.adapters import HTTPAdapter
 from twisted.internet import threads
 from twisted.internet.defer import CancelledError
 
-from leap.bitmask.config.leapsettings import LeapSettings
+from leap.bitmask.backend.settings import Settings
 from leap.bitmask.util import request_helpers as reqhelper
 from leap.bitmask.util.compat import requests_has_max_retries
 from leap.bitmask.util.constants import REQUEST_TIMEOUT
@@ -151,7 +151,7 @@ class SRPAuth(object):
 
             self._provider_config = provider_config
             self._signaler = signaler
-            self._settings = LeapSettings()
+            self._settings = Settings()
 
             # **************************************************** #
             # Dependency injection helpers, override this for more
diff --git a/src/leap/bitmask/gui/eip_preferenceswindow.py b/src/leap/bitmask/gui/eip_preferenceswindow.py
index 306fdb8c..0f63972f 100644
--- a/src/leap/bitmask/gui/eip_preferenceswindow.py
+++ b/src/leap/bitmask/gui/eip_preferenceswindow.py
@@ -149,6 +149,8 @@ class EIPPreferencesWindow(QtGui.QDialog):
             gateway = self.ui.cbGateways.itemData(idx)
 
         self._settings.set_selected_gateway(provider, gateway)
+        self._backend.settings_set_selected_gateway(provider=provider,
+                                                    gateway=gateway)
 
         msg = self.tr(
             "Gateway settings for provider '{0}' saved.").format(provider)
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 9be6f15c..27c7f717 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -129,6 +129,8 @@ class MainWindow(QtGui.QMainWindow):
         self._leap_signaler.start()
 
         self._settings = LeapSettings()
+        # gateway = self._settings.get_selected_gateway(provider)
+        # self._backend.settings_set_selected_gateway(provider, gateway)
 
         # Login Widget
         self._login_widget = LoginWidget(self._settings, self)
diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py
index 5e2a4743..e36fd76b 100644
--- a/src/leap/bitmask/services/eip/vpnlauncher.py
+++ b/src/leap/bitmask/services/eip/vpnlauncher.py
@@ -27,7 +27,7 @@ from abc import ABCMeta, abstractmethod
 from functools import partial
 
 from leap.bitmask.config import flags
-from leap.bitmask.config.leapsettings import LeapSettings
+from leap.bitmask.backend.settings import Settings, GATEWAY_AUTOMATIC
 from leap.bitmask.config.providerconfig import ProviderConfig
 from leap.bitmask.platform_init import IS_LINUX
 from leap.bitmask.services.eip.eipconfig import EIPConfig, VPNGatewaySelector
@@ -122,12 +122,12 @@ class VPNLauncher(object):
         :rtype: list
         """
         gateways = []
-        leap_settings = LeapSettings()
+        settings = Settings()
         domain = providerconfig.get_domain()
-        gateway_conf = leap_settings.get_selected_gateway(domain)
+        gateway_conf = settings.get_selected_gateway(domain)
         gateway_selector = VPNGatewaySelector(eipconfig)
 
-        if gateway_conf == leap_settings.GATEWAY_AUTOMATIC:
+        if gateway_conf == GATEWAY_AUTOMATIC:
             gateways = gateway_selector.get_gateways()
         else:
             gateways = [gateway_conf]
diff --git a/src/leap/bitmask/services/mail/plumber.py b/src/leap/bitmask/services/mail/plumber.py
index 1ef0543e..fa33afcd 100644
--- a/src/leap/bitmask/services/mail/plumber.py
+++ b/src/leap/bitmask/services/mail/plumber.py
@@ -26,7 +26,7 @@ from functools import partial
 
 from twisted.internet import defer
 
-from leap.bitmask.config.leapsettings import LeapSettings
+from leap.bitmask.backend.settings import Settings
 from leap.bitmask.config.providerconfig import ProviderConfig
 from leap.bitmask.provider import get_provider_path
 from leap.bitmask.services.soledad.soledadbootstrapper import get_db_paths
@@ -114,7 +114,7 @@ class MBOXPlumber(object):
         self.user = user
         self.mdir = mdir
         self.sol = None
-        self._settings = LeapSettings()
+        self._settings = Settings()
 
         provider_config_path = os.path.join(get_path_prefix(),
                                             get_provider_path(provider))
-- 
cgit v1.2.3


From cd8f6757b51a8eedc3e29c22656ade1ae22110fe Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Mon, 14 Jul 2014 12:08:37 -0300
Subject: Apply changes removed rebasing pullreq #679.

https://github.com/leapcode/bitmask_client/pull/679/files
---
 src/leap/bitmask/frontend_app.py | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/frontend_app.py b/src/leap/bitmask/frontend_app.py
index ffcb61ad..51607d0b 100644
--- a/src/leap/bitmask/frontend_app.py
+++ b/src/leap/bitmask/frontend_app.py
@@ -27,7 +27,6 @@ from functools import partial
 from PySide import QtCore, QtGui
 
 from leap.bitmask.config import flags
-from leap.bitmask.gui import locale_rc  # noqa - silence pylint
 from leap.bitmask.gui.mainwindow import MainWindow
 from leap.bitmask.util import dict_to_flags
 
@@ -35,20 +34,24 @@ import logging
 logger = logging.getLogger(__name__)
 
 
-def signal_handler(window, signum, frame):
+def signal_handler(window, pid, signum, frame):
     """
     Signal handler that quits the running app cleanly.
 
     :param window: a window with a `quit` callable
     :type window: MainWindow
+    :param pid: process id of the main process.
+    :type pid: int
     :param signum: number of the signal received (e.g. SIGINT -> 2)
     :type signum: int
     :param frame: current stack frame
     :type frame: frame or None
     """
-    pname = multiprocessing.current_process().name
-    logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum))
-    window.quit()
+    my_pid = os.getpid()
+    if pid == my_pid:
+        pname = multiprocessing.current_process().name
+        logger.debug("{0}: SIGNAL #{1} catched.".format(pname, signum))
+        window.quit()
 
 
 def run_frontend(options, flags_dict):
@@ -101,7 +104,8 @@ def run_frontend(options, flags_dict):
 
     window = MainWindow(start_hidden=start_hidden)
 
-    sig_handler = partial(signal_handler, window)
+    my_pid = os.getpid()
+    sig_handler = partial(signal_handler, window, my_pid)
     signal.signal(signal.SIGINT, sig_handler)
     signal.signal(signal.SIGTERM, sig_handler)
 
-- 
cgit v1.2.3


From d6cee5b46587367b558863292f71f5baafadc762 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Mon, 14 Jul 2014 12:23:13 -0300
Subject: pep8 fixes

---
 src/leap/bitmask/app.py            | 1 -
 src/leap/bitmask/gui/mainwindow.py | 4 ++--
 2 files changed, 2 insertions(+), 3 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index e80b9dd1..88f6bc15 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -188,6 +188,5 @@ def start_app():
     run_frontend(options, flags_dict)
 
 
-
 if __name__ == "__main__":
     start_app()
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 27c7f717..3d489bd8 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -256,7 +256,7 @@ class MainWindow(QtGui.QMainWindow):
         # XXX should connect to mail_conductor.start_mail_service instead
         self.soledad_ready.connect(self._start_smtp_bootstrapping)
         self.soledad_ready.connect(self._start_imap_service)
-        ################################# end Qt Signals connection ########
+        # ################################ end Qt Signals connection ########
 
         init_platform()
 
@@ -1295,7 +1295,7 @@ class MainWindow(QtGui.QMainWindow):
             sig.soledad_bootstrap_failed.connect(lambda: btn_enabled(True))
             sig.soledad_bootstrap_finished.connect(lambda: btn_enabled(True))
 
-        if not MX_SERVICE in self._provider_details['services']:
+        if MX_SERVICE not in self._provider_details['services']:
             self._set_mx_visible(False)
 
     def _start_eip_bootstrap(self):
-- 
cgit v1.2.3


From fad58792a499f5b3e7ef28c68d0bae7f055c603d Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Mon, 14 Jul 2014 14:32:28 -0300
Subject: Use custom `mkdir` to create the tree if needed.

---
 src/leap/bitmask/backend/utils.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py
index b71fab9e..54a16fd7 100644
--- a/src/leap/bitmask/backend/utils.py
+++ b/src/leap/bitmask/backend/utils.py
@@ -23,6 +23,7 @@ import shutil
 import zmq.auth
 
 from leap.bitmask.util import get_path_prefix
+from leap.common.files import mkdir_p
 
 KEYS_DIR = os.path.join(get_path_prefix(), 'leap', 'zmq_certificates')
 
@@ -34,7 +35,7 @@ def generate_certificates():
     # Create directory for certificates, remove old content if necessary
     if os.path.exists(KEYS_DIR):
         shutil.rmtree(KEYS_DIR)
-    os.mkdir(KEYS_DIR)
+    mkdir_p(KEYS_DIR)
 
     # create new keys in certificates dir
     # public_file, secret_file = create_certificates(...)
-- 
cgit v1.2.3


From 662ae7107bde734cda8d4bc08f5b647650139b61 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Mon, 14 Jul 2014 15:20:05 -0300
Subject: Prevent quit() being called more than once.

---
 src/leap/bitmask/gui/mainwindow.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 3d489bd8..6959650b 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -187,6 +187,7 @@ class MainWindow(QtGui.QMainWindow):
         self._services_being_stopped = {}
 
         # used to know if we are in the final steps of quitting
+        self._quitting = False
         self._finally_quitting = False
 
         self._backend_connected_signals = []
@@ -1762,8 +1763,10 @@ class MainWindow(QtGui.QMainWindow):
         Start the quit sequence and wait for services to finish.
         Cleanup and close the main window before quitting.
         """
-        # TODO separate the shutting down of services from the
-        # UI stuff.
+        if self._quitting:
+            return
+
+        self._quitting = True
 
         # first thing to do quitting, hide the mainwindow and show tooltip.
         self.hide()
-- 
cgit v1.2.3


From 57ac3750970777bb5b6e372e5eb00f3144098d90 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= <chiiph@leap.se>
Date: Mon, 14 Jul 2014 16:24:59 -0300
Subject: Support EIP in OSX

---
 src/leap/bitmask/backend/components.py             | 3 ++-
 src/leap/bitmask/services/eip/darwinvpnlauncher.py | 4 +++-
 src/leap/bitmask/services/eip/vpnprocess.py        | 3 +++
 3 files changed, 8 insertions(+), 2 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py
index 8b471b14..8fa8b285 100644
--- a/src/leap/bitmask/backend/components.py
+++ b/src/leap/bitmask/backend/components.py
@@ -649,7 +649,8 @@ class EIP(object):
         launcher = get_vpn_launcher()
         ovpn_path = force_eval(launcher.OPENVPN_BIN_PATH)
         if not os.path.isfile(ovpn_path):
-            logger.error("Cannot start OpenVPN, binary not found")
+            logger.error("Cannot start OpenVPN, binary not found: %s" %
+                         (ovpn_path,))
             return False
 
         # check for other problems
diff --git a/src/leap/bitmask/services/eip/darwinvpnlauncher.py b/src/leap/bitmask/services/eip/darwinvpnlauncher.py
index 41d75052..f83e0170 100644
--- a/src/leap/bitmask/services/eip/darwinvpnlauncher.py
+++ b/src/leap/bitmask/services/eip/darwinvpnlauncher.py
@@ -46,7 +46,9 @@ class DarwinVPNLauncher(VPNLauncher):
     INSTALL_MSG = ("\"Bitmask needs administrative privileges to install "
                    "missing scripts and fix permissions.\"")
 
-    INSTALL_PATH = os.path.realpath(os.getcwd() + "/../../")
+    # Hardcode the installation path for OSX for security, openvpn is
+    # run as root
+    INSTALL_PATH = "/Applications/Bitmask.app/"
     INSTALL_PATH_ESCAPED = os.path.realpath(os.getcwd() + "/../../")
     OPENVPN_BIN = 'openvpn.leap'
     OPENVPN_PATH = "%s/Contents/Resources/openvpn" % (INSTALL_PATH,)
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index 3bda3059..1c11a337 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -255,6 +255,9 @@ class VPN(object):
         """
         Tear the firewall 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, "firewall", "stop"])
-- 
cgit v1.2.3


From 7c7c2d49b172d08e106e297101142747eaf78944 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Mon, 14 Jul 2014 16:23:20 -0300
Subject: Use polling to prevent communication issues.

---
 src/leap/bitmask/backend/signaler.py | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py
index f21f0998..7401f3a0 100644
--- a/src/leap/bitmask/backend/signaler.py
+++ b/src/leap/bitmask/backend/signaler.py
@@ -38,6 +38,8 @@ class Signaler(object):
     """
     PORT = "5667"
     SERVER = "tcp://localhost:%s" % PORT
+    POLL_TIMEOUT = 1000  # ms
+    POLL_TRIES = 3
 
     def __init__(self):
         """
@@ -148,13 +150,23 @@ class Signaler(object):
         # logger.debug("Signaling '{0}'".format(request))
         self._socket.send(request)
 
-        # Get the reply.
-        try:
-            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 signaler. {0!r}".format(e)
+        poll = zmq.Poller()
+        poll.register(self._socket, zmq.POLLIN)
+
+        reply = None
+        tries = 0
+
+        while tries < self.POLL_TRIES:
+            socks = dict(poll.poll(self.POLL_TIMEOUT))
+            if socks.get(self._socket) == zmq.POLLIN:
+                reply = self._socket.recv()
+                break
+
+            tries += 1
+
+        if reply is None:
+            msg = "Timeout error contacting backend."
             logger.critical(msg)
+        # else:
+        #     msg = "Received reply for '{0}' -> '{1}'".format(request, reply)
+        #     logger.debug(msg)
-- 
cgit v1.2.3


From 986ff80c16efea0e32ff78012b2fd3c95b83e179 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Tue, 15 Jul 2014 16:24:49 -0300
Subject: Replace QThread with threading.Thread.

---
 src/leap/bitmask/backend/signaler_qt.py | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py
index 4ec27a1e..433f18ed 100644
--- a/src/leap/bitmask/backend/signaler_qt.py
+++ b/src/leap/bitmask/backend/signaler_qt.py
@@ -33,7 +33,7 @@ import logging
 logger = logging.getLogger(__name__)
 
 
-class SignalerQt(QtCore.QThread):
+class SignalerQt(QtCore.QObject):
     """
     Signaling server.
     Receives signals from the signaling client and emit Qt signals for the GUI.
@@ -42,11 +42,24 @@ class SignalerQt(QtCore.QThread):
     BIND_ADDR = "tcp://127.0.0.1:%s" % PORT
 
     def __init__(self):
-        QtCore.QThread.__init__(self)
+        QtCore.QObject.__init__(self)
+
+        # Note: we use a plain thread instead of a QThread since works better.
+        # The signaler was not responding on OSX if the worker loop was run in
+        # a QThread.
+        # Possibly, ZMQ was not getting cycles to do work because Qt not
+        # receiving focus or something.
+        self._worker_thread = threading.Thread(target=self._run)
         self._do_work = threading.Event()
+
+    def start(self):
+        """
+        Start the worker thread for the signaler server.
+        """
         self._do_work.set()
+        self._worker_thread.start()
 
-    def run(self):
+    def _run(self):
         """
         Start a loop to process the ZMQ requests from the signaler client.
         """
-- 
cgit v1.2.3


From 432fcab9f838b0bfc81ed8d40d92b4b5d3854f24 Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 16 Jul 2014 09:39:17 -0300
Subject: Code style fixes.

---
 src/leap/bitmask/__init__.py                       | 10 ++++-----
 src/leap/bitmask/backend/components.py             |  6 ++---
 src/leap/bitmask/config/provider_spec.py           |  2 +-
 src/leap/bitmask/crypto/srpauth.py                 |  2 +-
 src/leap/bitmask/crypto/tests/fake_provider.py     |  4 ++--
 src/leap/bitmask/gui/eip_status.py                 | 11 +++++----
 src/leap/bitmask/gui/statemachines.py              | 11 +++++----
 src/leap/bitmask/platform_init/initializers.py     |  3 +--
 src/leap/bitmask/provider/providerbootstrapper.py  |  4 ++--
 src/leap/bitmask/services/eip/conductor.py         |  4 ++--
 .../services/eip/tests/test_eipbootstrapper.py     |  2 +-
 src/leap/bitmask/services/eip/vpnlauncher.py       | 10 ++++-----
 src/leap/bitmask/services/eip/vpnprocess.py        |  2 +-
 src/leap/bitmask/services/mail/plumber.py          |  4 ++--
 .../services/soledad/soledadbootstrapper.py        |  2 +-
 .../services/tests/test_abstractbootstrapper.py    |  2 +-
 src/leap/bitmask/util/leap_argparse.py             | 26 +++++++++++-----------
 src/leap/bitmask/util/polkit_agent.py              |  6 ++---
 src/leap/bitmask/util/privilege_policies.py        |  4 ++--
 19 files changed, 56 insertions(+), 59 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/__init__.py b/src/leap/bitmask/__init__.py
index 03da1e2f..9ec5aae7 100644
--- a/src/leap/bitmask/__init__.py
+++ b/src/leap/bitmask/__init__.py
@@ -29,7 +29,7 @@ from leap.bitmask.util import first
 # place, it can't be technically imported, but that doesn't matter
 # because the import is never executed
 if False:
-    import _scrypt
+    import _scrypt  # noqa - skip 'not used' warning
 
 
 def _is_release_version(version):
@@ -66,16 +66,16 @@ try:
     IS_RELEASE_VERSION = _is_release_version(__version__)
     del get_versions
 except ImportError:
-    #running on a tree that has not run
-    #the setup.py setver
+    # running on a tree that has not run
+    # the setup.py setver
     pass
 
 __appname__ = "unknown"
 try:
     from leap.bitmask._appname import __appname__
 except ImportError:
-    #running on a tree that has not run
-    #the setup.py setver
+    # running on a tree that has not run
+    # the setup.py setver
     pass
 
 __short_version__ = first(re.findall('\d+\.\d+\.\d+', __version__))
diff --git a/src/leap/bitmask/backend/components.py b/src/leap/bitmask/backend/components.py
index 8fa8b285..b372db89 100644
--- a/src/leap/bitmask/backend/components.py
+++ b/src/leap/bitmask/backend/components.py
@@ -486,9 +486,9 @@ class EIP(object):
                 self._signaler.signal(self._signaler.eip_stopped)
                 return
             else:
-                #msg = "Firewall is not down yet, waiting... {0} of {1}"
-                #msg = msg.format(retry, MAX_FW_WAIT_RETRIES)
-                #logger.debug(msg)
+                # msg = "Firewall is not down yet, waiting... {0} of {1}"
+                # msg = msg.format(retry, MAX_FW_WAIT_RETRIES)
+                # logger.debug(msg)
                 time.sleep(FW_WAIT_STEP)
                 retry += 1
         logger.warning("After waiting, firewall is not down... "
diff --git a/src/leap/bitmask/config/provider_spec.py b/src/leap/bitmask/config/provider_spec.py
index cf942c7b..a1d91b90 100644
--- a/src/leap/bitmask/config/provider_spec.py
+++ b/src/leap/bitmask/config/provider_spec.py
@@ -37,7 +37,7 @@ leap_provider_spec = {
             'default': {u'en': u'Test Provider'}
         },
         'description': {
-            #'type': LEAPTranslatable,
+            # 'type': LEAPTranslatable,
             'type': dict,
             'format': 'translatable',
             'default': {u'en': u'Test provider'}
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py
index 67c686b0..d59b3c31 100644
--- a/src/leap/bitmask/crypto/srpauth.py
+++ b/src/leap/bitmask/crypto/srpauth.py
@@ -24,7 +24,7 @@ import requests
 import srp
 import json
 
-#this error is raised from requests
+# this error is raised from requests
 from simplejson.decoder import JSONDecodeError
 from functools import partial
 from requests.adapters import HTTPAdapter
diff --git a/src/leap/bitmask/crypto/tests/fake_provider.py b/src/leap/bitmask/crypto/tests/fake_provider.py
index b8cdbb12..60a3ef0a 100755
--- a/src/leap/bitmask/crypto/tests/fake_provider.py
+++ b/src/leap/bitmask/crypto/tests/fake_provider.py
@@ -156,7 +156,7 @@ def getSession(self, sessionInterface=None):
     put the right cookie name in place
     """
     if not self.session:
-        #cookiename = b"_".join([b'TWISTED_SESSION'] + self.sitepath)
+        # cookiename = b"_".join([b'TWISTED_SESSION'] + self.sitepath)
         cookiename = b"_".join([b'_session_id'] + self.sitepath)
         sessionCookie = self.getCookie(cookiename)
         if sessionCookie:
@@ -321,7 +321,7 @@ class OpenSSLServerContextFactory(object):
         Create an SSL context.
         """
         ctx = SSL.Context(SSL.SSLv23_METHOD)
-        #ctx = SSL.Context(SSL.TLSv1_METHOD)
+        # ctx = SSL.Context(SSL.TLSv1_METHOD)
         ctx.use_certificate_file(where('leaptestscert.pem'))
         ctx.use_privatekey_file(where('leaptestskey.pem'))
 
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
index df9f3741..a707050a 100644
--- a/src/leap/bitmask/gui/eip_status.py
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -24,7 +24,6 @@ from functools import partial
 
 from PySide import QtCore, QtGui
 
-from leap.bitmask.config import flags
 from leap.bitmask.services import get_service_display_name, EIP_SERVICE
 from leap.bitmask.platform_init import IS_LINUX
 from leap.bitmask.util.averages import RateMovingAverage
@@ -123,8 +122,8 @@ class EIPStatusWidget(QtGui.QWidget):
         # XXX we cannot connect this signal now because
         # it interferes with the proper notifications during restarts
         # without available network.
-        #signaler.eip_network_unreachable.connect(
-            #self._on_eip_network_unreachable)
+        # signaler.eip_network_unreachable.connect(
+        #     self._on_eip_network_unreachable)
 
     def _make_status_clickable(self):
         """
@@ -326,7 +325,7 @@ class EIPStatusWidget(QtGui.QWidget):
         Triggered after a successful login.
         Enables the start button.
         """
-        #logger.debug('Showing EIP start button')
+        # logger.debug('Showing EIP start button')
         self.eip_button.show()
 
         # Restore the eip action menu
@@ -545,7 +544,7 @@ class EIPStatusWidget(QtGui.QWidget):
         elif vpn_state == "ALREADYRUNNING":
             # Put the following calls in Qt's event queue, otherwise
             # the UI won't update properly
-            #self.send_disconnect_signal()
+            # self.send_disconnect_signal()
             QtDelayedCall(
                 0, self.eipconnection.qtsigns.do_disconnect_signal.emit)
             msg = self.tr("Unable to start VPN, it's already running.")
@@ -738,7 +737,7 @@ class EIPStatusWidget(QtGui.QWidget):
         self.set_eip_status_icon("error")
 
     def set_eipstatus_off(self, error=True):
-    # XXX this should be handled by the state machine.
+        # XXX this should be handled by the state machine.
         """
         Sets eip status to off
         """
diff --git a/src/leap/bitmask/gui/statemachines.py b/src/leap/bitmask/gui/statemachines.py
index 00a1387e..91f1f605 100644
--- a/src/leap/bitmask/gui/statemachines.py
+++ b/src/leap/bitmask/gui/statemachines.py
@@ -240,9 +240,9 @@ class CompositeMachine(QStateMachine):
         c2.qtsigs.disconnected_signal.connect(self.off_ev2_slot)
 
     # XXX why is this getting deletec in c++?
-    #Traceback (most recent call last):
-    #self.postEvent(self.events.on_ev2)
-    #RuntimeError: Internal C++ object (ConnectedEvent2) already deleted.
+    # Traceback (most recent call last):
+    # self.postEvent(self.events.on_ev2)
+    # RuntimeError: Internal C++ object (ConnectedEvent2) already deleted.
     # XXX trying the following workaround, since
     # I cannot find why in the world this is getting deleted :(
     # XXX refactor!
@@ -318,9 +318,8 @@ class ConnectionMachineBuilder(object):
         components = self._conn.components
 
         if components is None:
-        # simple case: connection definition inherits directly from
-        # the abstract connection.
-
+            # simple case: connection definition inherits directly from
+            # the abstract connection.
             leap_assert_type(self._conn, connections.AbstractLEAPConnection)
             return self._make_simple_machine(self._conn, **kwargs)
 
diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py
index 2d800703..e4d6f9b3 100644
--- a/src/leap/bitmask/platform_init/initializers.py
+++ b/src/leap/bitmask/platform_init/initializers.py
@@ -21,7 +21,6 @@ import logging
 import os
 import platform
 import stat
-import sys
 import subprocess
 import tempfile
 
@@ -103,7 +102,7 @@ def get_missing_helpers_dialog():
     msg.setWindowTitle(msg.tr("Missing helper files"))
     msg.setText(msg.tr(WE_NEED_POWERS))
     # but maybe the user really deserve to know more
-    #msg.setInformativeText(msg.tr(BECAUSE))
+    # msg.setInformativeText(msg.tr(BECAUSE))
     msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
     msg.addButton("No, don't ask again", QtGui.QMessageBox.RejectRole)
     msg.setDefaultButton(QtGui.QMessageBox.Yes)
diff --git a/src/leap/bitmask/provider/providerbootstrapper.py b/src/leap/bitmask/provider/providerbootstrapper.py
index 5064f6a4..71edbb87 100644
--- a/src/leap/bitmask/provider/providerbootstrapper.py
+++ b/src/leap/bitmask/provider/providerbootstrapper.py
@@ -194,8 +194,8 @@ class ProviderBootstrapper(AbstractBootstrapper):
         verify = self.verify
 
         if mtime:  # the provider.json exists
-        # So, we're getting it from the api.* and checking against
-        # the provider ca.
+            # So, we're getting it from the api.* and checking against
+            # the provider ca.
             try:
                 provider_config = ProviderConfig()
                 provider_config.load(provider_json)
diff --git a/src/leap/bitmask/services/eip/conductor.py b/src/leap/bitmask/services/eip/conductor.py
index dfd27f3d..bb07809a 100644
--- a/src/leap/bitmask/services/eip/conductor.py
+++ b/src/leap/bitmask/services/eip/conductor.py
@@ -202,7 +202,7 @@ class EIPConductor(object):
             # we bypass the on_eip_disconnected here
             plug_restart_on_disconnected()
             self.qtsigs.disconnected_signal.emit()
-            #QtDelayedCall(0, self.qtsigs.disconnected_signal.emit)
+            # QtDelayedCall(0, self.qtsigs.disconnected_signal.emit)
             # ...and reconnect the original signal again, after having used the
             # diversion
             QtDelayedCall(500, reconnect_disconnected_signal)
@@ -301,7 +301,7 @@ class EIPConductor(object):
         # XXX FIXME --- check exitcode is != 0 really.
         # 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 exitCode != 0 and not self.user_stopped_eip:
         if not self.user_stopped_eip:
             eip_status_label = self._eip_status.tr(
                 "{0} finished in an unexpected manner!")
diff --git a/src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py b/src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py
index 6640a860..1888f2c9 100644
--- a/src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py
+++ b/src/leap/bitmask/services/eip/tests/test_eipbootstrapper.py
@@ -30,7 +30,7 @@ import time
 try:
     import unittest2 as unittest
 except ImportError:
-    import unittest
+    import unittest  # noqa - skip 'unused import' warning
 
 from nose.twistedtools import deferred, reactor
 from twisted.internet import threads
diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py
index e36fd76b..72e19413 100644
--- a/src/leap/bitmask/services/eip/vpnlauncher.py
+++ b/src/leap/bitmask/services/eip/vpnlauncher.py
@@ -169,11 +169,11 @@ class VPNLauncher(object):
         leap_assert_type(providerconfig, ProviderConfig)
 
         # XXX this still has to be changed on osx and windows accordingly
-        #kwargs = {}
-        #openvpn_possibilities = which(kls.OPENVPN_BIN, **kwargs)
-        #if not openvpn_possibilities:
-            #raise OpenVPNNotFoundException()
-        #openvpn = first(openvpn_possibilities)
+        # kwargs = {}
+        # openvpn_possibilities = which(kls.OPENVPN_BIN, **kwargs)
+        # if not openvpn_possibilities:
+        #     raise OpenVPNNotFoundException()
+        # openvpn = first(openvpn_possibilities)
         # -----------------------------------------
         openvpn_path = force_eval(kls.OPENVPN_BIN_PATH)
 
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index 1c11a337..d1a3fdaa 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -817,7 +817,7 @@ class VPNProcess(protocol.ProcessProtocol, VPNManager):
         leap_assert_type(eipconfig, EIPConfig)
         leap_assert_type(providerconfig, ProviderConfig)
 
-        #leap_assert(not self.isRunning(), "Starting process more than once!")
+        # leap_assert(not self.isRunning(), "Starting process more than once!")
 
         self._eipconfig = eipconfig
         self._providerconfig = providerconfig
diff --git a/src/leap/bitmask/services/mail/plumber.py b/src/leap/bitmask/services/mail/plumber.py
index fa33afcd..1af65c5d 100644
--- a/src/leap/bitmask/services/mail/plumber.py
+++ b/src/leap/bitmask/services/mail/plumber.py
@@ -232,8 +232,8 @@ class MBOXPlumber(object):
 
         with open(mail_filename) as f:
             mail_string = f.read()
-            #uid = self._mbox.getUIDNext()
-            #print "saving with UID: %s" % uid
+            # uid = self._mbox.getUIDNext()
+            # print "saving with UID: %s" % uid
             d = self._mbox.messages.add_msg(
                 mail_string, notify_on_disk=True)
         return d
diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
index a5904dce..c4e43bfe 100644
--- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py
+++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
@@ -134,7 +134,7 @@ class SoledadBootstrapper(AbstractBootstrapper):
     MAX_INIT_RETRIES = 10
     MAX_SYNC_RETRIES = 10
     WAIT_MAX_SECONDS = 600
-    #WAIT_STEP_SECONDS = 1
+    # WAIT_STEP_SECONDS = 1
     WAIT_STEP_SECONDS = 5
 
     def __init__(self, signaler=None):
diff --git a/src/leap/bitmask/services/tests/test_abstractbootstrapper.py b/src/leap/bitmask/services/tests/test_abstractbootstrapper.py
index 3ac126ac..c3fda9e1 100644
--- a/src/leap/bitmask/services/tests/test_abstractbootstrapper.py
+++ b/src/leap/bitmask/services/tests/test_abstractbootstrapper.py
@@ -1,4 +1,4 @@
-## -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
 # test_abstrctbootstrapper.py
 # Copyright (C) 2013 LEAP
 #
diff --git a/src/leap/bitmask/util/leap_argparse.py b/src/leap/bitmask/util/leap_argparse.py
index c7fed0a3..cbd6d8a5 100644
--- a/src/leap/bitmask/util/leap_argparse.py
+++ b/src/leap/bitmask/util/leap_argparse.py
@@ -107,19 +107,19 @@ def build_parser():
                              'against domains.')
 
     # Not in use, we might want to reintroduce them.
-    #parser.add_argument('-i', '--no-provider-checks',
-                        #action="store_true", default=False,
-                        #help="skips download of provider config files. gets "
-                        #"config from local files only. Will fail if cannot "
-                        #"find any")
-    #parser.add_argument('-k', '--no-ca-verify',
-                        #action="store_true", default=False,
-                        #help="(insecure). Skips verification of the server "
-                        #"certificate used in TLS handshake.")
-    #parser.add_argument('-c', '--config', metavar="CONFIG FILE", nargs='?',
-                        #action="store", dest="config_file",
-                        #type=argparse.FileType('r'),
-                        #help='optional config file')
+    # parser.add_argument('-i', '--no-provider-checks',
+    #                     action="store_true", default=False,
+    #                     help="skips download of provider config files. gets "
+    #                     "config from local files only. Will fail if cannot "
+    #                     "find any")
+    # parser.add_argument('-k', '--no-ca-verify',
+    #                     action="store_true", default=False,
+    #                     help="(insecure). Skips verification of the server "
+    #                     "certificate used in TLS handshake.")
+    # parser.add_argument('-c', '--config', metavar="CONFIG FILE", nargs='?',
+    #                     action="store", dest="config_file",
+    #                     type=argparse.FileType('r'),
+    #                     help='optional config file')
     return parser
 
 
diff --git a/src/leap/bitmask/util/polkit_agent.py b/src/leap/bitmask/util/polkit_agent.py
index 6fda2f88..7764f571 100644
--- a/src/leap/bitmask/util/polkit_agent.py
+++ b/src/leap/bitmask/util/polkit_agent.py
@@ -39,9 +39,9 @@ def _launch_agent():
         logger.error('Exception while running polkit authentication agent '
                      '%s' % (exc,))
         # XXX fix KDE launch. See: #3755
-        #try:
-            #subprocess.call(KDE_PATH)
-        #except Exception as exc:
+        # try:
+        #     subprocess.call(KDE_PATH)
+        # except Exception as exc:
 
 
 def launch():
diff --git a/src/leap/bitmask/util/privilege_policies.py b/src/leap/bitmask/util/privilege_policies.py
index adc3503f..f894d73b 100644
--- a/src/leap/bitmask/util/privilege_policies.py
+++ b/src/leap/bitmask/util/privilege_policies.py
@@ -87,8 +87,8 @@ class LinuxPolicyChecker(PolicyChecker):
                 else self.LINUX_POLKIT_FILE)
 
     def is_missing_policy_permissions(self):
-    # FIXME this name is quite confusing, it does not have anything to do with
-    # file permissions.
+        # FIXME this name is quite confusing, it does not have anything to do
+        # with file permissions.
         """
         Returns True if we could not find the appropriate policykit file
         in place
-- 
cgit v1.2.3


From 3d6629348aedf2a6863d242d96d64b3492e86f9a Mon Sep 17 00:00:00 2001
From: Ivan Alejandro <ivanalejandro0@gmail.com>
Date: Wed, 16 Jul 2014 11:29:19 -0300
Subject: Increase timeout and retries.

With this change we avoid the communication issues on OSX.
---
 src/leap/bitmask/backend/signaler.py | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

(limited to 'src')

diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py
index 7401f3a0..574bfa71 100644
--- a/src/leap/bitmask/backend/signaler.py
+++ b/src/leap/bitmask/backend/signaler.py
@@ -38,8 +38,8 @@ class Signaler(object):
     """
     PORT = "5667"
     SERVER = "tcp://localhost:%s" % PORT
-    POLL_TIMEOUT = 1000  # ms
-    POLL_TRIES = 3
+    POLL_TIMEOUT = 2000  # ms
+    POLL_TRIES = 500
 
     def __init__(self):
         """
@@ -156,13 +156,18 @@ class Signaler(object):
         reply = None
         tries = 0
 
-        while tries < self.POLL_TRIES:
+        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."
-- 
cgit v1.2.3