diff --git a/.gitignore b/.gitignore
index 0e5bb658485b67745125a9a4c5a64e555fbfee78..23bfbfe80a21cf0046214fb2a595707b245fed33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,7 @@ pkg/osx/build
 
 src/*.egg-info
 src/pysqlcipher
+src/leap/bitmask/_binaries.py
 src/leap/bitmask/util/reqs.txt
 MANIFEST
 _trial_temp*
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4faceb98c75f1ec652543eb1133d2e5605dbd763..92da15730ae06e5e96c57826690f37174907973d 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,22 @@ History
 2014
 ====
 
+0.5.3 June 27 -- the "encrypt ALL THE THINGS" release:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+- Disable EIP if the helper files were not installed. Closes #5818.
+- Install helpers to /usr/local for bundle. Closes #5741.
+- Improve how pinned providers are handled by hardcoding it instead of
+  expecting them to be in the config. Closes #4733.
+- Remove deprecated policy files. Closes #5651.
+- Install helper files only if standalone=True. Related to #5625
+- Use installer helper from within bundle path. Related to #5634
+- Pin Riseup as a provider. Closes #5783.
+- Update the bundled binaries to their path if their sha256 is not
+  correct. Closes #5759.
+- Use a dict instead an object to ease later serialization of
+  ProviderConfig.
+
 0.5.2 June 6 -- the "are we there yet" release:
 +++++++++++++++++++++++++++++++++++++++++++++++
 
diff --git a/data/ts/en_US.ts b/data/ts/en_US.ts
index 562df1a34fe5630556d16178380e7a2af16f6af6..cf74d7b6e719ef005d056b3835e6a8f1d94cc3fe 100644
--- a/data/ts/en_US.ts
+++ b/data/ts/en_US.ts
@@ -68,96 +68,114 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="60"/>
-        <source>&lt;span style=&apos;color:#0000FF;&apos;&gt;NOTE&lt;/span&gt;: To use this, you need to enable/start {0}.</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="99"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="119"/>
         <source>Open keys file</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="191"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="237"/>
         <source>Input/Output error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="112"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="158"/>
         <source>There was an error accessing the file.
 Import canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="122"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="169"/>
         <source>Data mismatch</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="125"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="172"/>
         <source>The public and private key should have the same address and fingerprint.
 Import canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="130"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="183"/>
         <source>Missing key</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="133"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="186"/>
         <source>You need to provide the public AND private key in the same file.
 Import canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="139"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="197"/>
         <source>Address mismatch</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="142"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="200"/>
         <source>The identity for the key needs to be the same as your user address.
 Import canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="147"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="125"/>
         <source>Are you sure that you want to replace the current key pair whith the imported?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="164"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="144"/>
         <source>Import Successful</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="165"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="145"/>
         <source>The key pair was imported successfully.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="174"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="207"/>
         <source>Save keys file</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="185"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="224"/>
         <source>Export Successful</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="187"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="226"/>
         <source>The key pair was exported successfully.
 Please, store your private key in a safe place.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="193"/>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="239"/>
         <source>There was an error accessing the file.
 Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="59"/>
+        <source>The provider that you are using does not support {0}.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="65"/>
+        <source>To use this, you need to enable/start {0}.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/advanced_key_management.py" line="110"/>
+        <source>&lt;span style=&apos;color:#0000FF;&apos;&gt;NOTE&lt;/span&gt;: </source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ComplainDialog</name>
+    <message>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="419"/>
+        <source>Ok, thanks</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>EIPPreferences</name>
@@ -210,22 +228,22 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_preferenceswindow.py" line="125"/>
+        <location filename="../src/leap/bitmask/gui/eip_preferenceswindow.py" line="153"/>
         <source>Gateway settings for provider &apos;{0}&apos; saved.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_preferenceswindow.py" line="179"/>
+        <location filename="../src/leap/bitmask/gui/eip_preferenceswindow.py" line="230"/>
         <source>There was a problem with configuration files.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_preferenceswindow.py" line="101"/>
+        <location filename="../src/leap/bitmask/gui/eip_preferenceswindow.py" line="122"/>
         <source> (uninitialized)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_preferenceswindow.py" line="151"/>
+        <location filename="../src/leap/bitmask/gui/eip_preferenceswindow.py" line="245"/>
         <source>This is an uninitialized provider, please log in first.</source>
         <translation type="unfinished"></translation>
     </message>
@@ -253,88 +271,158 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/eip_status.ui" line="212"/>
+        <location filename="../src/leap/bitmask/gui/ui/eip_status.ui" line="213"/>
         <source>0.0 KB/s</source>
         <translation type="unfinished"></translation>
     </message>
-</context>
-<context>
-    <name>EIPStatusWidget</name>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="327"/>
-        <source>Turn OFF</source>
+        <location filename="../src/leap/bitmask/gui/ui/eip_status.ui" line="245"/>
+        <source>Turn Off</source>
         <translation type="unfinished"></translation>
     </message>
+</context>
+<context>
+    <name>EIPStatusWidget</name>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="341"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="411"/>
         <source>Turn ON</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="348"/>
-        <source>Traffic is being routed in the clear</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="405"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="521"/>
         <source>Authenticating...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="407"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="529"/>
         <source>Retrieving configuration...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="409"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="531"/>
         <source>Waiting to start...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="411"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="533"/>
         <source>Assigning IP</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="413"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="535"/>
         <source>Reconnecting...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="420"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="543"/>
         <source>Unable to start VPN, it&apos;s already running.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="463"/>
-        <source>Route traffic through: {0}</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="260"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="304"/>
         <source>disabled</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="442"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="565"/>
         <source>{0}: OFF</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="257"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="301"/>
         <source>You must login to use {0}</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="447"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="570"/>
         <source>{0}: Starting...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/eip_status.py" line="450"/>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="573"/>
         <source>{0}: ON</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="525"/>
+        <source>Encrypted Internet is starting</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="397"/>
+        <source>Retry</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="433"/>
+        <source>Traffic is being routed in the clear.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="434"/>
+        <source>Network is unreachable.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="436"/>
+        <source>Error connecting</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="451"/>
+        <source>Error connecting.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="454"/>
+        <source>Bitmask is blocking unencrypted traffic.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="587"/>
+        <source>Routing traffic through: &lt;b&gt;{0}&lt;/b&gt;</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="634"/>
+        <source>Could not load {0} configuration.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="643"/>
+        <source>Another openvpn instance is already running, and could not be stopped.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="653"/>
+        <source>Another openvpn instance is already running, and could not be stopped because it was not launched by Bitmask. Please stop it and try again.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="661"/>
+        <source>We could not find openvpn binary.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="682"/>
+        <source>We could not find any authentication agent in your system.&lt;br/&gt;Make sure you have&lt;b&gt;polkit-gnome-authentication-agent-1&lt;/b&gt; running andtry again.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="690"/>
+        <source>We could not find &lt;b&gt;pkexec&lt;/b&gt; in your system.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="700"/>
+        <source>{0} cannot be started because the tuntap extension is not installed properly in your system.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/eip_status.py" line="720"/>
+        <source>Network is unreachable</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>LoggerWindow</name>
@@ -399,25 +487,30 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="224"/>
+        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="225"/>
         <source>Your pastebin link &lt;a href=&apos;{0}&apos;&gt;{0}&lt;/a&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="227"/>
+        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="230"/>
         <source>Pastebin OK</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="240"/>
+        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="245"/>
         <source>Sending logs to Pastebin failed!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="241"/>
+        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="251"/>
         <source>Pastebin Error</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/loggerwindow.py" line="250"/>
+        <source>Maximum posts per day reached</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>LoginWidget</name>
@@ -447,17 +540,17 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="247"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="246"/>
         <source>Log In</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="125"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="124"/>
         <source>Other...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="242"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="241"/>
         <source>Cancel</source>
         <translation type="unfinished"></translation>
     </message>
@@ -467,32 +560,32 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="368"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="371"/>
         <source>Logout</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="296"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="299"/>
         <source>Please select a valid provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="301"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="304"/>
         <source>Please provide a valid username</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="306"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="309"/>
         <source>Please provide a valid password</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="309"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="312"/>
         <source>Logging in...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/login.py" line="361"/>
+        <location filename="../src/leap/bitmask/gui/login.py" line="364"/>
         <source>Logging out...</source>
         <translation type="unfinished"></translation>
     </message>
@@ -515,206 +608,196 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="192"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="196"/>
         <source>There was an unexpected problem with Soledad.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="413"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="432"/>
         <source>OFF</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="209"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="224"/>
         <source>Mail is OFF</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="217"/>
-        <source>Starting..</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="218"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="233"/>
         <source>Mail is starting</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="436"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="455"/>
         <source>ON</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="222"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="237"/>
         <source>Mail is ON</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="225"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="240"/>
         <source>Mail is disabled</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="422"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="441"/>
         <source>Starting...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="254"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="270"/>
         <source>Soledad has started...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="256"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="272"/>
         <source>Soledad is starting, please wait...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="291"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="308"/>
         <source>Looking for key for this user</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="295"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="312"/>
         <source>Found key! Starting mail...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="300"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="317"/>
         <source>Finished generating key!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="302"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="319"/>
         <source>Starting mail...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="334"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="352"/>
         <source>SMTP failed to start, check the logs.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="390"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="409"/>
         <source>About to start, please wait...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="397"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="416"/>
         <source>Disabled</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="162"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="166"/>
         <source>{0}: OFF</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="444"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="463"/>
         <source>You must be logged in to use {0}.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="298"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="315"/>
         <source>Generating new key, this may take a few minutes.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="373"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="392"/>
         <source>{0} Unread Emails in your Inbox</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="377"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="396"/>
         <source>1 Unread Email in your Inbox</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mail_status.py" line="429"/>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="448"/>
         <source>Disconnecting...</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="474"/>
+        <source>Invalid auth token, try logging in again.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mail_status.py" line="232"/>
+        <source>Starting&#xe2;&#x80;&#xa6;</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>MainWindow</name>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="238"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="228"/>
         <source>There are new updates available, please restart.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="280"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="270"/>
         <source>More...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="758"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="870"/>
         <source>Help</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="352"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="342"/>
         <source>&amp;Quit</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="362"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="352"/>
         <source>&amp;Help</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="367"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="357"/>
         <source>&amp;Wizard</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="806"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="930"/>
         <source>Hide Main Window</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="638"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="728"/>
         <source> The following components will be updated:
 %s</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="641"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="731"/>
         <source>Updates available</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="805"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="929"/>
         <source>Show Main Window</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1524"/>
-        <source>We could not find any authentication agent in your system.&lt;br/&gt;Make sure you have &lt;b&gt;polkit-gnome-authentication-agent-1&lt;/b&gt; running and try again.</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1536"/>
-        <source>We could not find &lt;b&gt;pkexec&lt;/b&gt; in your system.</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1541"/>
-        <source>We could not find openvpn binary.</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1705"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1548"/>
         <source>Starting...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1719"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1563"/>
         <source>Not supported</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1723"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1567"/>
         <source>Disabled</source>
         <translation type="unfinished"></translation>
     </message>
@@ -724,173 +807,203 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="357"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="347"/>
         <source>About &amp;Bitmask</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="289"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="211"/>
         <source>Mail is OFF</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="629"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="719"/>
         <source>The Bitmask app is ready to update, please restart the application.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="870"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="996"/>
         <source>About Bitmask - %s</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1011"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1138"/>
         <source>Unable to login: Problem with provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1089"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1219"/>
         <source>Log in cancelled by the user.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1547"/>
-        <source>Another openvpn instance is already running, and could not be stopped.</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1554"/>
-        <source>Another openvpn instance is already running, and could not be stopped because it was not launched by Bitmask. Please stop it and try again.</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1740"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1584"/>
         <source>There was a problem with the provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1845"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1639"/>
         <source>Something went wrong with the logout.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1864"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1606"/>
         <source>Unable to connect: Problem with provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1836"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1651"/>
         <source>Login</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="315"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="305"/>
         <source>&amp;Bitmask</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="372"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="362"/>
         <source>Show &amp;Log</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="377"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="367"/>
         <source>Create a new account...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="278"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="201"/>
         <source>File</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1606"/>
-        <source>Network is unreachable</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="123"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="121"/>
         <source>Please Log In</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="342"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="332"/>
         <source>Account Preferences...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="347"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="337"/>
         <source>Internet Preferences...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="385"/>
+        <location filename="../src/leap/bitmask/gui/ui/mainwindow.ui" line="375"/>
         <source>Advanced Key Management</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="742"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="854"/>
         <source> (offline mode)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="765"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="878"/>
         <source>OFF</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="884"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1010"/>
         <source>Version: &lt;b&gt;%s&lt;/b&gt; (%s)&lt;br&gt;&lt;br&gt;%sBitmask is the Desktop client application for the LEAP platform, supporting encrypted internet proxy, secure email, and secure chat (coming soon).&lt;br&gt;&lt;br&gt;LEAP is a non-profit dedicated to giving all internet users access to secure communication. Our focus is on adapting encryption technology to make it easy to use and widely available. &lt;br&gt;&lt;br&gt;&lt;a href=&apos;https://leap.se&apos;&gt;More about LEAP&lt;/a&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="911"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1038"/>
         <source>&lt;strong&gt;Instructions to use mail:&lt;/strong&gt;&lt;br&gt;If you use Thunderbird you can use the Bitmask extension helper. Search for &apos;Bitmask&apos; in the add-on manager or download it from: {0}.&lt;br&gt;&lt;br&gt;You can configure Bitmask manually with these options:&lt;br&gt;&lt;em&gt;   Incoming -&gt; IMAP, port: {1}&lt;br&gt;   Outgoing -&gt; SMTP, port: {2}&lt;br&gt;   Username -&gt; your bitmask username.&lt;br&gt;   Password -&gt; does not matter, use any text.  Just don&apos;t leave it empty and don&apos;t use your account&apos;s password.&lt;/em&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="912"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1039"/>
         <source>Bitmask Help</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="924"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1051"/>
         <source>The current client version is not supported by this provider.&lt;br&gt;Please update to latest version.&lt;br&gt;&lt;br&gt;You can get the latest version from &lt;a href=&apos;{0}&apos;&gt;{1}&lt;/a&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="925"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1052"/>
         <source>Update Needed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="935"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1062"/>
         <source>This provider is not compatible with the client.&lt;br&gt;&lt;br&gt;Error: API version incompatible.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="935"/>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1062"/>
         <source>Incompatible Provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1757"/>
-        <source>Could not load {0} configuration.</source>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="302"/>
+        <source>Application error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1531"/>
-        <source>{0} cannot be started because the tuntap extension is not installed properly in your system.</source>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="304"/>
+        <source>You are trying to do an operation that requires logging in first.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1670"/>
-        <source>{0} could not be launched because you did not authenticate properly.</source>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="362"/>
+        <source>Unknown error.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1677"/>
-        <source>{0} finished in an unexpected manner!</source>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="366"/>
+        <source>There was a server problem with authentication.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="370"/>
+        <source>Could not establish a connection.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="374"/>
+        <source>Invalid username or password.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="897"/>
+        <source>Hello!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="898"/>
+        <source>Bitmask has started in the tray.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1252"/>
+        <source>Succeeded</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1501"/>
+        <source>The server at {0} can&apos;t be found, because the DNS lookup failed. DNS is the network service that translates a website&apos;s name to its Internet address. Either your computer is having trouble connecting to the network, or you are missing some helper files that are needed to securely use DNS while {1} is active. To install these helper files, quit this application and start it again.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1504"/>
+        <source>Connection Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1748"/>
+        <source>Quitting...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/mainwindow.py" line="1749"/>
+        <source>Bitmask is quitting, please wait.</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -965,47 +1078,47 @@ Export canceled.</source>
 <context>
     <name>PreferencesWindow</name>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="63"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="59"/>
         <source>Automatic</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="159"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="168"/>
         <source>Changing password...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="210"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="249"/>
         <source>Password changed successfully.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="225"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="433"/>
         <source>There was a problem changing the password.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="228"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="437"/>
         <source>You did not enter a correct current password.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="371"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="417"/>
         <source>Services settings for provider &apos;{0}&apos; saved.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="97"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="114"/>
         <source>You need to enable {0} in order to change the password.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="103"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="122"/>
         <source>You need to wait until {0} is ready in order to change the password.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="113"/>
+        <location filename="../src/leap/bitmask/gui/preferenceswindow.py" line="101"/>
         <source>In order to change your password you need to be logged in.</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1013,24 +1126,16 @@ Export canceled.</source>
 <context>
     <name>ProviderBootstrapper</name>
     <message>
-        <location filename="../src/leap/bitmask/provider/providerbootstrapper.py" line="146"/>
+        <location filename="../src/leap/bitmask/provider/providerbootstrapper.py" line="154"/>
         <source>Provider certificate could not be verified</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/provider/providerbootstrapper.py" line="153"/>
+        <location filename="../src/leap/bitmask/provider/providerbootstrapper.py" line="161"/>
         <source>Provider does not support HTTPS</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
-<context>
-    <name>SRPAuth</name>
-    <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="714"/>
-        <source>Succeeded</source>
-        <translation type="unfinished"></translation>
-    </message>
-</context>
 <context>
     <name>Wizard</name>
     <message>
@@ -1059,7 +1164,7 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="298"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="340"/>
         <source>Check</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1084,195 +1189,180 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="336"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="353"/>
         <source>Provider Information</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="339"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="356"/>
         <source>Description of services offered by this provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="348"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="365"/>
         <source>Name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="380"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="397"/>
         <source>Desc</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="390"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="407"/>
         <source>&lt;b&gt;Services offered:&lt;/b&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="400"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="417"/>
         <source>services</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="420"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="437"/>
         <source>&lt;b&gt;Enrollment policy:&lt;/b&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="430"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="447"/>
         <source>policy</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="450"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="467"/>
         <source>&lt;b&gt;URL:&lt;/b&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="460"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="477"/>
         <source>URL</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="467"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="484"/>
         <source>&lt;b&gt;Description:&lt;/b&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="478"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="495"/>
         <source>Provider setup</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="481"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="498"/>
         <source>Gathering configuration options for this provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="503"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="520"/>
         <source>We are downloading some bits that we need to establish a secure connection with the provider for the first time.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="526"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="543"/>
         <source>Setting up provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="576"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="593"/>
         <source>Getting info from the Certificate Authority</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="583"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="600"/>
         <source>Do we trust this Certificate Authority?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="590"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="607"/>
         <source>Establishing a trust relationship with this provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="649"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="666"/>
         <source>Register new user</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="652"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="669"/>
         <source>Register a new user with provider</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="667"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="684"/>
         <source>&lt;b&gt;Password:&lt;/b&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="694"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="711"/>
         <source>&lt;b&gt;Re-enter password:&lt;/b&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="704"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="721"/>
         <source>Register</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="750"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="767"/>
         <source>Remember my username and password</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="774"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="791"/>
         <source>Service selection</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="777"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="794"/>
         <source>Please select the services you would like to have</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="132"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="131"/>
         <source>&amp;Next &gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="134"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="133"/>
         <source>Connect</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="265"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="289"/>
         <source>Starting registration...</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="296"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="333"/>
         <source>User %s successfully registered.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="448"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="503"/>
         <source>&lt;font color=&apos;red&apos;&gt;&lt;b&gt;Non-existent provider&lt;/b&gt;&lt;/font&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="466"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="522"/>
         <source>&lt;font color=&apos;red&apos;&gt;&lt;b&gt;%s&lt;/b&gt;&lt;/font&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="492"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="551"/>
         <source>Unable to load provider configuration</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="498"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="557"/>
         <source>&lt;font color=&apos;red&apos;&gt;&lt;b&gt;Not a valid provider&lt;/b&gt;&lt;/font&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="565"/>
-        <source>Services by %s</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="585"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="662"/>
         <source>Something went wrong while trying to load service %s</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="616"/>
-        <source>Description of services offered by %s</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="637"/>
-        <source>Register a new user with %s</source>
-        <translation type="unfinished"></translation>
-    </message>
     <message>
         <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="26"/>
         <source>Bitmask first run</source>
@@ -1289,7 +1379,7 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="737"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="754"/>
         <source>&lt;b&gt;Username:&lt;/b&gt;</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1299,7 +1389,7 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="288"/>
+        <location filename="../src/leap/bitmask/gui/ui/wizard.ui" line="275"/>
         <source>Configure new provider:</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1314,114 +1404,130 @@ Export canceled.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="317"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="360"/>
         <source>Something has gone wrong. Please try again.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/gui/wizard.py" line="607"/>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="688"/>
         <source>Gathering configuration options for {0}</source>
         <translation type="unfinished"></translation>
     </message>
-</context>
-<context>
-    <name>__impl</name>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="298"/>
-        <source>The server did not send the salt parameter</source>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="374"/>
+        <source>The requested username is taken, choose another.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="643"/>
+        <source>Services by {0}</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="696"/>
+        <source>Description of services offered by {0}</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="302"/>
-        <source>The server did not send the B parameter</source>
+        <location filename="../src/leap/bitmask/gui/wizard.py" line="711"/>
+        <source>Register a new user with {0}</source>
         <translation type="unfinished"></translation>
     </message>
+</context>
+<context>
+    <name>msg</name>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="334"/>
-        <source>The data sent from the server had errors</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="200"/>
+        <source>TAP Driver</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="356"/>
-        <source>Could not connect to the server</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="207"/>
+        <source>Encrypted Internet uses VPN, which needs a TAP device installed and none has been found. This will ask for administrative privileges.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="382"/>
-        <source>Unknown error (%s)</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="325"/>
+        <source>TUN Driver</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="413"/>
-        <source>Problem getting data from server</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="333"/>
+        <source>Encrypted Internet uses VPN, which needs a kernel extension for a TUN device installed, and none has been found. This will ask for administrative privileges.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="439"/>
-        <source>Bad data from server</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="142"/>
+        <source>Problem installing files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="446"/>
-        <source>Auth verification failed</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="143"/>
+        <source>Some of the files could not be copied.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="454"/>
-        <source>Session cookie verification failed</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="328"/>
+        <source>Bitmask needs to install the necessary drivers for Encrypted Internet to work. Would you like to proceed?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="289"/>
-        <source>There was a problem with authentication</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="92"/>
+        <source>Missing helper files</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/crypto/srpauth.py" line="178"/>
-        <source>Invalid username or password.</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="380"/>
+        <source>Missing resolvconf framework</source>
         <translation type="unfinished"></translation>
     </message>
-</context>
-<context>
-    <name>msg</name>
     <message>
-        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="93"/>
-        <source>Missing up/down scripts</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="432"/>
+        <source>Missing Bitmask helpers</source>
         <translation type="unfinished"></translation>
     </message>
+</context>
+<context>
+    <name>msgstr</name>
     <message>
-        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="184"/>
-        <source>TAP Driver</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="375"/>
+        <source>Could not find &lt;b&gt;resolvconf&lt;/b&gt; installed in your system.
+Do you want to quit Bitmask now?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="191"/>
-        <source>Encrypted Internet uses VPN, which needs a TAP device installed and none has been found. This will ask for administrative privileges.</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="379"/>
+        <source>Encrypted Internet needs resolvconf installed to work properly.
+Please use your package manager to install it.
+</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="310"/>
-        <source>TUN Driver</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="401"/>
+        <source>Some essential helper files are missing in your system.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="318"/>
-        <source>Encrypted Internet uses VPN, which needs a kernel extension for a TUN device installed, and none has been found. This will ask for administrative privileges.</source>
+        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="404"/>
+        <source>Reinstall your debian packages, or make sure you place them by hand.</source>
         <translation type="unfinished"></translation>
     </message>
+</context>
+<context>
+    <name>self._eip_status</name>
     <message>
-        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="132"/>
-        <source>Problem installing files</source>
+        <location filename="../src/leap/bitmask/services/eip/conductor.py" line="184"/>
+        <source>{0} is restarting</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="133"/>
-        <source>Some of the files could not be copied.</source>
+        <location filename="../src/leap/bitmask/services/eip/conductor.py" line="295"/>
+        <source>{0} could not be launched because you did not authenticate properly.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../src/leap/bitmask/platform_init/initializers.py" line="313"/>
-        <source>Bitmask needs to install the necessary drivers for Encrypted Internet to work. Would you like to proceed?</source>
+        <location filename="../src/leap/bitmask/services/eip/conductor.py" line="307"/>
+        <source>{0} finished in an unexpected manner!</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
diff --git a/pkg/linux/README.rst b/pkg/linux/README.rst
index 220565ff2a1128fc4e92ac60a570fc88d30280be..f89842d3921c5fe9bc2f4403b4aa6d2c3b571bb2 100644
--- a/pkg/linux/README.rst
+++ b/pkg/linux/README.rst
@@ -3,8 +3,38 @@ Files
 
 In GNU/Linux, we expect these files to be in place::
 
- update-resolv-conf -> /etc/leap/update-resolv-conf
- resolv-update -> /etc/leap/resolv-update
-
  bitmask-root -> /usr/sbin/bitmask-root
  polkit/se.leap.bitmask.policy -> /usr/share/polkit-1/actions/se.leap.bitmask.policy
+
+Bundle
+======
+
+The bundle will ask for permission to install to a different path. This search
+path will be used if the flag ``--standalone`` is set::
+
+ bitmask-root -> /usr/local/sbin/bitmask-root
+ polkit/se.leap.bitmask.bundle.policy -> /usr/share/polkit-1/actions/se.leap.bitmask.bundle.policy
+
+When running with ``--standalone`` flag, the openvpn binary is  expected in the following path::
+
+ leap-openvpn -> /usr/local/sbin/leap-openvpn
+
+The bundle will use the script ``leap-install-helper.sh`` to copy the needed
+files. If you ever want to use it manually to update the helpers or bins, it
+needs a ``--from-path`` parameter to be passed to it. This points to a folder
+from where all the needed binaries and scripts can be found.
+
+
+Binary hashing
+==============
+
+To be able to update the binaries when needed, the bundles distribute with the
+sha256 hash of the packaged binaries for each release. This info can be found
+in::
+
+  src/leap/bitmask/_binaries.py
+
+That file is generated during the bundling process, by issuing the following
+command from the root folder::
+
+  python setup.py hash_binaries
diff --git a/pkg/linux/bitmask-root b/pkg/linux/bitmask-root
index 1929b51ba1a297e2071b9a261303fe71d8884bf5..5367a31c24ff9e9b90948d4ad200de4c7db684fd 100755
--- a/pkg/linux/bitmask-root
+++ b/pkg/linux/bitmask-root
@@ -67,7 +67,7 @@ OPENVPN_USER = "nobody"
 OPENVPN_GROUP = "nogroup"
 LEAPOPENVPN = "LEAPOPENVPN"
 OPENVPN_SYSTEM_BIN = "/usr/sbin/openvpn"  # Debian location
-OPENVPN_LEAP_BIN = "/usr/sbin/leap-openvpn"  # installed by bundle
+OPENVPN_LEAP_BIN = "/usr/local/sbin/leap-openvpn"  # installed by bundle
 
 
 """
diff --git a/pkg/linux/leap-install-helper.sh b/pkg/linux/leap-install-helper.sh
new file mode 100755
index 0000000000000000000000000000000000000000..566dd3d9190df1f7d9abee27e4b2c5afc38d7fa8
--- /dev/null
+++ b/pkg/linux/leap-install-helper.sh
@@ -0,0 +1,173 @@
+#!/bin/bash
+
+# File: leap-install-helper.sh
+# Copy the needed binaries and helper files to their destination.
+# Copyright (C) 2014 LEAP Encryption Access Project.
+#
+# 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/>.
+
+LOCAL_SBIN_FOLDER=/usr/local/sbin
+
+POLKIT_FOLDER="/usr/share/polkit-1/actions"
+POLKIT_FILE="se.leap.bitmask.bundle.policy"
+POLKIT_PATH="${POLKIT_FOLDER}/${POLKIT_FILE}"
+
+BITMASK_ROOT_FILE="bitmask-root"
+BITMASK_ROOT_PATH="${LOCAL_SBIN_FOLDER}/${BITMASK_ROOT_FILE}"
+
+OPENVPN_FILE="leap-openvpn"
+OPENVPN_PATH="${LOCAL_SBIN_FOLDER}/${OPENVPN_FILE}"
+
+# The following array stores global files that have been deprecated and we want
+# to remove from the system path, after having dropped them there in the past.
+
+DEPRECATED_FILES=(
+  '/usr/share/polkit-1/actions/net.openvpn.gui.leap.policy'
+)
+
+
+# Variables for parsing and storing the script options.
+
+FROM_PATH=NONE
+REMOVE_OLD_FILES=NO
+INSTALL_BITMASK_ROOT=NO
+INSTALL_POLKIT_FILE=NO
+INSTALL_OPENVPN=NO
+
+
+# Process the options
+
+while [[ $# > 1 ]]
+do
+key="$1"
+shift
+
+case $key in
+    -f|--from-path)
+    FROM_PATH="$1"
+    shift
+    ;;
+    -r|--remove-old-files)
+    REMOVE_OLD_FILES="$1"
+    shift
+    ;;
+    --install-bitmask-root)
+    INSTALL_BITMASK_ROOT="$1"
+    shift
+    ;;
+    --install-polkit-file)
+    INSTALL_POLKIT_FILE="$1"
+    shift
+    ;;
+    --install-openvpn)
+    INSTALL_OPENVPN="$1"
+    shift
+    ;;
+    *)
+    # unknown option
+    ;;
+esac
+done
+echo "LEAP_INSTALL_HELPER"
+echo "-------------------"
+echo FROM_PATH	          = "${FROM_PATH}"
+echo REMOVE_OLD_FILES     = "${REMOVE_OLD_FILES}"
+echo INSTALL_BITMASK_ROOT = "${INSTALL_BITMASK_ROOT}"
+echo INSTALL_POLKIT_FILE  = "${INSTALL_POLKIT_FILE}"
+echo INSTALL_OPENVPN      = "${INSTALL_OPENVPN}"
+echo
+
+
+#
+# helper functions
+#
+
+function check_current_uid() {
+  current_uid=`id | sed 's/^uid=//;s/(.*$//'`
+  if [ $current_uid != 0 ]
+  then
+    echo "[ERROR] NEED TO BE RUN AS ROOT"
+    exit 1
+  fi
+}
+
+function check_from_path() {
+  if [ $FROM_PATH == NONE ]
+  then
+    echo "[ERROR] YOU NEED TO GIVE --from-path VALUE..."
+    exit 1
+  fi
+}
+
+function remove_old_files() {
+  for file in "${DEPRECATED_FILES[@]}"
+  do
+    rm $file
+  done
+}
+
+function copy_bitmask_root() {
+  mkdir -p "${LOCAL_SBIN_FOLDER}"
+  cp "${FROM_PATH}/${BITMASK_ROOT_FILE}" "${BITMASK_ROOT_PATH}"
+  chmod 744 "${BITMASK_ROOT_PATH}"
+
+}
+
+function copy_polkit_file() {
+  cp "${FROM_PATH}/${POLKIT_FILE}" "${POLKIT_PATH}"
+  chmod 644 "${POLKIT_PATH}"
+}
+
+function copy_openvpn_file() {
+  mkdir -p "${LOCAL_SBIN_FOLDER}"
+  cp "${FROM_PATH}/${OPENVPN_FILE}" "${OPENVPN_PATH}"
+  chmod 744 "${OPENVPN_PATH}"
+
+}
+
+
+#
+# Process options and run functions.
+#
+
+check_current_uid
+
+if [ $INSTALL_BITMASK_ROOT == YES ] || [ $INSTALL_POLKIT_FILE == YES ] || [ $INSTALL_OPENVPN == YES ]
+then
+  check_from_path
+fi
+
+if [ $REMOVE_OLD_FILES == YES ]
+then
+  echo "REMOVING OLD FILES..."
+  remove_old_files
+fi
+
+if [ $INSTALL_BITMASK_ROOT == YES ]
+then
+  echo "INSTALLING bitmask-root..."
+  copy_bitmask_root
+fi
+
+if [ $INSTALL_POLKIT_FILE == YES ]
+then
+  echo "INSTALLING policykit file..."
+  copy_polkit_file
+fi
+
+if [ $INSTALL_OPENVPN == YES ]
+then
+  echo "INSTALLING openvpn..."
+  copy_openvpn_file
+fi
diff --git a/pkg/linux/polkit/se.leap.bitmask.bundle.policy b/pkg/linux/polkit/se.leap.bitmask.bundle.policy
new file mode 100644
index 0000000000000000000000000000000000000000..58fcaaa87e7b05992749a7a4d27d2937a4174132
--- /dev/null
+++ b/pkg/linux/polkit/se.leap.bitmask.bundle.policy
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+<policyconfig>
+
+  <vendor>LEAP Project</vendor>
+  <vendor_url>http://leap.se/</vendor_url>
+
+  <action id="se.leap.bitmask.bundle.policy">
+    <description>Runs bitmask helper to launch firewall and openvpn (bundle version)</description>
+    <description xml:lang="es">Ejecuta el asistente de bitmask para lanzar el firewall y openvpn (version bundle)</description>
+    <message>Bitmask needs that you authenticate to start</message>
+    <message xml:lang="es">Bitmask necesita autorizacion para comenzar</message>
+    <icon_name>package-x-generic</icon_name> 
+    <defaults>
+      <allow_any>yes</allow_any>
+      <allow_inactive>yes</allow_inactive>
+      <allow_active>yes</allow_active>
+    </defaults>
+    <annotate key="org.freedesktop.policykit.exec.path">/usr/local/sbin/bitmask-root</annotate>
+  </action>
+</policyconfig>
diff --git a/relnotes.txt b/relnotes.txt
index e95e8c15ac470ab6ffee650081942b50f6909aa4..4fc33b391af3fb80aea44213ae96d074923242bf 100644
--- a/relnotes.txt
+++ b/relnotes.txt
@@ -1,8 +1,8 @@
-ANNOUNCING Bitmask, the Internet Encryption Toolkit, release 0.5.2
+ANNOUNCING Bitmask, the Internet Encryption Toolkit, release 0.5.3
 
 The LEAP  team is  pleased to announce  the immediate  availability of
-version 0.5.2  of Bitmask,  the Internet Encryption  Toolkit, codename
-"are we there yet".
+version 0.5.3  of Bitmask,  the Internet Encryption  Toolkit, codename
+"encrypt ALL THE THINGS".
 
 https://downloads.leap.se/client/
 
@@ -34,7 +34,7 @@ signature verification.
 You can read about this and many  other cool things in the user manual
 and the developer notes, which can be found online at:
 
-http://bitmask.rtfd.org/
+https://leap.se/en/docs/client
 
 WARNING: This is still  part of a beta release of  our software, a lot
 of testing and auditing is still needed, so indeed use it, and feed us
@@ -43,7 +43,7 @@ NOT trust your life to it.
 
 WHAT CAN THIS VERSION OF BITMASK DO FOR ME?
 
-Bitmask  0.5.2 improves  greatly  its Encrypted  internet support  and
+Bitmask  0.5.3 improves  greatly  its Encrypted  Internet support  and
 stability in general, among other various  bug fixes. You can refer to
 the CHANGELOG for the meat.
 
@@ -104,6 +104,6 @@ beyond any border.
 
 The LEAP team,
 
-June 6, 2014
+June 27, 2014
 Somewhere in the middle of the intertubes.
 EOF
diff --git a/setup.py b/setup.py
index 3d12db641233d2856f0544b3041d9d2a36ba792c..bb1937cc3ba51ab4a81b42828fda431c8d1adc9c 100755
--- a/setup.py
+++ b/setup.py
@@ -20,7 +20,9 @@ Setup file for bitmask.
 """
 from __future__ import print_function
 
+import hashlib
 import sys
+import os
 import re
 
 if not sys.version_info[0] == 2:
@@ -34,7 +36,6 @@ except ImportError:
     from pkg import distribute_setup
     distribute_setup.use_setuptools()
     from setuptools import setup, find_packages
-import os
 
 from pkg import utils
 
@@ -168,6 +169,64 @@ class cmd_develop(_develop):
 
 cmdclass["develop"] = cmd_develop
 
+
+class cmd_binary_hash(Command):
+    """
+    Update the _binaries.py file with hashes for the different helpers.
+    This is used from within the bundle.
+    """
+
+    user_options = []
+
+    def initialize_options(self):
+        pass
+
+    def finalize_options(self):
+        pass
+
+    def run(self, *args):
+
+        OPENVPN_BIN = os.environ.get('OPENVPN_BIN', None)
+        BITMASK_ROOT = os.environ.get('BITMASK_ROOT', None)
+
+        def exit():
+            print("Please set environment variables "
+                  "OPENVPN_BIN and BITMASK_ROOT pointing to the right path "
+                  "to use this command")
+            sys.exit(1)
+
+        bin_paths = OPENVPN_BIN, BITMASK_ROOT
+        if not all(bin_paths):
+            exit()
+
+        if not all(map(os.path.isfile, bin_paths)):
+            exit()
+
+        openvpn_bin_hash, bitmask_root_hash = map(
+            lambda path: hashlib.sha256(open(path).read()).hexdigest(),
+            bin_paths)
+
+        template = r"""
+# Hashes for binaries used in Bitmask Bundle.
+# This file has been automatically generated by `setup.py hash_binaries`
+# DO NOT modify it manually.
+
+OPENVPN_BIN = "{openvpn}"
+BITMASK_ROOT = "{bitmask}"
+"""
+        subst_template = template.format(
+            openvpn=openvpn_bin_hash,
+            bitmask=bitmask_root_hash)
+
+        bin_hash_path = os.path.join('src', 'leap', 'bitmask', '_binaries.py')
+        with open(bin_hash_path, 'w') as f:
+            f.write(subst_template)
+        print("Binaries hash file %s has been updated!" % (bin_hash_path,))
+
+
+cmdclass["hash_binaries"] = cmd_binary_hash
+
+
 # next two classes need to augment the versioneer modified ones
 
 versioneer_build = cmdclass['build']
diff --git a/src/leap/bitmask/__init__.py b/src/leap/bitmask/__init__.py
index c844beb125dfd9ea11e1be437c06d46f3347d7da..0f733f26a0efb3611ae9bee7d6543ad728619e66 100644
--- a/src/leap/bitmask/__init__.py
+++ b/src/leap/bitmask/__init__.py
@@ -66,7 +66,7 @@ except ImportError:
 
 __appname__ = "unknown"
 try:
-    from leap._appname import __appname__
+    from leap.bitmask._appname import __appname__
 except ImportError:
     #running on a tree that has not run
     #the setup.py setver
diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py
index e965604a32fbb9dabe86e1c8ec0abce0492ab8eb..6a7d6ff1ead34572ec1b50d881e3df590bf95357 100644
--- a/src/leap/bitmask/app.py
+++ b/src/leap/bitmask/app.py
@@ -48,9 +48,15 @@ from functools import partial
 from PySide import QtCore, QtGui
 
 from leap.bitmask import __version__ as VERSION
-from leap.bitmask.util import leap_argparse
-from leap.bitmask.logs.utils import get_logger
+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
+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.requirement_checker import check_requirements
+
 from leap.common.events import server as event_server
 from leap.mail import __version__ as MAIL_VERSION
 
@@ -114,35 +120,16 @@ def main():
     """
     Starts the main event loop and launches the main window.
     """
-    # TODO move boilerplate outa here!
-    _, opts = leap_argparse.init_leapc_args()
+    # Parse arguments and store them
+    opts = leap_argparse.get_options()
     do_display_version(opts)
 
-    standalone = opts.standalone
-    offline = opts.offline
-    bypass_checks = getattr(opts, 'danger', False)
-    debug = opts.debug
-    logfile = opts.log_file
-    mail_logfile = opts.mail_log_file
+    bypass_checks = opts.danger
     start_hidden = opts.start_hidden
 
-    replace_stdout = True
-    if opts.repair or opts.import_maildir:
-        # We don't want too much clutter on the comand mode
-        # this could be more generic with a Command class.
-        replace_stdout = False
-
-    logger = get_logger(debug, logfile, replace_stdout)
-
-    #############################################################
-    # Given how paths and bundling works, we need to delay the imports
-    # of certain parts that depend on this path settings.
-    # So first we set all the places where standalone might be queried.
-    from leap.bitmask.config import flags
-    from leap.common.config.baseconfig import BaseConfig
-    flags.STANDALONE = standalone
-    flags.OFFLINE = offline
-    flags.MAIL_LOGFILE = mail_logfile
+    flags.STANDALONE = opts.standalone
+    flags.OFFLINE = opts.offline
+    flags.MAIL_LOGFILE = opts.mail_log_file
     flags.APP_VERSION_CHECK = opts.app_version_check
     flags.API_VERSION_CHECK = opts.api_version_check
     flags.OPENVPN_VERBOSITY = opts.openvpn_verb
@@ -150,7 +137,13 @@ def main():
 
     flags.CA_CERT_FILE = opts.ca_cert_file
 
-    BaseConfig.standalone = standalone
+    replace_stdout = True
+    if opts.repair or opts.import_maildir:
+        # We don't want too much clutter on the comand mode
+        # this could be more generic with a Command class.
+        replace_stdout = False
+
+    logger = create_logger(opts.debug, opts.log_file, replace_stdout)
 
     # ok, we got logging in place, we can satisfy mail plumbing requests
     # and show logs there. it normally will exit there if we got that path.
@@ -167,18 +160,6 @@ def main():
         nice = os.nice(int(PLAY_NICE))
         logger.info("Setting NICE: %s" % nice)
 
-    # And then we import all the other stuff
-    # I think it's safe to import at the top by now -- kali
-    from leap.bitmask.gui import locale_rc
-    from leap.bitmask.gui import twisted_main
-    from leap.bitmask.gui.mainwindow import MainWindow
-    from leap.bitmask.platform_init import IS_MAC
-    from leap.bitmask.platform_init.locks import we_are_the_one_and_only
-    from leap.bitmask.util.requirement_checker import check_requirements
-
-    # pylint: avoid unused import
-    assert(locale_rc)
-
     # TODO move to a different module: commands?
     if not we_are_the_one_and_only():
         # Bitmask is already running
@@ -231,10 +212,8 @@ def main():
     #timer.timeout.connect(lambda: None)
     # XXX ---------------------------------------------------------
 
-    window = MainWindow(
-        lambda: twisted_main.quit(app),
-        bypass_checks=bypass_checks,
-        start_hidden=start_hidden)
+    window = MainWindow(bypass_checks=bypass_checks,
+                        start_hidden=start_hidden)
 
     sigint_window = partial(sigint_handler, window, logger=logger)
     signal.signal(signal.SIGINT, sigint_window)
@@ -242,14 +221,6 @@ def main():
     # callable used in addSystemEventTrigger to handle SIGTERM
     sigterm_window = partial(sigterm_handler, window, logger=logger)
 
-    if IS_MAC:
-        window.raise_()
-
-    # This was a good idea, but for this to work as intended we
-    # should centralize the start of all services in there.
-    #tx_app = leap_services()
-    #assert(tx_app)
-
     l = LoopingCall(QtCore.QCoreApplication.processEvents, 0, 10)
     l.start(0.01)
 
diff --git a/src/leap/bitmask/backend/__init__.py b/src/leap/bitmask/backend/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend/components.py
similarity index 52%
rename from src/leap/bitmask/backend.py
rename to src/leap/bitmask/backend/components.py
index 3c97c797b885803ad301a7d85806bb0248a4a545..19fcf2830ce39810dfb008ece590e2f73031ccc0 100644
--- a/src/leap/bitmask/backend.py
+++ b/src/leap/bitmask/backend/components.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# backend.py
+# components.py
 # Copyright (C) 2013 LEAP
 #
 # This program is free software: you can redistribute it and/or modify
@@ -15,19 +15,17 @@
 # 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 everything
+Backend components
 """
 import logging
 import os
+import socket
 import time
 
 from functools import partial
-from Queue import Queue, Empty
 from threading import Condition
 
-from twisted.internet import reactor
 from twisted.internet import threads, defer
-from twisted.internet.task import LoopingCall
 from twisted.python import log
 
 import zope.interface
@@ -38,6 +36,7 @@ from leap.bitmask.crypto.srpauth import SRPAuth
 from leap.bitmask.crypto.srpregister import SRPRegister
 from leap.bitmask.platform_init import IS_LINUX
 from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper
+from leap.bitmask.provider.pinned import PinnedProviders
 from leap.bitmask.services import get_supported
 from leap.bitmask.services.eip import eipconfig
 from leap.bitmask.services.eip import get_openvpn_management
@@ -53,6 +52,7 @@ from leap.bitmask.services.mail.smtpconfig import SMTPConfig
 
 from leap.bitmask.services.soledad.soledadbootstrapper import \
     SoledadBootstrapper
+from leap.bitmask.util import force_eval
 
 from leap.common import certs as leap_certs
 
@@ -61,9 +61,6 @@ from leap.keymanager.errors import KeyAddressMismatch, KeyFingerprintMismatch
 
 from leap.soledad.client import NoStorageSecret, PassphraseTooShort
 
-# Frontend side
-from PySide import QtCore
-
 logger = logging.getLogger(__name__)
 
 
@@ -260,8 +257,7 @@ class Provider(object):
 
     def get_details(self, domain, lang=None):
         """
-        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
@@ -269,12 +265,23 @@ class Provider(object):
         :type lang: str
 
         Signals:
-            prov_get_details -> ProviderConfigLight
+            prov_get_details -> dict
         """
         self._signaler.signal(
             self._signaler.PROV_GET_DETAILS,
             self._provider_config.get_light_config(domain, lang))
 
+    def get_pinned_providers(self):
+        """
+        Signal the list of pinned provider domains.
+
+        Signals:
+            prov_get_pinned_providers -> list of provider domains
+        """
+        self._signaler.signal(
+            self._signaler.PROV_GET_PINNED_PROVIDERS,
+            PinnedProviders.domains())
+
 
 class Register(object):
     """
@@ -598,7 +605,8 @@ class EIP(object):
         eip_loaded = eip_config.load(eipconfig.get_eipconfig_path(domain))
 
         launcher = get_vpn_launcher()
-        if not os.path.isfile(launcher.OPENVPN_BIN_PATH):
+        ovpn_path = force_eval(launcher.OPENVPN_BIN_PATH)
+        if not os.path.isfile(ovpn_path):
             logger.error("Cannot start OpenVPN, binary not found")
             return False
 
@@ -640,6 +648,45 @@ class EIP(object):
             if self._signaler is not None:
                 self._signaler.signal(self._signaler.EIP_CANNOT_START)
 
+    def check_dns(self, domain):
+        """
+        Check if we can resolve the given domain name.
+
+        :param domain: the domain to check.
+        :type domain: str
+        """
+        def do_check():
+            """
+            Try to resolve the domain name.
+            """
+            socket.gethostbyname(domain.encode('idna'))
+
+        def check_ok(_):
+            """
+            Callback handler for `do_check`.
+            """
+            self._signaler.signal(self._signaler.EIP_DNS_OK)
+            logger.debug("DNS check OK")
+
+        def check_err(failure):
+            """
+            Errback handler for `do_check`.
+
+            :param failure: the failure that triggered the errback.
+            :type failure: twisted.python.failure.Failure
+            """
+            logger.debug("Can't resolve hostname. {0!r}".format(failure))
+
+            self._signaler.signal(self._signaler.EIP_DNS_ERROR)
+
+            # python 2.7.4 raises socket.error
+            # python 2.7.5 raises socket.gaierror
+            failure.trap(socket.gaierror, socket.error)
+
+        d = threads.deferToThread(do_check)
+        d.addCallback(check_ok)
+        d.addErrback(check_err)
+
 
 class Soledad(object):
     """
@@ -1098,932 +1145,3 @@ class Authenticate(object):
             signal = self._signaler.SRP_STATUS_NOT_LOGGED_IN
 
         self._signaler.signal(signal)
-
-
-class Signaler(QtCore.QObject):
-    """
-    Signaler object, handles converting string commands to Qt signals.
-
-    This is intended for the separation in frontend/backend, this will
-    live in the frontend.
-    """
-
-    ####################
-    # 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_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_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_connection_died = QtCore.Signal(object)
-    eip_connection_aborted = QtCore.Signal(object)
-    eip_stopped = 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_get_gateways_list = QtCore.Signal(object)
-    eip_get_gateways_list_error = QtCore.Signal(object)
-    eip_uninitialized_provider = QtCore.Signal(object)
-    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_state_changed = QtCore.Signal(dict)
-    eip_status_changed = QtCore.Signal(dict)
-    eip_process_finished = QtCore.Signal(int)
-    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)
-
-    keymanager_key_details = 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"
-
-    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"
-
-    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.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.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:
-            log.err("Unknown key for signal %s!" % (key,))
-
-
-class Backend(object):
-    """
-    Backend for everything, the UI should only use this class.
-    """
-
-    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()
-
-        # 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(Provider(self._signaler, bypass_checks))
-        self._register(Register(self._signaler))
-        self._register(Authenticate(self._signaler))
-        self._register(EIP(self._signaler))
-        self._register(Soledad(self._soledad_proxy,
-                               self._keymanager_proxy,
-                               self._signaler))
-        self._register(Keymanager(self._keymanager_proxy,
-                                  self._signaler))
-        self._register(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.
-
-        :param signal: signal name
-        :type signal: str
-        """
-        self._signaler.signal(signal)
-
-    def _worker(self):
-        """
-        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.
-
-    def provider_setup(self, provider):
-        """
-        Initiate the setup for a provider.
-
-        :param provider: URL for the provider
-        :type provider: unicode
-
-        Signals:
-            prov_unsupported_client
-            prov_unsupported_api
-            prov_name_resolution        -> { PASSED_KEY: bool, ERROR_KEY: str }
-            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))
-
-    def provider_cancel_setup(self):
-        """
-        Cancel the ongoing setup provider (if any).
-        """
-        self._call_queue.put(("provider", "cancel_setup_provider", None))
-
-    def provider_bootstrap(self, provider):
-        """
-        Second stage of bootstrapping for a provider.
-
-        :param provider: URL for the provider
-        :type provider: unicode
-
-        Signals:
-            prov_problem_with_provider
-            prov_download_ca_cert      -> {PASSED_KEY: bool, ERROR_KEY: str}
-            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))
-
-    def provider_get_supported_services(self, domain):
-        """
-        Signal a list of supported services provided by the given provider.
-
-        :param domain: the provider to get the services from.
-        :type domain: str
-
-        Signals:
-            prov_get_supported_services -> list of unicode
-        """
-        self._call_queue.put(("provider", "get_supported_services", None,
-                              domain))
-
-    def provider_get_all_services(self, providers):
-        """
-        Signal a list of services provided by all the configured providers.
-
-        :param providers: the list of providers to get the services.
-        :type providers: list
-
-        Signals:
-            prov_get_all_services -> list of unicode
-        """
-        self._call_queue.put(("provider", "get_all_services", None,
-                              providers))
-
-    def provider_get_details(self, domain, lang):
-        """
-        Signal a ProviderConfigLight object with the current ProviderConfig
-        settings.
-
-        :param domain: the domain name of the provider.
-        :type domain: str
-        :param lang: the language to use for localized strings.
-        :type lang: str
-
-        Signals:
-            prov_get_details -> ProviderConfigLight
-        """
-        self._call_queue.put(("provider", "get_details", None, domain, lang))
-
-    def user_register(self, provider, username, password):
-        """
-        Register a user using the domain and password given as parameters.
-
-        :param domain: the domain we need to register the user.
-        :type domain: unicode
-        :param username: the user name
-        :type username: unicode
-        :param password: the password for the username
-        :type password: unicode
-
-        Signals:
-            srp_registration_finished
-            srp_registration_taken
-            srp_registration_failed
-        """
-        self._call_queue.put(("register", "register_user", None, provider,
-                              username, password))
-
-    def eip_setup(self, provider, skip_network=False):
-        """
-        Initiate the setup for a provider
-
-        :param provider: URL for the provider
-        :type provider: unicode
-        :param skip_network: Whether checks that involve network should be done
-                             or not
-        :type skip_network: bool
-
-        Signals:
-            eip_config_ready             -> {PASSED_KEY: bool, ERROR_KEY: str}
-            eip_client_certificate_ready -> {PASSED_KEY: bool, ERROR_KEY: str}
-            eip_cancelled_setup
-        """
-        self._call_queue.put(("eip", "setup_eip", None, provider,
-                              skip_network))
-
-    def eip_cancel_setup(self):
-        """
-        Cancel the ongoing setup EIP (if any).
-        """
-        self._call_queue.put(("eip", "cancel_setup_eip", None))
-
-    def eip_start(self, restart=False):
-        """
-        Start the EIP service.
-
-        Signals:
-            backend_bad_call
-            eip_alien_openvpn_already_running
-            eip_connected
-            eip_connection_aborted
-            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 -> str
-            eip_status_changed -> tuple of str (download, upload)
-            eip_vpn_launcher_exception
-
-        :param restart: whether is is a restart.
-        :type restart: bool
-        """
-        self._call_queue.put(("eip", "start", None, restart))
-
-    def eip_stop(self, shutdown=False, restart=False, failed=False):
-        """
-        Stop the EIP service.
-
-        :param shutdown: whether this is the final shutdown.
-        :type shutdown: bool
-
-        :param restart: whether this is part of a restart.
-        :type restart: bool
-        """
-        self._call_queue.put(("eip", "stop", None, shutdown, restart))
-
-    def eip_terminate(self):
-        """
-        Terminate the EIP service, not necessarily in a nice way.
-        """
-        self._call_queue.put(("eip", "terminate", None))
-
-    def eip_get_gateways_list(self, domain):
-        """
-        Signal a list of gateways for the given provider.
-
-        :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))
-
-    def eip_get_initialized_providers(self, domains):
-        """
-        Signal a list of the given domains and if they are initialized or not.
-
-        :param domains: the list of domains to check.
-        :type domain: list of str
-
-        Signals:
-            eip_get_initialized_providers -> list of tuple(unicode, bool)
-
-        """
-        self._call_queue.put(("eip", "get_initialized_providers",
-                              None, domains))
-
-    def eip_can_start(self, domain):
-        """
-        Signal whether it has everything that is needed to run EIP or not
-
-        :param domain: the domain for the provider to check
-        :type domain: str
-
-        Signals:
-            eip_can_start
-            eip_cannot_start
-        """
-        self._call_queue.put(("eip", "can_start",
-                              None, domain))
-
-    def tear_fw_down(self):
-        """
-        Signal the need to tear the fw down.
-        """
-        self._call_queue.put(("eip", "tear_fw_down", None))
-
-    def user_login(self, provider, username, password):
-        """
-        Execute the whole authentication process for a user
-
-        :param domain: the domain where we need to authenticate.
-        :type domain: unicode
-        :param username: username for this session
-        :type username: str
-        :param password: password for this user
-        :type password: str
-
-        Signals:
-            srp_auth_error
-            srp_auth_ok
-            srp_auth_bad_user_or_password
-            srp_auth_server_error
-            srp_auth_connection_error
-            srp_auth_error
-        """
-        self._call_queue.put(("authenticate", "login", None, provider,
-                              username, password))
-
-    def user_logout(self):
-        """
-        Log out the current session.
-
-        Signals:
-            srp_logout_ok
-            srp_logout_error
-            srp_not_logged_in_error
-        """
-        self._call_queue.put(("authenticate", "logout", None))
-
-    def user_cancel_login(self):
-        """
-        Cancel the ongoing login (if any).
-        """
-        self._call_queue.put(("authenticate", "cancel_login", None))
-
-    def user_change_password(self, current_password, new_password):
-        """
-        Change the user's password.
-
-        :param current_password: the current password of the user.
-        :type current_password: str
-        :param new_password: the new password for the user.
-        :type new_password: str
-
-        Signals:
-            srp_not_logged_in_error
-            srp_password_change_ok
-            srp_password_change_badpw
-            srp_password_change_error
-        """
-        self._call_queue.put(("authenticate", "change_password", None,
-                              current_password, new_password))
-
-    def soledad_change_password(self, new_password):
-        """
-        Change the database's password.
-
-        :param new_password: the new password for the user.
-        :type new_password: unicode
-
-        Signals:
-            srp_not_logged_in_error
-            srp_password_change_ok
-            srp_password_change_badpw
-            srp_password_change_error
-        """
-        self._call_queue.put(("soledad", "change_password", None,
-                              new_password))
-
-    def user_get_logged_in_status(self):
-        """
-        Signal if the user is currently logged in or not.
-
-        Signals:
-            srp_status_logged_in
-            srp_status_not_logged_in
-        """
-        self._call_queue.put(("authenticate", "get_logged_in_status", None))
-
-    def soledad_bootstrap(self, username, domain, password):
-        """
-        Bootstrap the soledad database.
-
-        :param username: the user name
-        :type username: unicode
-        :param domain: the domain that we are using.
-        :type domain: unicode
-        :param password: the password for the username
-        :type password: unicode
-
-        Signals:
-            soledad_bootstrap_finished
-            soledad_bootstrap_failed
-            soledad_invalid_auth_token
-        """
-        self._call_queue.put(("soledad", "bootstrap", None,
-                              username, domain, password))
-
-    def soledad_load_offline(self, username, password, uuid):
-        """
-        Load the soledad database in offline mode.
-
-        :param username: full user id (user@provider)
-        :type username: str or unicode
-        :param password: the soledad passphrase
-        :type password: unicode
-        :param uuid: the user uuid
-        :type uuid: str or unicode
-
-        Signals:
-        """
-        self._call_queue.put(("soledad", "load_offline", None,
-                              username, password, uuid))
-
-    def soledad_cancel_bootstrap(self):
-        """
-        Cancel the ongoing soledad bootstrapping process (if any).
-        """
-        self._call_queue.put(("soledad", "cancel_bootstrap", None))
-
-    def soledad_close(self):
-        """
-        Close soledad database.
-        """
-        self._call_queue.put(("soledad", "close", None))
-
-    def keymanager_list_keys(self):
-        """
-        Signal a list of public keys locally stored.
-
-        Signals:
-            keymanager_keys_list -> list
-        """
-        self._call_queue.put(("keymanager", "list_keys", None))
-
-    def keymanager_export_keys(self, username, filename):
-        """
-        Export the given username's keys to a file.
-
-        :param username: the username whos keys we need to export.
-        :type username: str
-        :param filename: the name of the file where we want to save the keys.
-        :type filename: str
-
-        Signals:
-            keymanager_export_ok
-            keymanager_export_error
-        """
-        self._call_queue.put(("keymanager", "export_keys", None,
-                              username, filename))
-
-    def keymanager_get_key_details(self, username):
-        """
-        Signal the given username's key details.
-
-        :param username: the username whos keys we need to get details.
-        :type username: str
-
-        Signals:
-            keymanager_key_details
-        """
-        self._call_queue.put(("keymanager", "get_key_details", None, username))
-
-    def smtp_start_service(self, full_user_id, download_if_needed=False):
-        """
-        Start the SMTP service.
-
-        :param full_user_id: user id, in the form "user@provider"
-        :type full_user_id: str
-        :param download_if_needed: True if it should check for mtime
-                                   for the file
-        :type download_if_needed: bool
-        """
-        self._call_queue.put(("mail", "start_smtp_service", None,
-                              full_user_id, download_if_needed))
-
-    def imap_start_service(self, full_user_id, offline=False):
-        """
-        Start the IMAP service.
-
-        :param full_user_id: user id, in the form "user@provider"
-        :type full_user_id: str
-        :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))
-
-    def smtp_stop_service(self):
-        """
-        Stop the SMTP service.
-        """
-        self._call_queue.put(("mail", "stop_smtp_service", None))
-
-    def imap_stop_service(self):
-        """
-        Stop imap service.
-
-        Signals:
-            imap_stopped
-        """
-        self._call_queue.put(("mail", "stop_imap_service", None))
diff --git a/src/leap/bitmask/backend/leapbackend.py b/src/leap/bitmask/backend/leapbackend.py
new file mode 100644
index 0000000000000000000000000000000000000000..3c5222f48bc4a34d2e7e0cf2d5096a36da2986eb
--- /dev/null
+++ b/src/leap/bitmask/backend/leapbackend.py
@@ -0,0 +1,636 @@
+# -*- coding: utf-8 -*-
+# leapbackend.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/>.
+"""
+Backend for GUI/Logic communication.
+"""
+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 zope.interface
+import zope.proxy
+
+from leap.bitmask.backend.leapsignaler import Signaler
+from leap.bitmask.backend import components
+
+logger = logging.getLogger(__name__)
+
+
+class Backend(object):
+    """
+    Backend for everything, the UI should only use this class.
+    """
+
+    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()
+
+        # 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.
+
+        :param signal: signal name
+        :type signal: str
+        """
+        self._signaler.signal(signal)
+
+    def _worker(self):
+        """
+        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.
+
+    def provider_setup(self, provider):
+        """
+        Initiate the setup for a provider.
+
+        :param provider: URL for the provider
+        :type provider: unicode
+
+        Signals:
+            prov_unsupported_client
+            prov_unsupported_api
+            prov_name_resolution        -> { PASSED_KEY: bool, ERROR_KEY: str }
+            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))
+
+    def provider_cancel_setup(self):
+        """
+        Cancel the ongoing setup provider (if any).
+        """
+        self._call_queue.put(("provider", "cancel_setup_provider", None))
+
+    def provider_bootstrap(self, provider):
+        """
+        Second stage of bootstrapping for a provider.
+
+        :param provider: URL for the provider
+        :type provider: unicode
+
+        Signals:
+            prov_problem_with_provider
+            prov_download_ca_cert      -> {PASSED_KEY: bool, ERROR_KEY: str}
+            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))
+
+    def provider_get_supported_services(self, domain):
+        """
+        Signal a list of supported services provided by the given provider.
+
+        :param domain: the provider to get the services from.
+        :type domain: str
+
+        Signals:
+            prov_get_supported_services -> list of unicode
+        """
+        self._call_queue.put(("provider", "get_supported_services", None,
+                              domain))
+
+    def provider_get_all_services(self, providers):
+        """
+        Signal a list of services provided by all the configured providers.
+
+        :param providers: the list of providers to get the services.
+        :type providers: list
+
+        Signals:
+            prov_get_all_services -> list of unicode
+        """
+        self._call_queue.put(("provider", "get_all_services", None,
+                              providers))
+
+    def provider_get_details(self, domain, lang):
+        """
+        Signal a ProviderConfigLight object with the current ProviderConfig
+        settings.
+
+        :param domain: the domain name of the provider.
+        :type domain: str
+        :param lang: the language to use for localized strings.
+        :type lang: str
+
+        Signals:
+            prov_get_details -> ProviderConfigLight
+        """
+        self._call_queue.put(("provider", "get_details", None, domain, lang))
+
+    def provider_get_pinned_providers(self):
+        """
+        Signal the pinned providers.
+
+        Signals:
+            prov_get_pinned_providers -> list of provider domains
+        """
+        self._call_queue.put(("provider", "get_pinned_providers", None))
+
+    def user_register(self, provider, username, password):
+        """
+        Register a user using the domain and password given as parameters.
+
+        :param domain: the domain we need to register the user.
+        :type domain: unicode
+        :param username: the user name
+        :type username: unicode
+        :param password: the password for the username
+        :type password: unicode
+
+        Signals:
+            srp_registration_finished
+            srp_registration_taken
+            srp_registration_failed
+        """
+        self._call_queue.put(("register", "register_user", None, provider,
+                              username, password))
+
+    def eip_setup(self, provider, skip_network=False):
+        """
+        Initiate the setup for a provider
+
+        :param provider: URL for the provider
+        :type provider: unicode
+        :param skip_network: Whether checks that involve network should be done
+                             or not
+        :type skip_network: bool
+
+        Signals:
+            eip_config_ready             -> {PASSED_KEY: bool, ERROR_KEY: str}
+            eip_client_certificate_ready -> {PASSED_KEY: bool, ERROR_KEY: str}
+            eip_cancelled_setup
+        """
+        self._call_queue.put(("eip", "setup_eip", None, provider,
+                              skip_network))
+
+    def eip_cancel_setup(self):
+        """
+        Cancel the ongoing setup EIP (if any).
+        """
+        self._call_queue.put(("eip", "cancel_setup_eip", None))
+
+    def eip_start(self, restart=False):
+        """
+        Start the EIP service.
+
+        Signals:
+            backend_bad_call
+            eip_alien_openvpn_already_running
+            eip_connected
+            eip_connection_aborted
+            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 -> str
+            eip_status_changed -> tuple of str (download, upload)
+            eip_vpn_launcher_exception
+
+        :param restart: whether is is a restart.
+        :type restart: bool
+        """
+        self._call_queue.put(("eip", "start", None, restart))
+
+    def eip_stop(self, shutdown=False, restart=False, failed=False):
+        """
+        Stop the EIP service.
+
+        :param shutdown: whether this is the final shutdown.
+        :type shutdown: bool
+
+        :param restart: whether this is part of a restart.
+        :type restart: bool
+        """
+        self._call_queue.put(("eip", "stop", None, shutdown, restart))
+
+    def eip_terminate(self):
+        """
+        Terminate the EIP service, not necessarily in a nice way.
+        """
+        self._call_queue.put(("eip", "terminate", None))
+
+    def eip_get_gateways_list(self, domain):
+        """
+        Signal a list of gateways for the given provider.
+
+        :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))
+
+    def eip_get_initialized_providers(self, domains):
+        """
+        Signal a list of the given domains and if they are initialized or not.
+
+        :param domains: the list of domains to check.
+        :type domain: list of str
+
+        Signals:
+            eip_get_initialized_providers -> list of tuple(unicode, bool)
+
+        """
+        self._call_queue.put(("eip", "get_initialized_providers",
+                              None, domains))
+
+    def eip_can_start(self, domain):
+        """
+        Signal whether it has everything that is needed to run EIP or not
+
+        :param domain: the domain for the provider to check
+        :type domain: str
+
+        Signals:
+            eip_can_start
+            eip_cannot_start
+        """
+        self._call_queue.put(("eip", "can_start",
+                              None, domain))
+
+    def eip_check_dns(self, domain):
+        """
+        Check if we can resolve the given domain name.
+
+        :param domain: the domain for the provider to check
+        :type domain: str
+
+        Signals:
+            eip_dns_ok
+            eip_dns_error
+        """
+        self._call_queue.put(("eip", "check_dns", None, domain))
+
+    def tear_fw_down(self):
+        """
+        Signal the need to tear the fw down.
+        """
+        self._call_queue.put(("eip", "tear_fw_down", None))
+
+    def user_login(self, provider, username, password):
+        """
+        Execute the whole authentication process for a user
+
+        :param domain: the domain where we need to authenticate.
+        :type domain: unicode
+        :param username: username for this session
+        :type username: str
+        :param password: password for this user
+        :type password: str
+
+        Signals:
+            srp_auth_error
+            srp_auth_ok
+            srp_auth_bad_user_or_password
+            srp_auth_server_error
+            srp_auth_connection_error
+            srp_auth_error
+        """
+        self._call_queue.put(("authenticate", "login", None, provider,
+                              username, password))
+
+    def user_logout(self):
+        """
+        Log out the current session.
+
+        Signals:
+            srp_logout_ok
+            srp_logout_error
+            srp_not_logged_in_error
+        """
+        self._call_queue.put(("authenticate", "logout", None))
+
+    def user_cancel_login(self):
+        """
+        Cancel the ongoing login (if any).
+        """
+        self._call_queue.put(("authenticate", "cancel_login", None))
+
+    def user_change_password(self, current_password, new_password):
+        """
+        Change the user's password.
+
+        :param current_password: the current password of the user.
+        :type current_password: str
+        :param new_password: the new password for the user.
+        :type new_password: str
+
+        Signals:
+            srp_not_logged_in_error
+            srp_password_change_ok
+            srp_password_change_badpw
+            srp_password_change_error
+        """
+        self._call_queue.put(("authenticate", "change_password", None,
+                              current_password, new_password))
+
+    def soledad_change_password(self, new_password):
+        """
+        Change the database's password.
+
+        :param new_password: the new password for the user.
+        :type new_password: unicode
+
+        Signals:
+            srp_not_logged_in_error
+            srp_password_change_ok
+            srp_password_change_badpw
+            srp_password_change_error
+        """
+        self._call_queue.put(("soledad", "change_password", None,
+                              new_password))
+
+    def user_get_logged_in_status(self):
+        """
+        Signal if the user is currently logged in or not.
+
+        Signals:
+            srp_status_logged_in
+            srp_status_not_logged_in
+        """
+        self._call_queue.put(("authenticate", "get_logged_in_status", None))
+
+    def soledad_bootstrap(self, username, domain, password):
+        """
+        Bootstrap the soledad database.
+
+        :param username: the user name
+        :type username: unicode
+        :param domain: the domain that we are using.
+        :type domain: unicode
+        :param password: the password for the username
+        :type password: unicode
+
+        Signals:
+            soledad_bootstrap_finished
+            soledad_bootstrap_failed
+            soledad_invalid_auth_token
+        """
+        self._call_queue.put(("soledad", "bootstrap", None,
+                              username, domain, password))
+
+    def soledad_load_offline(self, username, password, uuid):
+        """
+        Load the soledad database in offline mode.
+
+        :param username: full user id (user@provider)
+        :type username: str or unicode
+        :param password: the soledad passphrase
+        :type password: unicode
+        :param uuid: the user uuid
+        :type uuid: str or unicode
+
+        Signals:
+        """
+        self._call_queue.put(("soledad", "load_offline", None,
+                              username, password, uuid))
+
+    def soledad_cancel_bootstrap(self):
+        """
+        Cancel the ongoing soledad bootstrapping process (if any).
+        """
+        self._call_queue.put(("soledad", "cancel_bootstrap", None))
+
+    def soledad_close(self):
+        """
+        Close soledad database.
+        """
+        self._call_queue.put(("soledad", "close", None))
+
+    def keymanager_list_keys(self):
+        """
+        Signal a list of public keys locally stored.
+
+        Signals:
+            keymanager_keys_list -> list
+        """
+        self._call_queue.put(("keymanager", "list_keys", None))
+
+    def keymanager_export_keys(self, username, filename):
+        """
+        Export the given username's keys to a file.
+
+        :param username: the username whos keys we need to export.
+        :type username: str
+        :param filename: the name of the file where we want to save the keys.
+        :type filename: str
+
+        Signals:
+            keymanager_export_ok
+            keymanager_export_error
+        """
+        self._call_queue.put(("keymanager", "export_keys", None,
+                              username, filename))
+
+    def keymanager_get_key_details(self, username):
+        """
+        Signal the given username's key details.
+
+        :param username: the username whos keys we need to get details.
+        :type username: str
+
+        Signals:
+            keymanager_key_details
+        """
+        self._call_queue.put(("keymanager", "get_key_details", None, username))
+
+    def smtp_start_service(self, full_user_id, download_if_needed=False):
+        """
+        Start the SMTP service.
+
+        :param full_user_id: user id, in the form "user@provider"
+        :type full_user_id: str
+        :param download_if_needed: True if it should check for mtime
+                                   for the file
+        :type download_if_needed: bool
+        """
+        self._call_queue.put(("mail", "start_smtp_service", None,
+                              full_user_id, download_if_needed))
+
+    def imap_start_service(self, full_user_id, offline=False):
+        """
+        Start the IMAP service.
+
+        :param full_user_id: user id, in the form "user@provider"
+        :type full_user_id: str
+        :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))
+
+    def smtp_stop_service(self):
+        """
+        Stop the SMTP service.
+        """
+        self._call_queue.put(("mail", "stop_smtp_service", None))
+
+    def imap_stop_service(self):
+        """
+        Stop imap service.
+
+        Signals:
+            imap_stopped
+        """
+        self._call_queue.put(("mail", "stop_imap_service", None))
diff --git a/src/leap/bitmask/backend/leapsignaler.py b/src/leap/bitmask/backend/leapsignaler.py
new file mode 100644
index 0000000000000000000000000000000000000000..da8908fdbbf3dce3d5dd5ccb9e9b77f4504b341c
--- /dev/null
+++ b/src/leap/bitmask/backend/leapsignaler.py
@@ -0,0 +1,385 @@
+# -*- coding: utf-8 -*-
+# components.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/>.
+"""
+Signaler for Backend/Frontend communication.
+"""
+import logging
+
+from PySide import QtCore
+
+logger = logging.getLogger(__name__)
+
+
+class Signaler(QtCore.QObject):
+    """
+    Signaler object, handles converting string commands to Qt signals.
+
+    This is intended for the separation in frontend/backend, this will
+    live in the frontend.
+    """
+
+    ####################
+    # 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_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_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_get_gateways_list = QtCore.Signal(object)
+    eip_get_gateways_list_error = QtCore.Signal(object)
+    eip_uninitialized_provider = QtCore.Signal(object)
+    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_state_changed = QtCore.Signal(dict)
+    eip_status_changed = QtCore.Signal(dict)
+    eip_process_finished = QtCore.Signal(int)
+    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)
+
+    keymanager_key_details = 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,))
diff --git a/src/leap/bitmask/config/providerconfig.py b/src/leap/bitmask/config/providerconfig.py
index cf31b3b26970d46f735b483a6729ec40ed5cdb2e..7b979e61fe6efb426703774539042221c1164912 100644
--- a/src/leap/bitmask/config/providerconfig.py
+++ b/src/leap/bitmask/config/providerconfig.py
@@ -38,35 +38,6 @@ class MissingCACert(Exception):
     pass
 
 
-class ProviderConfigLight(object):
-    """
-    A light config object to hold some provider settings needed by the GUI.
-    """
-    def __init__(self):
-        """
-        Define the public attributes.
-        """
-        self.domain = ""
-        self.name = ""
-        self.description = ""
-        self.enrollment_policy = ""
-        self.services = []
-
-    @property
-    def services_string(self):
-        """
-        Return a comma separated list of serices provided by this provider.
-
-        :rtype: str
-        """
-        services = []
-        for service in self.services:
-            services.append(get_service_display_name(service))
-
-        services_str = ", ".join(services)
-        return services_str
-
-
 class ProviderConfig(BaseConfig):
     """
     Provider configuration abstraction class
@@ -76,24 +47,32 @@ class ProviderConfig(BaseConfig):
 
     def get_light_config(self, domain, lang=None):
         """
-        Return a ProviderConfigLight object with the data for the loaded
-        object.
+        Return a dict with the data for the loaded object.
 
         :param domain: the domain name of the provider.
         :type domain: str
         :param lang: the language to use for localized strings.
         :type lang: str
 
-        :rtype: ProviderConfigLight or None if the ProviderConfig isn't loaded.
+        :rtype: dict or None if the ProviderConfig isn't loaded.
         """
         config = self.get_provider_config(domain)
-        details = ProviderConfigLight()
 
-        details.domain = config.get_domain()
-        details.name = config.get_name(lang=lang)
-        details.description = config.get_description(lang=lang)
-        details.enrollment_policy = config.get_enrollment_policy()
-        details.services = config.get_services()
+        if config is None:
+            return
+
+        details = {}
+        details["domain"] = config.get_domain()
+        details["name"] = config.get_name(lang=lang)
+        details["description"] = config.get_description(lang=lang)
+        details["enrollment_policy"] = config.get_enrollment_policy()
+        details["services"] = config.get_services()
+
+        services = []
+        for service in config.get_services():
+            services.append(get_service_display_name(service))
+
+        details['services_string'] = ", ".join(services)
 
         return details
 
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py
index 8b9f2d443cacc22ce32f63a08d33cee3716b39d1..bd569343bb3b05ec39be417c9483db332cb9c79e 100644
--- a/src/leap/bitmask/gui/eip_status.py
+++ b/src/leap/bitmask/gui/eip_status.py
@@ -88,6 +88,8 @@ class EIPStatusWidget(QtGui.QWidget):
         self.is_restart = False
         self.is_cold_start = True
 
+        self.missing_helpers = False
+
         # Action for the systray
         self._eip_disabled_action = QtGui.QAction(
             "{0} is {1}".format(self._service_name, self.tr("disabled")), self)
@@ -298,7 +300,12 @@ class EIPStatusWidget(QtGui.QWidget):
         # probably the best thing would be to make a conditional
         # transition there, but that's more involved.
         self.eip_button.hide()
-        msg = self.tr("You must login to use {0}".format(self._service_name))
+        if self.missing_helpers:
+            msg = self.tr(
+                "<font color=red>Disabled: missing helper files</font>")
+        else:
+            msg = self.tr(
+                "You must login to use {0}".format(self._service_name))
         self.eip_label.setText(msg)
         self._eip_status_menu.setTitle("{0} is {1}".format(
             self._service_name, self.tr("disabled")))
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 3ef994b14ce7e6f653178f62d5c0ebec1ccb2c1f..53a7d95a10314ac40260002b46eb7ab565c67665 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -18,12 +18,10 @@
 Main window for Bitmask.
 """
 import logging
-import socket
 
 from datetime import datetime
 
 from PySide import QtCore, QtGui
-from twisted.internet import reactor, threads
 
 from leap.bitmask import __version__ as VERSION
 from leap.bitmask import __version_hash__ as VERSION_HASH
@@ -39,11 +37,13 @@ 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
+from leap.bitmask.platform_init.initializers import init_signals
 
-from leap.bitmask import backend
+from leap.bitmask.backend import leapbackend
 
 from leap.bitmask.services.eip import conductor as eip_conductor
 from leap.bitmask.services.mail import conductor as mail_conductor
@@ -89,16 +89,12 @@ class MainWindow(QtGui.QMainWindow):
     EIP_START_TIMEOUT = 60000  # in milliseconds
 
     # We give the services some time to a halt before forcing quit.
-    SERVICES_STOP_TIMEOUT = 20
+    SERVICES_STOP_TIMEOUT = 20000  # in milliseconds
 
-    def __init__(self, quit_callback, bypass_checks=False, start_hidden=False):
+    def __init__(self, bypass_checks=False, start_hidden=False):
         """
         Constructor for the client main window
 
-        :param quit_callback: Function to be called when closing
-                              the application.
-        :type quit_callback: callable
-
         :param bypass_checks: Set to true if the app should bypass first round
                               of checks for CA certificates at bootstrap
         :type bypass_checks: bool
@@ -117,14 +113,13 @@ class MainWindow(QtGui.QMainWindow):
                  reqcbk=lambda req, resp: None)  # make rpc call async
         # end register leap events ####################################
 
-        self._quit_callback = quit_callback
         self._updates_content = ""
 
         # setup UI
         self.ui = Ui_MainWindow()
         self.ui.setupUi(self)
         self.menuBar().setNativeMenuBar(not IS_LINUX)
-        self._backend = backend.Backend(bypass_checks)
+        self._backend = leapbackend.Backend(bypass_checks)
         self._backend.start()
 
         self._settings = LeapSettings()
@@ -152,6 +147,9 @@ class MainWindow(QtGui.QMainWindow):
             self._settings, self._backend)
         self._eip_status = EIPStatusWidget(self, self._eip_conductor)
 
+        init_signals.eip_missing_helpers.connect(
+            self._disable_eip_missing_helpers)
+
         self.ui.eipLayout.addWidget(self._eip_status)
         self._eip_conductor.add_eip_widget(self._eip_status)
 
@@ -181,8 +179,8 @@ class MainWindow(QtGui.QMainWindow):
         # Set used to track the services being stopped and need wait.
         self._services_being_stopped = {}
 
-        # timeout object used to trigger quit
-        self._quit_timeout_callater = None
+        # used to know if we are in the final steps of quitting
+        self._finally_quitting = False
 
         self._backend_connected_signals = []
         self._backend_connect()
@@ -407,6 +405,8 @@ class MainWindow(QtGui.QMainWindow):
         sig.eip_can_start.connect(self._backend_can_start_eip)
         sig.eip_cannot_start.connect(self._backend_cannot_start_eip)
 
+        sig.eip_dns_error.connect(self._eip_dns_error)
+
         # ==================================================================
 
         # Soledad signals
@@ -553,7 +553,7 @@ class MainWindow(QtGui.QMainWindow):
         details = self._provider_details
         mx_provided = False
         if details is not None:
-            mx_provided = MX_SERVICE in details.services
+            mx_provided = MX_SERVICE in details['services']
 
         # XXX: handle differently not logged in user?
         akm = AdvancedKeyManagement(self, mx_provided, logged_user,
@@ -573,7 +573,7 @@ class MainWindow(QtGui.QMainWindow):
         domain = self._login_widget.get_selected_provider()
         mx_provided = False
         if self._provider_details is not None:
-            mx_provided = MX_SERVICE in self._provider_details.services
+            mx_provided = MX_SERVICE in self._provider_details['services']
         preferences = PreferencesWindow(self, user, domain, self._backend,
                                         self._soledad_started, mx_provided)
 
@@ -666,6 +666,16 @@ class MainWindow(QtGui.QMainWindow):
             self._eip_status.disable_eip_start()
             self._eip_status.set_eip_status(self.tr("Disabled"))
 
+    @QtCore.Slot()
+    def _disable_eip_missing_helpers(self):
+        """
+        TRIGGERS:
+            init_signals.missing_helpers
+
+        Set the missing_helpers flag, so we can disable EIP.
+        """
+        self._eip_status.missing_helpers = True
+
     @QtCore.Slot()
     def _show_eip_preferences(self):
         """
@@ -901,7 +911,7 @@ class MainWindow(QtGui.QMainWindow):
                 self.tr('Hello!'),
                 self.tr('Bitmask has started in the tray.'))
             # we wait for the systray to be ready
-            reactor.callLater(1, hello)
+            QtDelayedCall(1000, hello)
 
     @QtCore.Slot(int)
     def _tray_activated(self, reason=None):
@@ -1271,7 +1281,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 not MX_SERVICE in self._provider_details['services']:
             self._set_mx_visible(False)
 
     def _start_eip_bootstrap(self):
@@ -1314,7 +1324,7 @@ class MainWindow(QtGui.QMainWindow):
         Set the details for the just downloaded provider.
 
         :param details: the details of the provider.
-        :type details: ProviderConfigLight
+        :type details: dict
         """
         self._provider_details = details
 
@@ -1331,7 +1341,7 @@ class MainWindow(QtGui.QMainWindow):
         mx_enabled = MX_SERVICE in enabled_services
         mx_provided = False
         if self._provider_details is not None:
-            mx_provided = MX_SERVICE in self._provider_details.services
+            mx_provided = MX_SERVICE in self._provider_details['services']
 
         return mx_enabled and mx_provided
 
@@ -1348,7 +1358,7 @@ class MainWindow(QtGui.QMainWindow):
         eip_enabled = EIP_SERVICE in enabled_services
         eip_provided = False
         if self._provider_details is not None:
-            eip_provided = EIP_SERVICE in self._provider_details.services
+            eip_provided = EIP_SERVICE in self._provider_details['services']
 
         return eip_enabled and eip_provided
 
@@ -1465,55 +1475,25 @@ class MainWindow(QtGui.QMainWindow):
         self._already_started_eip = True
 
         # check for connectivity
-        # we might want to leave a little time here...
-        self._check_name_resolution(domain)
-
-    def _check_name_resolution(self, domain):
-        # FIXME this has to be moved to backend !!!
-        # Should move to netchecks module.
-        # and separate qt from reactor...
-        """
-        Check if we can resolve the given domain name.
-
-        :param domain: the domain to check.
-        :type domain: str
-        """
-        def do_check():
-            """
-            Try to resolve the domain name.
-            """
-            socket.gethostbyname(domain.encode('idna'))
-
-        def check_err(failure):
-            """
-            Errback handler for `do_check`.
-
-            :param failure: the failure that triggered the errback.
-            :type failure: twisted.python.failure.Failure
-            """
-            logger.error(repr(failure))
-            logger.error("Can't resolve hostname.")
-
-            msg = self.tr(
-                "The server at {0} can't be found, because the DNS lookup "
-                "failed. DNS is the network service that translates a "
-                "website's name to its Internet address. Either your computer "
-                "is having trouble connecting to the network, or you are "
-                "missing some helper files that are needed to securely use "
-                "DNS while {1} is active. To install these helper files, quit "
-                "this application and start it again."
-            ).format(domain, self._eip_conductor.eip_name)
-
-            show_err = lambda: QtGui.QMessageBox.critical(
-                self, self.tr("Connection Error"), msg)
-            reactor.callLater(0, show_err)
-
-            # python 2.7.4 raises socket.error
-            # python 2.7.5 raises socket.gaierror
-            failure.trap(socket.gaierror, socket.error)
-
-        d = threads.deferToThread(do_check)
-        d.addErrback(check_err)
+        self._backend.eip_check_dns(domain)
+
+    @QtCore.Slot()
+    def _eip_dns_error(self):
+        """
+        Trigger this if we don't have a working DNS resolver.
+        """
+        domain = self._login_widget.get_selected_provider()
+        msg = self.tr(
+            "The server at {0} can't be found, because the DNS lookup "
+            "failed. DNS is the network service that translates a "
+            "website's name to its Internet address. Either your computer "
+            "is having trouble connecting to the network, or you are "
+            "missing some helper files that are needed to securely use "
+            "DNS while {1} is active. To install these helper files, quit "
+            "this application and start it again."
+        ).format(domain, self._eip_conductor.eip_name)
+
+        QtGui.QMessageBox.critical(self, self.tr("Connection Error"), msg)
 
     def _try_autostart_eip(self):
         """
@@ -1543,7 +1523,13 @@ class MainWindow(QtGui.QMainWindow):
         else:
             should_start = self._provides_eip_and_enabled()
 
-        if should_start and not self._already_started_eip:
+        missing_helpers = self._eip_status.missing_helpers
+        already_started = self._already_started_eip
+        can_start = (should_start
+                     and not already_started
+                     and not missing_helpers)
+
+        if can_start:
             if self._eip_status.is_cold_start:
                 self._backend.tear_fw_down()
             # XXX this should be handled by the state machine.
@@ -1563,12 +1549,16 @@ class MainWindow(QtGui.QMainWindow):
         else:
             if not self._already_started_eip:
                 if EIP_SERVICE in self._enabled_services:
-                    self._eip_status.set_eip_status(
-                        self.tr("Not supported"),
-                        error=True)
+                    if missing_helpers:
+                        msg = self.tr(
+                            "Disabled: missing helper files")
+                    else:
+                        msg = self.tr("Not supported"),
+                    self._eip_status.set_eip_status(msg, error=True)
                 else:
+                    msg = self.tr("Disabled")
                     self._eip_status.disable_eip_start()
-                    self._eip_status.set_eip_status(self.tr("Disabled"))
+                    self._eip_status.set_eip_status(msg)
             # eip will not start, so we start soledad anyway
             self._maybe_run_soledad_setup_checks()
 
@@ -1772,8 +1762,7 @@ class MainWindow(QtGui.QMainWindow):
         # call final quit when all the services are stopped
         self.all_services_stopped.connect(self.final_quit)
         # or if we reach the timeout
-        self._quit_timeout_callater = reactor.callLater(
-            self.SERVICES_STOP_TIMEOUT, self.final_quit)
+        QtDelayedCall(self.SERVICES_STOP_TIMEOUT, self.final_quit)
 
     @QtCore.Slot()
     def _remove_service(self, service):
@@ -1799,16 +1788,13 @@ class MainWindow(QtGui.QMainWindow):
         """
         logger.debug('Final quit...')
 
-        try:
-            # disconnect signal if we get here due a timeout.
-            self.all_services_stopped.disconnect(self.final_quit)
-        except RuntimeError:
-            pass  # Signal was not connected
+        # 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.
+        if self._finally_quitting:
+            return
 
-        # Cancel timeout to avoid being called if we reached here through the
-        # signal
-        if self._quit_timeout_callater.active():
-            self._quit_timeout_callater.cancel()
+        self._finally_quitting = True
 
         # Remove lockfiles on a clean shutdown.
         logger.debug('Cleaning pidfiles')
@@ -1818,4 +1804,4 @@ class MainWindow(QtGui.QMainWindow):
         self._backend.stop()
         self.close()
 
-        reactor.callLater(1, self._quit_callback)
+        QtDelayedCall(100, twisted_main.quit)
diff --git a/src/leap/bitmask/gui/twisted_main.py b/src/leap/bitmask/gui/twisted_main.py
index dfd69033f41bfbf797f9fda414617025f73e3169..b1ce0ead6b234203b5a9367e1edafb1cf4b5d2c6 100644
--- a/src/leap/bitmask/gui/twisted_main.py
+++ b/src/leap/bitmask/gui/twisted_main.py
@@ -36,11 +36,8 @@ def stop():
     logger.debug("Done stopping all the things.")
 
 
-def quit(app):
+def quit():
     """
     Stop the mainloop.
-
-    :param app: the main qt QApplication instance.
-    :type app: QtCore.QApplication
     """
     reactor.callLater(0, stop)
diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui
index 6c592522ce913a8f3e5918b0f7d6123c28a589f6..8c52897d4070253e1115e87bcfa2a06e5c455449 100644
--- a/src/leap/bitmask/gui/ui/wizard.ui
+++ b/src/leap/bitmask/gui/ui/wizard.ui
@@ -38,7 +38,7 @@
   <property name="options">
    <set>QWizard::IndependentPages</set>
   </property>
-  <widget class="QWizardPage" name="introduction_page">
+  <widget class="WizardPage" name="introduction_page">
    <property name="title">
     <string>Welcome</string>
    </property>
diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py
index 4d7749072d123c4a85275288173ade04f656e2ce..f66c553d5e3d82b26f2b8f4428af02a8272b2640 100644
--- a/src/leap/bitmask/gui/wizard.py
+++ b/src/leap/bitmask/gui/wizard.py
@@ -33,6 +33,7 @@ from leap.bitmask.util.keyring_helpers import has_keyring
 
 from ui_wizard import Ui_Wizard
 
+QtDelayedCall = QtCore.QTimer.singleShot
 logger = logging.getLogger(__name__)
 
 
@@ -64,6 +65,8 @@ class Wizard(QtGui.QWizard):
         self.ui = Ui_Wizard()
         self.ui.setupUi(self)
 
+        self._connected_signals = []
+
         self.setPixmap(QtGui.QWizard.LogoPixmap,
                        QtGui.QPixmap(":/images/mask-icon.png"))
 
@@ -79,8 +82,8 @@ class Wizard(QtGui.QWizard):
         self._use_existing_provider = False
 
         self.ui.grpCheckProvider.setVisible(False)
-        self.ui.btnCheck.clicked.connect(self._check_provider)
-        self.ui.lnProvider.returnPressed.connect(self._check_provider)
+        self._connect_and_track(self.ui.btnCheck.clicked, self._check_provider)
+        self._connect_and_track(self.ui.lnProvider.returnPressed, self._check_provider)
 
         self._backend = backend
         self._backend_connect()
@@ -95,24 +98,25 @@ class Wizard(QtGui.QWizard):
         self._provider_select_defer = None
         self._provider_setup_defer = None
 
-        self.currentIdChanged.connect(self._current_id_changed)
+        self._connect_and_track(self.currentIdChanged, self._current_id_changed)
 
-        self.ui.lnProvider.textChanged.connect(self._enable_check)
-        self.ui.rbNewProvider.toggled.connect(
+        self._connect_and_track(self.ui.lnProvider.textChanged, self._enable_check)
+        self._connect_and_track(self.ui.rbNewProvider.toggled,
             lambda x: self._enable_check())
-        self.ui.cbProviders.currentIndexChanged[int].connect(
+        self._connect_and_track(self.ui.cbProviders.currentIndexChanged[int],
             self._reset_provider_check)
 
-        self.ui.lblUser.returnPressed.connect(
+        self._connect_and_track(self.ui.lblUser.returnPressed,
             self._focus_password)
-        self.ui.lblPassword.returnPressed.connect(
+        self._connect_and_track(self.ui.lblPassword.returnPressed,
             self._focus_second_password)
-        self.ui.lblPassword2.returnPressed.connect(
+        self._connect_and_track(self.ui.lblPassword2.returnPressed,
             self._register)
-        self.ui.btnRegister.clicked.connect(
+        self._connect_and_track(self.ui.btnRegister.clicked,
             self._register)
 
-        self.ui.rbExistingProvider.toggled.connect(self._skip_provider_checks)
+        self._connect_and_track(self.ui.rbExistingProvider.toggled,
+                                self._skip_provider_checks)
 
         usernameRe = QtCore.QRegExp(USERNAME_REGEX)
         self.ui.lblUser.setValidator(
@@ -137,7 +141,19 @@ class Wizard(QtGui.QWizard):
 
         self._provider_checks_ok = False
         self._provider_setup_ok = False
-        self.finished.connect(self._wizard_finished)
+        self._connect_and_track(self.finished, self._wizard_finished)
+
+    def _connect_and_track(self, signal, method):
+        """
+        Helper to connect signals and keep track of them.
+
+        :param signal: the signal to connect to.
+        :type signal: QtCore.Signal
+        :param method: the method to call when the signal is triggered.
+        :type method: callable, Slot or Signal
+        """
+        self._connected_signals.append((signal, method))
+        signal.connect(method)
 
     @QtCore.Slot()
     def _wizard_finished(self):
@@ -153,28 +169,35 @@ class Wizard(QtGui.QWizard):
         self._provider_setup_ok = False
         self.ui.lnProvider.setText('')
         self.ui.grpCheckProvider.setVisible(False)
-        self._backend_disconnect()
+        self._disconnect_tracked()
 
     def _load_configured_providers(self):
         """
         Loads the configured providers into the wizard providers combo box.
         """
+        self._backend.provider_get_pinned_providers()
+
+    def _load_configured_providers_with_pinned(self, pinned):
+        """
+        Once we have the pinned providers from the backend, we
+        continue setting everything up
+
+        :param pinned: list of pinned providers
+        :type pinned: list of str
+        """
         ls = LeapSettings()
         providers = ls.get_configured_providers()
-        if not providers:
+        if not providers and not pinned:
             self.ui.rbExistingProvider.setEnabled(False)
             self.ui.label_8.setEnabled(False)  # 'https://' label
             self.ui.cbProviders.setEnabled(False)
             return
 
-        pinned = []
         user_added = []
 
         # separate pinned providers from user added ones
         for p in providers:
-            if ls.is_pinned_provider(p):
-                pinned.append(p)
-            else:
+            if p not in pinned:
                 user_added.append(p)
 
         if user_added:
@@ -191,6 +214,9 @@ class Wizard(QtGui.QWizard):
         # 'Use existing provider' option.
         self.ui.rbExistingProvider.setChecked(True)
 
+        # We need to set it as complete explicitly
+        self.page(self.INTRO_PAGE).set_completed()
+
     def get_domain(self):
         return self._domain
 
@@ -543,7 +569,7 @@ class Wizard(QtGui.QWizard):
         Set the details for the just downloaded provider.
 
         :param details: the details of the provider.
-        :type details: ProviderConfigLight
+        :type details: dict
         """
         self._provider_details = details
 
@@ -614,9 +640,9 @@ class Wizard(QtGui.QWizard):
         the user to enable or disable.
         """
         self.ui.grpServices.setTitle(
-            self.tr("Services by {0}").format(self._provider_details.name))
+            self.tr("Services by {0}").format(self._provider_details['name']))
 
-        services = get_supported(self._provider_details.services)
+        services = get_supported(self._provider_details['services'])
 
         for service in services:
             try:
@@ -659,7 +685,7 @@ class Wizard(QtGui.QWizard):
             if not self._provider_setup_ok:
                 self._reset_provider_setup()
                 sub_title = self.tr("Gathering configuration options for {0}")
-                sub_title = sub_title.format(self._provider_details.name)
+                sub_title = sub_title.format(self._provider_details['name'])
                 self.page(pageId).setSubTitle(sub_title)
                 self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON)
                 self._provider_setup_defer = self._backend.\
@@ -667,22 +693,22 @@ class Wizard(QtGui.QWizard):
 
         if pageId == self.PRESENT_PROVIDER_PAGE:
             sub_title = self.tr("Description of services offered by {0}")
-            sub_title = sub_title.format(self._provider_details.name)
+            sub_title = sub_title.format(self._provider_details['name'])
             self.page(pageId).setSubTitle(sub_title)
 
             details = self._provider_details
-            name = "<b>{0}</b>".format(details.name)
-            domain = "https://{0}".format(details.domain)
-            description = "<i>{0}</i>".format(details.description)
+            name = "<b>{0}</b>".format(details['name'])
+            domain = "https://{0}".format(details['domain'])
+            description = "<i>{0}</i>".format(details['description'])
             self.ui.lblProviderName.setText(name)
             self.ui.lblProviderURL.setText(domain)
             self.ui.lblProviderDesc.setText(description)
-            self.ui.lblServicesOffered.setText(details.services_string)
-            self.ui.lblProviderPolicy.setText(details.enrollment_policy)
+            self.ui.lblServicesOffered.setText(details['services_string'])
+            self.ui.lblProviderPolicy.setText(details['enrollment_policy'])
 
         if pageId == self.REGISTER_USER_PAGE:
             sub_title = self.tr("Register a new user with {0}")
-            sub_title = sub_title.format(self._provider_details.name)
+            sub_title = sub_title.format(self._provider_details['name'])
             self.page(pageId).setSubTitle(sub_title)
             self.ui.chkRemember.setVisible(False)
 
@@ -727,36 +753,30 @@ class Wizard(QtGui.QWizard):
         Connects all the backend signals with the wizard.
         """
         sig = self._backend.signaler
-        sig.prov_name_resolution.connect(self._name_resolution)
-        sig.prov_https_connection.connect(self._https_connection)
-        sig.prov_download_provider_info.connect(self._download_provider_info)
-        sig.prov_get_details.connect(self._provider_get_details)
+        conntrack = self._connect_and_track
+        conntrack(sig.prov_name_resolution, self._name_resolution)
+        conntrack(sig.prov_https_connection, self._https_connection)
+        conntrack(sig.prov_download_provider_info,
+                  self._download_provider_info)
+        conntrack(sig.prov_get_details, self._provider_get_details)
+        conntrack(sig.prov_get_pinned_providers,
+                  self._load_configured_providers_with_pinned)
 
-        sig.prov_download_ca_cert.connect(self._download_ca_cert)
-        sig.prov_check_ca_fingerprint.connect(self._check_ca_fingerprint)
-        sig.prov_check_api_certificate.connect(self._check_api_certificate)
+        conntrack(sig.prov_download_ca_cert, self._download_ca_cert)
+        conntrack(sig.prov_check_ca_fingerprint, self._check_ca_fingerprint)
+        conntrack(sig.prov_check_api_certificate, self._check_api_certificate)
 
-        sig.srp_registration_finished.connect(self._registration_finished)
-        sig.srp_registration_failed.connect(self._registration_failed)
-        sig.srp_registration_taken.connect(self._registration_taken)
+        conntrack(sig.srp_registration_finished, self._registration_finished)
+        conntrack(sig.srp_registration_failed, self._registration_failed)
+        conntrack(sig.srp_registration_taken, self._registration_taken)
 
-    def _backend_disconnect(self):
+    def _disconnect_tracked(self):
         """
         This method is called when the wizard dialog is closed.
-        We disconnect all the backend signals in here.
+        We disconnect all the signals in here.
         """
-        sig = self._backend.signaler
-        try:
-            # disconnect backend signals
-            sig.prov_name_resolution.disconnect(self._name_resolution)
-            sig.prov_https_connection.disconnect(self._https_connection)
-            sig.prov_download_provider_info.disconnect(
-                self._download_provider_info)
-
-            sig.prov_download_ca_cert.disconnect(self._download_ca_cert)
-            sig.prov_check_ca_fingerprint.disconnect(
-                self._check_ca_fingerprint)
-            sig.prov_check_api_certificate.disconnect(
-                self._check_api_certificate)
-        except RuntimeError:
-            pass  # Signal was not connected
+        for signal, method in self._connected_signals:
+            try:
+                signal.disconnect(method)
+            except RuntimeError:
+                pass  # Signal was not connected
diff --git a/src/leap/bitmask/logs/utils.py b/src/leap/bitmask/logs/utils.py
index 06959c454afdf992c421d4a3d5c3aaaedcae003d..8367937aefa7b20b1bd0c4ce2d9f827162ee561e 100644
--- a/src/leap/bitmask/logs/utils.py
+++ b/src/leap/bitmask/logs/utils.py
@@ -8,7 +8,7 @@ from leap.bitmask.logs.streamtologger import StreamToLogger
 from leap.bitmask.platform_init import IS_WIN
 
 
-def get_logger(debug=False, logfile=None, replace_stdout=True):
+def create_logger(debug=False, logfile=None, replace_stdout=True):
     """
     Create the logger and attach the handlers.
 
diff --git a/src/leap/bitmask/platform_init/initializers.py b/src/leap/bitmask/platform_init/initializers.py
index b282a229afe59c09c7f5c5645dbdfd6ab9792e25..384e1ec1395c33415a74a1f6aa7136b8c6881c26 100644
--- a/src/leap/bitmask/platform_init/initializers.py
+++ b/src/leap/bitmask/platform_init/initializers.py
@@ -25,8 +25,9 @@ import sys
 import subprocess
 import tempfile
 
-from PySide import QtGui
+from PySide import QtGui, QtCore
 
+from leap.bitmask.config import flags
 from leap.bitmask.config.leapsettings import LeapSettings
 from leap.bitmask.services.eip import get_vpn_launcher
 from leap.bitmask.services.eip.linuxvpnlauncher import LinuxVPNLauncher
@@ -44,6 +45,16 @@ __all__ = ["init_platform"]
 _system = platform.system()
 
 
+class InitSignals(QtCore.QObject):
+    """
+    Signal container to communicate initialization events to differnt widgets.
+    """
+    eip_missing_helpers = QtCore.Signal()
+
+
+init_signals = InitSignals()
+
+
 def init_platform():
     """
     Return the right initializer for the platform we are running in, or
@@ -70,25 +81,26 @@ NOTFOUND_MSG = ("Tried to install %s, but %s "
 BADEXEC_MSG = ("Tried to install %s, but %s "
                "failed to %s.")
 
-UPDOWN_NOTFOUND_MSG = NOTFOUND_MSG % (
-    "updown scripts", "those were")
-UPDOWN_BADEXEC_MSG = BADEXEC_MSG % (
-    "updown scripts", "they", "be copied")
+HELPERS_NOTFOUND_MSG = NOTFOUND_MSG % (
+    "helper files", "those were")
+HELPERS_BADEXEC_MSG = BADEXEC_MSG % (
+    "helper files", "they", "be copied")
 
 
-def get_missing_updown_dialog():
+def get_missing_helpers_dialog():
     """
-    Create a dialog for notifying of missing updown scripts.
+    Create a dialog for notifying of missing helpers.
     Returns that dialog.
 
     :rtype: QtGui.QMessageBox instance
     """
     WE_NEED_POWERS = ("To better protect your privacy, "
                       "Bitmask needs administrative privileges "
-                      "to install helper files. "
-                      "Do you want to proceed?")
+                      "to install helper files. Encrypted "
+                      "Internet cannot work without those files. "
+                      "Do you want to install them now?")
     msg = QtGui.QMessageBox()
-    msg.setWindowTitle(msg.tr("Missing up/down scripts"))
+    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))
@@ -104,14 +116,25 @@ def check_missing():
     raises a dialog to ask user for permission to do it.
     """
     config = LeapSettings()
+    complain_missing = False
     alert_missing = config.get_alert_missing_scripts()
 
+    if alert_missing and not flags.STANDALONE:
+        # We refuse to install missing stuff if not running with standalone
+        # flag. Right now we rely on the flag alone, but we can disable this
+        # by overwriting some constant from within the debian package.
+        alert_missing = False
+        complain_missing = True
+
     launcher = get_vpn_launcher()
     missing_scripts = launcher.missing_updown_scripts
     missing_other = launcher.missing_other_files
 
-    if alert_missing and (missing_scripts() or missing_other()):
-        msg = get_missing_updown_dialog()
+    logger.debug("MISSING OTHER: %s" % (str(missing_other())))
+
+    missing_some = missing_scripts() or missing_other()
+    if alert_missing and missing_some:
+        msg = get_missing_helpers_dialog()
         ret = msg.exec_()
 
         if ret == QtGui.QMessageBox.Yes:
@@ -124,7 +147,7 @@ def check_missing():
                 return
 
             # XXX maybe move constants to fun
-            ok = install_missing_fun(UPDOWN_BADEXEC_MSG, UPDOWN_NOTFOUND_MSG)
+            ok = install_missing_fun(HELPERS_BADEXEC_MSG, HELPERS_NOTFOUND_MSG)
             if not ok:
                 msg = QtGui.QMessageBox()
                 msg.setWindowTitle(msg.tr("Problem installing files"))
@@ -135,12 +158,19 @@ def check_missing():
         elif ret == QtGui.QMessageBox.No:
             logger.debug("Not installing missing scripts, "
                          "user decided to ignore our warning.")
+            init_signals.eip_missing_helpers.emit()
 
         elif ret == QtGui.QMessageBox.Rejected:
             logger.debug(
                 "Setting alert_missing_scripts to False, we will not "
                 "ask again")
             config.set_alert_missing_scripts(False)
+
+    if complain_missing and missing_some:
+        missing = missing_scripts() + missing_other()
+        msg = _get_missing_complain_dialog(missing)
+        ret = msg.exec_()
+
 #
 # windows initializers
 #
@@ -246,13 +276,12 @@ def _darwin_install_missing_scripts(badexec, notfound):
     # We expect to execute this from some way of bundle, since
     # the up/down scripts should be put in place by the installer.
     success = False
-    installer_path = os.path.join(
-        os.getcwd(),
-        "..",
-        "Resources",
-        "openvpn")
+    installer_path = os.path.abspath(
+        os.path.join(
+            os.getcwd(), "..", "Resources", "openvpn"))
     launcher = DarwinVPNLauncher
 
+    # XXX FIXME !!! call the bash script!
     if os.path.isdir(installer_path):
         fd, tempscript = tempfile.mkstemp(prefix="leap_installer-")
         try:
@@ -350,24 +379,72 @@ def _get_missing_resolvconf_dialog():
 
     :rtype: QtGui.QMessageBox instance
     """
-    NO_RESOLVCONF = (
+    msgstr = QtCore.QObject()
+    msgstr.NO_RESOLVCONF = msgstr.tr(
         "Could not find <b>resolvconf</b> installed in your system.\n"
         "Do you want to quit Bitmask now?")
 
-    EXPLAIN = (
+    msgstr.EXPLAIN = msgstr.tr(
         "Encrypted Internet needs resolvconf installed to work properly.\n"
         "Please use your package manager to install it.\n")
 
     msg = QtGui.QMessageBox()
     msg.setWindowTitle(msg.tr("Missing resolvconf framework"))
-    msg.setText(msg.tr(NO_RESOLVCONF))
+    msg.setText(msgstr.NO_RESOLVCONF)
     # but maybe the user really deserve to know more
-    msg.setInformativeText(msg.tr(EXPLAIN))
+    msg.setInformativeText(msgstr.EXPLAIN)
     msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
     msg.setDefaultButton(QtGui.QMessageBox.Yes)
     return msg
 
 
+def _get_missing_complain_dialog(stuff):
+    """
+    Create a dialog for notifying about missing helpers (but doing nothing).
+    Used from non-standalone runs.
+
+    :param stuff: list of missing items to display
+    :type stuff: list
+    :rtype: QtGui.QMessageBox instance
+    """
+    msgstr = QtCore.QObject()
+    msgstr.NO_HELPERS = msgstr.tr(
+        "Some essential helper files are missing in your system.")
+    msgstr.EXPLAIN = msgstr.tr(
+        "Reinstall your debian packages, or make sure you place them by hand.")
+
+    class ComplainDialog(QtGui.QDialog):
+
+        def __init__(self, parent=None):
+                super(ComplainDialog, self).__init__(parent)
+
+                label = QtGui.QLabel(msgstr.NO_HELPERS)
+                label.setAlignment(QtCore.Qt.AlignLeft)
+
+                label2 = QtGui.QLabel(msgstr.EXPLAIN)
+                label2.setAlignment(QtCore.Qt.AlignLeft)
+
+                textedit = QtGui.QTextEdit()
+                textedit.setText("\n".join(stuff))
+
+                ok = QtGui.QPushButton()
+                ok.setText(self.tr("Ok, thanks"))
+                self.ok = ok
+                self.ok.clicked.connect(self.close)
+
+                mainLayout = QtGui.QGridLayout()
+                mainLayout.addWidget(label, 0, 0)
+                mainLayout.addWidget(label2, 1, 0)
+                mainLayout.addWidget(textedit, 2, 0)
+                mainLayout.addWidget(ok, 3, 0)
+
+                self.setLayout(mainLayout)
+
+    msg = ComplainDialog()
+    msg.setWindowTitle(msg.tr("Missing Bitmask helpers"))
+    return msg
+
+
 def _linux_check_resolvconf():
     """
     Raise a dialog warning about the lack of the resolvconf framework.
@@ -385,7 +462,7 @@ def _linux_check_resolvconf():
 
 def _linux_install_missing_scripts(badexec, notfound):
     """
-    Try to install the missing up/down scripts.
+    Try to install the missing helper files.
 
     :param badexec: error for notifying execution error during command.
     :type badexec: str
@@ -395,38 +472,32 @@ def _linux_install_missing_scripts(badexec, notfound):
     :rtype: bool
     """
     success = False
-    installer_path = os.path.join(os.getcwd(), "apps", "eip", "files")
+    installer_path = os.path.abspath(
+        os.path.join(os.getcwd(), "apps", "eip", "files"))
     launcher = LinuxVPNLauncher
 
-    # XXX refactor with darwin, same block.
+    install_helper = "leap-install-helper.sh"
+    install_helper_path = os.path.join(installer_path, install_helper)
+
+    install_opts = ("--from-path %s --install-bitmask-root YES "
+                    "--install-polkit-file YES --install-openvpn YES "
+                    "--remove-old-files YES" % (installer_path,))
 
     if os.path.isdir(installer_path):
-        fd, tempscript = tempfile.mkstemp(prefix="leap_installer-")
-        polfd, pol_tempfile = tempfile.mkstemp(prefix="leap_installer-")
         try:
             pkexec = first(launcher.maybe_pkexec())
-            scriptlines = launcher.cmd_for_missing_scripts(installer_path)
-            with os.fdopen(fd, 'w') as f:
-                f.write(scriptlines)
+            cmdline = ["%s %s %s" % (
+                pkexec, install_helper_path, install_opts)]
 
-            st = os.stat(tempscript)
-            os.chmod(tempscript, st.st_mode | stat.S_IEXEC | stat.S_IXUSR |
-                     stat.S_IXGRP | stat.S_IXOTH)
-            cmdline = ["%s %s" % (pkexec, tempscript)]
             ret = subprocess.call(
                 cmdline, stdout=subprocess.PIPE,
                 shell=True)
             success = ret == 0
             if not success:
-                logger.error("Install missing scripts failed.")
+                logger.error("Install of helpers failed.")
         except Exception as exc:
             logger.error(badexec)
             logger.error("Error was: %r" % (exc,))
-        finally:
-            try:
-                os.remove(tempscript)
-            except OSError as exc:
-                logger.error("%r" % (exc,))
     else:
         logger.error(notfound)
         logger.debug('path searched: %s' % (installer_path,))
diff --git a/src/leap/bitmask/provider/pinned.py b/src/leap/bitmask/provider/pinned.py
new file mode 100644
index 0000000000000000000000000000000000000000..38851621a00d5311af1cf97976dcee158285ceaa
--- /dev/null
+++ b/src/leap/bitmask/provider/pinned.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+# pinned.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/>.
+"""
+Pinned Providers
+"""
+import logging
+
+from leap.bitmask.provider import pinned_demobitmask
+from leap.bitmask.provider import pinned_riseup
+
+logger = logging.getLogger(__name__)
+
+
+class PinnedProviders(object):
+    """
+    Represents the providers that are pinned in Bitmask
+    """
+
+    CONFIG_KEY = "config"
+    CACERT_KEY = "cacert"
+
+    PROVIDERS = {
+        pinned_demobitmask.DOMAIN: {
+            CONFIG_KEY: pinned_demobitmask.PROVIDER_JSON,
+            CACERT_KEY: pinned_demobitmask.CACERT_PEM,
+        },
+        pinned_riseup.DOMAIN: {
+            CONFIG_KEY: pinned_riseup.PROVIDER_JSON,
+            CACERT_KEY: pinned_riseup.CACERT_PEM,
+        }
+    }
+
+    def __init__(self):
+        pass
+
+    @classmethod
+    def domains(self):
+        """
+        Return the domains that are pinned in here
+
+        :rtype: list of str
+        """
+        return self.PROVIDERS.keys()
+
+    @classmethod
+    def save_hardcoded(self, domain, provider_path, cacert_path):
+        """
+        Save the pinned content for provider.json and cacert.pem to
+        the specified paths
+
+        :param domain: domain of the pinned provider
+        :type domain: str
+        :param provider_path: path where the pinned provider.json will
+                              be saved
+        :type provider_path: str
+        :param cacert_path: path where the pinned cacert.pem will be
+                            saved
+        :type cacert_path: str
+        """
+        with open(provider_path, "w") as f:
+            f.write(self.PROVIDERS[domain][self.CONFIG_KEY])
+
+        with open(cacert_path, "w") as f:
+            f.write(self.PROVIDERS[domain][self.CACERT_KEY])
diff --git a/src/leap/bitmask/provider/pinned_demobitmask.py b/src/leap/bitmask/provider/pinned_demobitmask.py
new file mode 100644
index 0000000000000000000000000000000000000000..9c699a4ca74bcb5c959506f879e50b424b569c84
--- /dev/null
+++ b/src/leap/bitmask/provider/pinned_demobitmask.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+# pinned_demobitmask.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/>.
+"""
+Pinned provider.json and cacert.pem for demo.bitmask.net
+"""
+
+DOMAIN = "demo.bitmask.net"
+
+PROVIDER_JSON = """
+{
+  "api_uri": "https://api.demo.bitmask.net:4430",
+  "api_version": "1",
+  "ca_cert_fingerprint": "SHA256: 0f17c033115f6b76ff67871872303ff65034efe7dd1b910062ca323eb4da5c7e",
+  "ca_cert_uri": "https://demo.bitmask.net/ca.crt",
+  "default_language": "en",
+  "description": {
+    "el": "demo.bitmask.net allows you to test the Bitmask application. User accounts may be periodically deleted.",
+    "en": "demo.bitmask.net allows you to test the Bitmask application. User accounts may be periodically deleted.",
+    "es": "demo.bitmask.net allows you to test the Bitmask application. User accounts may be periodically deleted."
+  },
+  "domain": "demo.bitmask.net",
+  "enrollment_policy": "open",
+  "languages": [
+    "en"
+  ],
+  "name": {
+    "en": "Bitmask"
+  },
+  "service": {
+    "allow_anonymous": true,
+    "allow_free": true,
+    "allow_limited_bandwidth": false,
+    "allow_paid": true,
+    "allow_registration": true,
+    "allow_unlimited_bandwidth": true,
+    "bandwidth_limit": 102400,
+    "default_service_level": 1,
+    "levels": [
+      {
+        "id": 1,
+        "name": "free",
+        "storage": 50
+      },
+      {
+        "id": 2,
+        "name": "basic",
+        "rate": [
+          "US$10",
+          "\u20ac10"
+        ],
+        "storage": 1000
+      },
+      {
+        "id": 3,
+        "name": "pro",
+        "rate": [
+          "US$20",
+          "\u20ac20"
+        ],
+        "storage": 10000
+      }
+    ]
+  },
+  "services": [
+    "openvpn"
+  ]
+}
+"""
+
+CACERT_PEM = """-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgIBATANBgkqhkiG9w0BAQ0FADBKMRgwFgYDVQQDDA9CaXRt
+YXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNVBAsME2h0dHBzOi8v
+Yml0bWFzay5uZXQwHhcNMTIxMTA2MDAwMDAwWhcNMjIxMTA2MDAwMDAwWjBKMRgw
+FgYDVQQDDA9CaXRtYXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNV
+BAsME2h0dHBzOi8vYml0bWFzay5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQC1eV4YvayaU+maJbWrD4OHo3d7S1BtDlcvkIRS1Fw3iYDjsyDkZxai
+dHp4EUasfNQ+EVtXUvtk6170EmLco6Elg8SJBQ27trE6nielPRPCfX3fQzETRfvB
+7tNvGw4Jn2YKiYoMD79kkjgyZjkJ2r/bEHUSevmR09BRp86syHZerdNGpXYhcQ84
+CA1+V+603GFIHnrP+uQDdssW93rgDNYu+exT+Wj6STfnUkugyjmPRPjL7wh0tzy+
+znCeLl4xiV3g9sjPnc7r2EQKd5uaTe3j71sDPF92KRk0SSUndREz+B1+Dbe/RGk4
+MEqGFuOzrtsgEhPIX0hplhb0Tgz/rtug+yTT7oJjBa3u20AAOQ38/M99EfdeJvc4
+lPFF1XBBLh6X9UKF72an2NuANiX6XPySnJgZ7nZ09RiYZqVwu/qt3DfvLfhboq+0
+bQvLUPXrVDr70onv5UDjpmEA/cLmaIqqrduuTkFZOym65/PfAPvpGnt7crQj/Ibl
+DEDYZQmP7AS+6zBjoOzNjUGE5r40zWAR1RSi7zliXTu+yfsjXUIhUAWmYR6J3KxB
+lfsiHBQ+8dn9kC3YrUexWoOqBiqJOAJzZh5Y1tqgzfh+2nmHSB2dsQRs7rDRRlyy
+YMbkpzL9ZsOUO2eTP1mmar6YjCN+rggYjRrX71K2SpBG6b1zZxOG+wIDAQABo2Aw
+XjAdBgNVHQ4EFgQUuYGDLL2sswnYpHHvProt1JU+D48wDgYDVR0PAQH/BAQDAgIE
+MAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAUuYGDLL2sswnYpHHvProt1JU+D48w
+DQYJKoZIhvcNAQENBQADggIBADeG67vaFcbITGpi51264kHPYPEWaXUa5XYbtmBl
+cXYyB6hY5hv/YNuVGJ1gWsDmdeXEyj0j2icGQjYdHRfwhrbEri+h1EZOm1cSBDuY
+k/P5+ctHyOXx8IE79DBsZ6IL61UKIaKhqZBfLGYcWu17DVV6+LT+AKtHhOrv3TSj
+RnAcKnCbKqXLhUPXpK0eTjPYS2zQGQGIhIy9sQXVXJJJsGrPgMxna1Xw2JikBOCG
+htD/JKwt6xBmNwktH0GI/LVtVgSp82Clbn9C4eZN9E5YbVYjLkIEDhpByeC71QhX
+EIQ0ZR56bFuJA/CwValBqV/G9gscTPQqd+iETp8yrFpAVHOW+YzSFbxjTEkBte1J
+aF0vmbqdMAWLk+LEFPQRptZh0B88igtx6tV5oVd+p5IVRM49poLhuPNJGPvMj99l
+mlZ4+AeRUnbOOeAEuvpLJbel4rhwFzmUiGoeTVoPZyMevWcVFq6BMkS+jRR2w0jK
+G6b0v5XDHlcFYPOgUrtsOBFJVwbutLvxdk6q37kIFnWCd8L3kmES5q4wjyFK47Co
+Ja8zlx64jmMZPg/t3wWqkZgXZ14qnbyG5/lGsj5CwVtfDljrhN0oCWK1FZaUmW3d
+69db12/g4f6phldhxiWuGC/W6fCW5kre7nmhshcltqAJJuU47iX+DarBFiIj816e
+yV8e
+-----END CERTIFICATE-----"""
diff --git a/src/leap/bitmask/provider/pinned_riseup.py b/src/leap/bitmask/provider/pinned_riseup.py
new file mode 100644
index 0000000000000000000000000000000000000000..8cc51506c4f1eb12a80563b7f6dbc75e6116c4c5
--- /dev/null
+++ b/src/leap/bitmask/provider/pinned_riseup.py
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+# pinned_riseup.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/>.
+"""
+Pinned provider.json and cacert.pem for riseup.net
+"""
+
+DOMAIN = "riseup.net"
+
+PROVIDER_JSON = """
+{
+  "api_uri": "https://api.black.riseup.net:4430",
+  "api_version": "1",
+  "ca_cert_fingerprint": "SHA256: a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494",
+  "ca_cert_uri": "https://black.riseup.net/ca.crt",
+  "default_language": "en",
+  "description": {
+    "en": "Riseup is a non-profit collective in Seattle that provides online communication tools for people and groups working toward liberatory social change."
+  },
+  "domain": "riseup.net",
+  "enrollment_policy": "open",
+  "languages": [
+    "en"
+  ],
+  "name": {
+    "en": "Riseup Networks"
+  },
+  "service": {
+    "allow_anonymous": false,
+    "allow_free": true,
+    "allow_limited_bandwidth": false,
+    "allow_paid": false,
+    "allow_registration": true,
+    "allow_unlimited_bandwidth": true,
+    "bandwidth_limit": 102400,
+    "default_service_level": 1,
+    "levels": {
+      "1": {
+        "description": "Please donate.",
+        "name": "free"
+      }
+    }
+  },
+  "services": [
+    "openvpn"
+  ]
+}
+"""
+
+CACERT_PEM = """-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIBATANBgkqhkiG9w0BAQ0FADBZMRgwFgYDVQQKDA9SaXNl
+dXAgTmV0d29ya3MxGzAZBgNVBAsMEmh0dHBzOi8vcmlzZXVwLm5ldDEgMB4GA1UE
+AwwXUmlzZXVwIE5ldHdvcmtzIFJvb3QgQ0EwHhcNMTQwNDI4MDAwMDAwWhcNMjQw
+NDI4MDAwMDAwWjBZMRgwFgYDVQQKDA9SaXNldXAgTmV0d29ya3MxGzAZBgNVBAsM
+Emh0dHBzOi8vcmlzZXVwLm5ldDEgMB4GA1UEAwwXUmlzZXVwIE5ldHdvcmtzIFJv
+b3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC76J4ciMJ8Sg0m
+TP7DF2DT9zNe0Csk4myoMFC57rfJeqsAlJCv1XMzBmXrw8wq/9z7XHv6n/0sWU7a
+7cF2hLR33ktjwODlx7vorU39/lXLndo492ZBhXQtG1INMShyv+nlmzO6GT7ESfNE
+LliFitEzwIegpMqxCIHXFuobGSCWF4N0qLHkq/SYUMoOJ96O3hmPSl1kFDRMtWXY
+iw1SEKjUvpyDJpVs3NGxeLCaA7bAWhDY5s5Yb2fA1o8ICAqhowurowJpW7n5ZuLK
+5VNTlNy6nZpkjt1QycYvNycffyPOFm/Q/RKDlvnorJIrihPkyniV3YY5cGgP+Qkx
+HUOT0uLA6LHtzfiyaOqkXwc4b0ZcQD5Vbf6Prd20Ppt6ei0zazkUPwxld3hgyw58
+m/4UIjG3PInWTNf293GngK2Bnz8Qx9e/6TueMSAn/3JBLem56E0WtmbLVjvko+LF
+PM5xA+m0BmuSJtrD1MUCXMhqYTtiOvgLBlUm5zkNxALzG+cXB28k6XikXt6MRG7q
+hzIPG38zwkooM55yy5i1YfcIi5NjMH6A+t4IJxxwb67MSb6UFOwg5kFokdONZcwj
+shczHdG9gLKSBIvrKa03Nd3W2dF9hMbRu//STcQxOailDBQCnXXfAATj9pYzdY4k
+ha8VCAREGAKTDAex9oXf1yRuktES4QIDAQABo2AwXjAdBgNVHQ4EFgQUC4tdmLVu
+f9hwfK4AGliaet5KkcgwDgYDVR0PAQH/BAQDAgIEMAwGA1UdEwQFMAMBAf8wHwYD
+VR0jBBgwFoAUC4tdmLVuf9hwfK4AGliaet5KkcgwDQYJKoZIhvcNAQENBQADggIB
+AGzL+GRnYu99zFoy0bXJKOGCF5XUXP/3gIXPRDqQf5g7Cu/jYMID9dB3No4Zmf7v
+qHjiSXiS8jx1j/6/Luk6PpFbT7QYm4QLs1f4BlfZOti2KE8r7KRDPIecUsUXW6P/
+3GJAVYH/+7OjA39za9AieM7+H5BELGccGrM5wfl7JeEz8in+V2ZWDzHQO4hMkiTQ
+4ZckuaL201F68YpiItBNnJ9N5nHr1MRiGyApHmLXY/wvlrOpclh95qn+lG6/2jk7
+3AmihLOKYMlPwPakJg4PYczm3icFLgTpjV5sq2md9bRyAg3oPGfAuWHmKj2Ikqch
+Td5CHKGxEEWbGUWEMP0s1A/JHWiCbDigc4Cfxhy56CWG4q0tYtnc2GMw8OAUO6Wf
+Xu5pYKNkzKSEtT/MrNJt44tTZWbKV/Pi/N2Fx36my7TgTUj7g3xcE9eF4JV2H/sg
+tsK3pwE0FEqGnT4qMFbixQmc8bGyuakr23wjMvfO7eZUxBuWYR2SkcP26sozF9PF
+tGhbZHQVGZUTVPyvwahMUEhbPGVerOW0IYpxkm0x/eaWdTc4vPpf/rIlgbAjarnJ
+UN9SaWRlWKSdP4haujnzCoJbM7dU9bjvlGZNyXEekgeT0W2qFeGGp+yyUWw8tNsp
+0BuC1b7uW/bBn/xKm319wXVDvBgZgcktMolak39V7DVO
+-----END CERTIFICATE-----"""
diff --git a/src/leap/bitmask/provider/providerbootstrapper.py b/src/leap/bitmask/provider/providerbootstrapper.py
index 6cdfe4f4f174e57f31244f50557c118ddbf44970..8c96a8b5fb512bbbfb19632f4ca7b100d2ff0ca6 100644
--- a/src/leap/bitmask/provider/providerbootstrapper.py
+++ b/src/leap/bitmask/provider/providerbootstrapper.py
@@ -29,6 +29,7 @@ from leap.bitmask import util
 from leap.bitmask.config import flags
 from leap.bitmask.config.providerconfig import ProviderConfig, MissingCACert
 from leap.bitmask.provider import get_provider_path
+from leap.bitmask.provider.pinned import PinnedProviders
 from leap.bitmask.services.abstractbootstrapper import AbstractBootstrapper
 from leap.bitmask.util.constants import REQUEST_TIMEOUT
 from leap.bitmask.util.request_helpers import get_content
@@ -176,6 +177,14 @@ class ProviderBootstrapper(AbstractBootstrapper):
         provider_json = os.path.join(util.get_path_prefix(),
                                      get_provider_path(domain))
 
+        if domain in PinnedProviders.domains() and \
+           not os.path.exists(provider_json):
+            mkdir_p(os.path.join(os.path.dirname(provider_json),
+                                 "keys", "ca"))
+            cacert = os.path.join(os.path.dirname(provider_json),
+                                  "keys", "ca", "cacert.pem")
+            PinnedProviders.save_hardcoded(domain, provider_json, cacert)
+
         mtime = get_mtime(provider_json)
 
         if self._download_if_needed and mtime:
diff --git a/src/leap/bitmask/services/eip/linuxvpnlauncher.py b/src/leap/bitmask/services/eip/linuxvpnlauncher.py
index 955768d110c39c34b614a4b8351d621baab4a75f..8ec0c050dee9af51392979c9baad90da923344e9 100644
--- a/src/leap/bitmask/services/eip/linuxvpnlauncher.py
+++ b/src/leap/bitmask/services/eip/linuxvpnlauncher.py
@@ -29,7 +29,7 @@ from leap.bitmask.util.privilege_policies import LinuxPolicyChecker
 from leap.common.files import which
 from leap.bitmask.services.eip.vpnlauncher import VPNLauncher
 from leap.bitmask.services.eip.vpnlauncher import VPNLauncherException
-from leap.bitmask.util import get_path_prefix
+from leap.bitmask.util import get_path_prefix, force_eval
 from leap.common.check import leap_assert
 from leap.bitmask.util import first
 
@@ -105,26 +105,34 @@ leapfile = lambda f: "%s/%s" % (SYSTEM_CONFIG, f)
 
 class LinuxVPNLauncher(VPNLauncher):
     PKEXEC_BIN = 'pkexec'
-    BITMASK_ROOT = "/usr/sbin/bitmask-root"
 
-    # We assume this is there by our openvpn dependency, and
-    # we will put it there on the bundle too.
-    if flags.STANDALONE:
-        OPENVPN_BIN_PATH = "/usr/sbin/leap-openvpn"
-    else:
-        OPENVPN_BIN_PATH = "/usr/sbin/openvpn"
-
-    POLKIT_PATH = LinuxPolicyChecker.get_polkit_path()
-
-    if flags.STANDALONE:
-        RESOLVCONF_BIN_PATH = "/usr/local/sbin/leap-resolvconf"
-    else:
+    # The following classes depend on force_eval to be called against
+    # the classes, to get the evaluation of the standalone flag on runtine.
+    # If we keep extending this kind of classes, we should abstract the
+    # handling of the STANDALONE flag in a base class
+
+    class BITMASK_ROOT(object):
+        def __call__(self):
+            return ("/usr/local/sbin/bitmask-root" if flags.STANDALONE else
+                    "/usr/sbin/bitmask-root")
+
+    class OPENVPN_BIN_PATH(object):
+        def __call__(self):
+            return ("/usr/local/sbin/leap-openvpn" if flags.STANDALONE else
+                    "/usr/sbin/openvpn")
+
+    class POLKIT_PATH(object):
+        def __call__(self):
+            # LinuxPolicyChecker will give us the right path if standalone.
+            return LinuxPolicyChecker.get_polkit_path()
+
+    class RESOLVCONF_BIN_PATH(object):
+        def __call__(self):
+            return ("/usr/local/sbin/leap-resolvconf" if flags.STANDALONE else
+                    "/sbin/resolvconf")
         # this only will work with debian/ubuntu distros.
-        RESOLVCONF_BIN_PATH = "/sbin/resolvconf"
 
-    # XXX openvpn binary TOO
-    OTHER_FILES = (POLKIT_PATH, BITMASK_ROOT, OPENVPN_BIN_PATH,
-                   RESOLVCONF_BIN_PATH)
+    OTHER_FILES = (POLKIT_PATH, BITMASK_ROOT, OPENVPN_BIN_PATH)
 
     @classmethod
     def maybe_pkexec(kls):
@@ -187,7 +195,7 @@ class LinuxVPNLauncher(VPNLauncher):
         command = super(LinuxVPNLauncher, kls).get_vpn_command(
             eipconfig, providerconfig, socket_host, socket_port, openvpn_verb)
 
-        command.insert(0, kls.BITMASK_ROOT)
+        command.insert(0, force_eval(kls.BITMASK_ROOT))
         command.insert(1, "openvpn")
         command.insert(2, "start")
 
@@ -207,35 +215,37 @@ class LinuxVPNLauncher(VPNLauncher):
 
         :rtype: str
         """
+        bin_paths = force_eval(
+            (LinuxVPNLauncher.POLKIT_PATH,
+             LinuxVPNLauncher.OPENVPN_BIN_PATH,
+             LinuxVPNLauncher.BITMASK_ROOT))
+
+        polkit_path, openvpn_bin_path, bitmask_root = bin_paths
+
         # no system config for now
         # sys_config = kls.SYSTEM_CONFIG
         (polkit_file, openvpn_bin_file,
-         bitmask_root_file, resolvconf_bin_file) = map(
+         bitmask_root_file) = map(
             lambda p: os.path.split(p)[-1],
-            (kls.POLKIT_PATH, kls.OPENVPN_BIN_PATH,
-             kls.BITMASK_ROOT, kls.RESOLVCONF_BIN_PATH))
+            bin_paths)
 
         cmd = '#!/bin/sh\n'
         cmd += 'mkdir -p /usr/local/sbin\n'
 
         cmd += 'cp "%s" "%s"\n' % (os.path.join(frompath, polkit_file),
-                                   kls.POLKIT_PATH)
-        cmd += 'chmod 644 "%s"\n' % (kls.POLKIT_PATH, )
+                                   polkit_path)
+        cmd += 'chmod 644 "%s"\n' % (polkit_path, )
 
         cmd += 'cp "%s" "%s"\n' % (os.path.join(frompath, bitmask_root_file),
-                                   kls.BITMASK_ROOT)
-        cmd += 'chmod 744 "%s"\n' % (kls.BITMASK_ROOT, )
+                                   bitmask_root)
+        cmd += 'chmod 744 "%s"\n' % (bitmask_root, )
 
         if flags.STANDALONE:
             cmd += 'cp "%s" "%s"\n' % (
                 os.path.join(frompath, openvpn_bin_file),
-                kls.OPENVPN_BIN_PATH)
-            cmd += 'chmod 744 "%s"\n' % (kls.POLKIT_PATH, )
+                openvpn_bin_path)
+            cmd += 'chmod 744 "%s"\n' % (openvpn_bin_path, )
 
-            cmd += 'cp "%s" "%s"\n' % (
-                os.path.join(frompath, resolvconf_bin_file),
-                kls.RESOLVCONF_BIN_PATH)
-            cmd += 'chmod 744 "%s"\n' % (kls.POLKIT_PATH, )
         return cmd
 
     @classmethod
diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py
index 9629afae64f49c6a85ea3e36d9169208f0675da6..0731bee38538053564f510048ef3d6f9ba4ac8c1 100644
--- a/src/leap/bitmask/services/eip/vpnlauncher.py
+++ b/src/leap/bitmask/services/eip/vpnlauncher.py
@@ -18,6 +18,7 @@
 Platform independant VPN launcher interface.
 """
 import getpass
+import hashlib
 import logging
 import os
 import stat
@@ -30,6 +31,7 @@ from leap.bitmask.config.leapsettings import LeapSettings
 from leap.bitmask.config.providerconfig import ProviderConfig
 from leap.bitmask.platform_init import IS_LINUX
 from leap.bitmask.services.eip.eipconfig import EIPConfig, VPNGatewaySelector
+from leap.bitmask.util import force_eval
 from leap.common.check import leap_assert, leap_assert_type
 
 
@@ -76,7 +78,7 @@ def _has_updown_scripts(path, warn=True):
 
 def _has_other_files(path, warn=True):
     """
-    Checks the existence of other important files.
+    Check the existence of other important files.
 
     :param path: the path to be checked
     :type path: str
@@ -179,12 +181,13 @@ class VPNLauncher(object):
             #raise OpenVPNNotFoundException()
         #openvpn = first(openvpn_possibilities)
         # -----------------------------------------
-        if not os.path.isfile(kls.OPENVPN_BIN_PATH):
+        openvpn_path = force_eval(kls.OPENVPN_BIN_PATH)
+
+        if not os.path.isfile(openvpn_path):
             logger.warning("Could not find openvpn bin in path %s" % (
-                kls.OPENVPN_BIN_PATH))
+                openvpn_path))
             raise OpenVPNNotFoundException()
 
-        openvpn = kls.OPENVPN_BIN_PATH
         args = []
 
         args += [
@@ -248,13 +251,13 @@ class VPNLauncher(object):
             '--ping', '10',
             '--ping-restart', '30']
 
-        command_and_args = [openvpn] + args
+        command_and_args = [openvpn_path] + args
         return command_and_args
 
     @classmethod
     def get_vpn_env(kls):
         """
-        Returns a dictionary with the custom env for the platform.
+        Return a dictionary with the custom env for the platform.
         This is mainly used for setting LD_LIBRARY_PATH to the correct
         path when distributing a standalone client
 
@@ -265,7 +268,7 @@ class VPNLauncher(object):
     @classmethod
     def missing_updown_scripts(kls):
         """
-        Returns what updown scripts are missing.
+        Return what updown scripts are missing.
 
         :rtype: list
         """
@@ -285,7 +288,7 @@ class VPNLauncher(object):
     @classmethod
     def missing_other_files(kls):
         """
-        Returns what other important files are missing during startup.
+        Return what other important files are missing during startup.
         Same as missing_updown_scripts but does not check for exec bit.
 
         :rtype: list
@@ -293,7 +296,57 @@ class VPNLauncher(object):
         leap_assert(kls.OTHER_FILES is not None,
                     "Need to define OTHER_FILES for this particular "
                     "auncher before calling this method")
+        other = force_eval(kls.OTHER_FILES)
         file_exist = partial(_has_other_files, warn=False)
-        zipped = zip(kls.OTHER_FILES, map(file_exist, kls.OTHER_FILES))
-        missing = filter(lambda (path, exists): exists is False, zipped)
-        return [path for path, exists in missing]
+
+        if flags.STANDALONE:
+            try:
+                from leap.bitmask import _binaries
+            except ImportError:
+                raise RuntimeError(
+                    "Could not find binary hash info in this bundle!")
+
+            _, bitmask_root_path, openvpn_bin_path = other
+
+            check_hash = _has_expected_binary_hash
+            openvpn_hash = _binaries.OPENVPN_BIN
+            bitmask_root_hash = _binaries.BITMASK_ROOT
+
+            correct_hash = (
+                True,  # we do not check the polkit file
+                check_hash(bitmask_root_path, bitmask_root_hash),
+                check_hash(openvpn_bin_path, openvpn_hash))
+
+            zipped = zip(other, map(file_exist, other), correct_hash)
+            missing = filter(
+                lambda (path, exists, hash_ok): (
+                    exists is False or hash_ok is False),
+                zipped)
+            return [path for path, exists, hash_ok in missing]
+        else:
+            zipped = zip(other, map(file_exist, other))
+            missing = filter(lambda (path, exists): exists is False, zipped)
+            return [path for path, exists in missing]
+
+
+def _has_expected_binary_hash(path, expected_hash):
+    """
+    Check if the passed path matches the expected hash.
+
+    Used from within the bundle, to know if we have to reinstall the shipped
+    binaries into the system path.
+
+    This path will be /usr/local/sbin for linux.
+
+    :param path: the path to check.
+    :type path: str
+    :param expected_hash: the sha256 hash that we expect
+    :type expected_hash: str
+    :rtype: bool
+    """
+    try:
+        with open(path) as f:
+            file_hash = hashlib.sha256(f.read()).hexdigest()
+        return expected_hash == file_hash
+    except IOError:
+        return False
diff --git a/src/leap/bitmask/services/eip/vpnprocess.py b/src/leap/bitmask/services/eip/vpnprocess.py
index f56d464efd44f15d6566358efe477495b7632089..b54f2925efa5ad85abf9d26782c13143d72bf32e 100644
--- a/src/leap/bitmask/services/eip/vpnprocess.py
+++ b/src/leap/bitmask/services/eip/vpnprocess.py
@@ -43,7 +43,7 @@ from leap.bitmask.services.eip import get_vpn_launcher
 from leap.bitmask.services.eip import linuxvpnlauncher
 from leap.bitmask.services.eip.eipconfig import EIPConfig
 from leap.bitmask.services.eip.udstelnet import UDSTelnet
-from leap.bitmask.util import first
+from leap.bitmask.util import first, force_eval
 from leap.bitmask.platform_init import IS_MAC, IS_LINUX
 from leap.common.check import leap_assert, leap_assert_type
 
@@ -233,7 +233,7 @@ class VPN(object):
         # XXX could check for wrapper existence, check it's root owned etc.
         # XXX could check that the iptables rules are in place.
 
-        BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT
+        BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
         cmd = ["pkexec", BM_ROOT, "firewall", "start"]
         if restart:
             cmd.append("restart")
@@ -246,7 +246,7 @@ class VPN(object):
 
         :rtype: bool
         """
-        BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT
+        BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
         fw_up_cmd = "pkexec {0} firewall isup".format(BM_ROOT)
         fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256
         return fw_is_down()
@@ -255,7 +255,7 @@ class VPN(object):
         """
         Tear the firewall down using the privileged wrapper.
         """
-        BM_ROOT = linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT
+        BM_ROOT = force_eval(linuxvpnlauncher.LinuxVPNLauncher.BITMASK_ROOT)
         exitCode = subprocess.call(["pkexec",
                                     BM_ROOT, "firewall", "stop"])
         return True if exitCode is 0 else False
diff --git a/src/leap/bitmask/services/tx.py b/src/leap/bitmask/services/tx.py
deleted file mode 100644
index adc6fcea06284eb666f93d0c03242d6683aa8ac0..0000000000000000000000000000000000000000
--- a/src/leap/bitmask/services/tx.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-# twisted.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/>.
-"""
-Twisted services launched by the client
-"""
-import logging
-
-from twisted.application.service import Application
-#from twisted.internet.task import LoopingCall
-
-logger = logging.getLogger(__name__)
-
-
-def task():
-    """
-    stub periodic task, mainly for tests.
-    DELETE-ME when there's real meat here :)
-    """
-    from datetime import datetime
-    logger.debug("hi there %s", datetime.now())
-
-
-def leap_services():
-    """
-    Check which twisted services are enabled and
-    register them.
-    """
-    logger.debug('starting leap services')
-    application = Application("Bitmask Local Services")
-    #lc = LoopingCall(task)
-    #lc.start(5)
-    return application
diff --git a/src/leap/bitmask/util/__init__.py b/src/leap/bitmask/util/__init__.py
index c35be99e6b0cb980ab9ce33ddbf95615bb340110..25b86874f40119f06a86ece877f1fb3927f7e748 100644
--- a/src/leap/bitmask/util/__init__.py
+++ b/src/leap/bitmask/util/__init__.py
@@ -110,3 +110,22 @@ def make_address(user, provider):
     :type provider: basestring
     """
     return "%s@%s" % (user, provider)
+
+
+def force_eval(items):
+    """
+    Return a sequence that evaluates any callable in the sequence,
+    instantiating it beforehand if the item is a class, and
+    leaves the non-callable items without change.
+    """
+    def do_eval(thing):
+        if isinstance(thing, type):
+            return thing()()
+        if callable(thing):
+            return thing()
+        return thing
+
+    if isinstance(items, (list, tuple)):
+        return map(do_eval, items)
+    else:
+        return do_eval(items)
diff --git a/src/leap/bitmask/util/leap_argparse.py b/src/leap/bitmask/util/leap_argparse.py
index 84af4e8d9129bbde72f15240e677957161ec54f0..0717aea5a5649a7c113772c98c997e6337438d65 100644
--- a/src/leap/bitmask/util/leap_argparse.py
+++ b/src/leap/bitmask/util/leap_argparse.py
@@ -123,7 +123,13 @@ def build_parser():
     return parser
 
 
-def init_leapc_args():
+def get_options():
+    """
+    Get the command line options used when the app was started.
+
+    :return: the command options
+    :rtype: argparse.Namespace
+    """
     parser = build_parser()
     opts, unknown = parser.parse_known_args()
-    return parser, opts
+    return opts
diff --git a/src/leap/bitmask/util/pastebin.py b/src/leap/bitmask/util/pastebin.py
old mode 100755
new mode 100644
diff --git a/src/leap/bitmask/util/privilege_policies.py b/src/leap/bitmask/util/privilege_policies.py
index 9d1e2c9af5523b1bd64ef7b389a4410a5b5c5144..adc3503f0529bdaf23c94d7e86c608d077b87880 100644
--- a/src/leap/bitmask/util/privilege_policies.py
+++ b/src/leap/bitmask/util/privilege_policies.py
@@ -24,6 +24,8 @@ import platform
 
 from abc import ABCMeta, abstractmethod
 
+from leap.bitmask.config import flags
+
 logger = logging.getLogger(__name__)
 
 
@@ -71,6 +73,8 @@ class LinuxPolicyChecker(PolicyChecker):
     """
     LINUX_POLKIT_FILE = ("/usr/share/polkit-1/actions/"
                          "se.leap.bitmask.policy")
+    LINUX_POLKIT_FILE_BUNDLE = ("/usr/share/polkit-1/actions/"
+                                "se.leap.bitmask.bundle.policy")
 
     @classmethod
     def get_polkit_path(self):
@@ -79,7 +83,8 @@ class LinuxPolicyChecker(PolicyChecker):
 
         :rtype: str
         """
-        return self.LINUX_POLKIT_FILE
+        return (self.LINUX_POLKIT_FILE_BUNDLE if flags.STANDALONE
+                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
@@ -90,4 +95,5 @@ class LinuxPolicyChecker(PolicyChecker):
 
         :rtype: bool
         """
-        return not os.path.isfile(self.LINUX_POLKIT_FILE)
+        path = self.get_polkit_path()
+        return not os.path.isfile(path)