diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/leap/gui/mainwindow.py | 98 | ||||
| -rw-r--r-- | src/leap/gui/ui/mainwindow.ui | 63 | ||||
| -rw-r--r-- | src/leap/services/eip/vpn.py | 29 | 
3 files changed, 142 insertions, 48 deletions
diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py index 50a03fb9..df21a2bb 100644 --- a/src/leap/gui/mainwindow.py +++ b/src/leap/gui/mainwindow.py @@ -56,6 +56,9 @@ class MainWindow(QtGui.QMainWindow):          self.CONNECTED_ICON = QtGui.QPixmap(":/images/conn_connected.png")          self.ERROR_ICON = QtGui.QPixmap(":/images/conn_error.png") +        self.LOGGED_OUT_ICON = QtGui.QPixmap(":/images/leap-gray-big.png") +        self.LOGGED_IN_ICON = QtGui.QPixmap(":/images/leap-color-big.png") +          self.ui = Ui_MainWindow()          self.ui.setupUi(self) @@ -67,6 +70,10 @@ class MainWindow(QtGui.QMainWindow):          self.ui.stackedWidget.setCurrentIndex(self.LOGIN_INDEX) +        self.ui.btnEipStartStop.setEnabled(False) +        self.ui.btnEipStartStop.clicked.connect( +            self._stop_eip) +          # This is loaded only once, there's a bug when doing that more          # than once          self._provider_config = ProviderConfig() @@ -105,11 +112,13 @@ class MainWindow(QtGui.QMainWindow):          self._eip_bootstrapper.download_config.connect(              self._intermediate_stage)          self._eip_bootstrapper.download_client_certificate.connect( -            self._start_eip) +            self._finish_eip_bootstrap)          self._vpn = VPN()          self._vpn.state_changed.connect(self._update_vpn_state)          self._vpn.status_changed.connect(self._update_vpn_status) +        self._vpn.process_finished.connect( +            self._eip_finished)          QtCore.QCoreApplication.instance().connect(              QtCore.QCoreApplication.instance(), @@ -130,6 +139,22 @@ class MainWindow(QtGui.QMainWindow):          self._really_quit = False          self._systray = None +        self._vpn_systray = None + +        self._action_eip_status = QtGui.QAction("Encryption is OFF", self) +        self._action_eip_status.setEnabled(False) +        self._action_eip_stop = QtGui.QAction("Stop", self) +        self._action_eip_stop.triggered.connect( +            self._stop_eip) +        self._action_eip_write = QtGui.QAction( +            QtGui.QIcon(":/images/Arrow-Up-32.png"), +            "0.0 Kb", self) +        self._action_eip_write.setEnabled(False) +        self._action_eip_read = QtGui.QAction( +            QtGui.QIcon(":/images/Arrow-Down-32.png"), +            "0.0 Kb", self) +        self._action_eip_read.setEnabled(False) +          self._action_visible = QtGui.QAction("Hide", self)          self._action_visible.triggered.connect(self._toggle_visible) @@ -179,10 +204,20 @@ class MainWindow(QtGui.QMainWindow):          systrayMenu.addAction(self.ui.action_quit)          self._systray = QtGui.QSystemTrayIcon(self)          self._systray.setContextMenu(systrayMenu) -        self._systray.setIcon(QtGui.QIcon(self.ERROR_ICON)) +        self._systray.setIcon(QtGui.QIcon(self.LOGGED_OUT_ICON))          self._systray.setVisible(True)          self._systray.activated.connect(self._toggle_visible) +        vpn_systrayMenu = QtGui.QMenu(self) +        vpn_systrayMenu.addAction(self._action_eip_status) +        vpn_systrayMenu.addAction(self._action_eip_stop) +        vpn_systrayMenu.addAction(self._action_eip_read) +        vpn_systrayMenu.addAction(self._action_eip_write) +        self._vpn_systray = QtGui.QSystemTrayIcon(self) +        self._vpn_systray.setContextMenu(vpn_systrayMenu) +        self._vpn_systray.setIcon(QtGui.QIcon(self.ERROR_ICON)) +        self._vpn_systray.setVisible(False) +      def _toggle_visible(self):          """          SLOT @@ -455,8 +490,33 @@ class MainWindow(QtGui.QMainWindow):          triggers the eip bootstrapping          """          self.ui.stackedWidget.setCurrentIndex(self.EIP_STATUS_INDEX) +        self._systray.setIcon(self.LOGGED_IN_ICON)          self._download_eip_config() +    def _start_eip(self): +        self._vpn.start(eipconfig=self._eip_config, +                        providerconfig=self._provider_config, +                        socket_host="/home/chiiph/vpnsock", +                        socket_port="unix") +        self._vpn_systray.setVisible(True) +        self.ui.btnEipStartStop.setEnabled(True) +        self.ui.btnEipStartStop.setText("Stop EIP") +        self.ui.btnEipStartStop.clicked.disconnect( +            self._start_eip) +        self.ui.btnEipStartStop.clicked.connect( +            self._stop_eip) + +    def _stop_eip(self): +        self._vpn.set_should_quit() +        self._vpn_systray.setVisible(False) +        self._set_eip_status("EIP has stopped") +        self._set_eip_status_icon("error") +        self.ui.btnEipStartStop.setText("Start EIP") +        self.ui.btnEipStartStop.clicked.disconnect( +            self._stop_eip) +        self.ui.btnEipStartStop.clicked.connect( +            self._start_eip) +      def _download_eip_config(self):          """          Starts the EIP bootstrapping sequence @@ -483,13 +543,16 @@ class MainWindow(QtGui.QMainWindow):          @type status: str          """          selected_pixmap = self.ERROR_ICON +        tray_message = "Encryption is OFF"          if status in ("AUTH", "GET_CONFIG"):              selected_pixmap = self.CONNECTING_ICON          elif status in ("CONNECTED"): +            tray_message = "Encryption is ON"              selected_pixmap = self.CONNECTED_ICON          self.ui.lblVPNStatusIcon.setPixmap(selected_pixmap) -        self._systray.setIcon(QtGui.QIcon(selected_pixmap)) +        self._vpn_systray.setIcon(QtGui.QIcon(selected_pixmap)) +        self._action_eip_status.setText(tray_message)      def _update_vpn_state(self, data):          """ @@ -520,12 +583,16 @@ class MainWindow(QtGui.QMainWindow):          """          upload = float(data[self._vpn.TUNTAP_WRITE_KEY])          upload = upload / 1000.0 -        self.ui.lblUpload.setText("%s Kb" % (upload,)) +        upload_str = "%s Kb" % (upload,) +        self.ui.lblUpload.setText(upload_str) +        self._action_eip_write.setText(upload_str)          download = float(data[self._vpn.TUNTAP_READ_KEY])          download = download / 1000.0 -        self.ui.lblDownload.setText("%s Kb" % (download,)) +        download_str = "%s Kb" % (download,) +        self.ui.lblDownload.setText(download_str) +        self._action_eip_read.setText(download_str) -    def _start_eip(self, data): +    def _finish_eip_bootstrap(self, data):          """          SLOT          TRIGGER: self._eip_bootstrapper.download_client_certificate @@ -542,10 +609,7 @@ class MainWindow(QtGui.QMainWindow):                                                     self._provider_config                                                     .get_domain(),                                                     "eip-service.json")): -            self._vpn.start(eipconfig=self._eip_config, -                            providerconfig=self._provider_config, -                            socket_host="/home/chiiph/vpnsock", -                            socket_port="unix") +                self._start_eip()          # TODO: display a message if the EIP configuration cannot be          # loaded @@ -569,12 +633,14 @@ class MainWindow(QtGui.QMainWindow):          logging out          """          self._set_status(message) +        self._vpn_systray.setIcon(self.LOGGED_OUT_ICON)          self.ui.action_sign_out.setEnabled(False)          self.ui.stackedWidget.setCurrentIndex(self.LOGIN_INDEX)          self.ui.lnPassword.setText("")          self._login_set_enabled(True)          self._set_status("")          self._vpn.set_should_quit() +        self._vpn_systray.setVisible(False)      def _intermediate_stage(self, data):          """ @@ -594,6 +660,18 @@ class MainWindow(QtGui.QMainWindow):              self._login_set_enabled(True)              self._set_status(data[self._provider_bootstrapper.ERROR_KEY]) +    def _eip_finished(self, exitCode): +        """ +        SLOT +        TRIGGERS: +          self._vpn.process_finished + +        Triggered when the EIP/VPN process finishes to set the UI +        accordingly +        """ +        logger.debug("Finished VPN with exitCode %s" % (exitCode,)) +        self._stop_eip() +  if __name__ == "__main__":      import signal      from functools import partial diff --git a/src/leap/gui/ui/mainwindow.ui b/src/leap/gui/ui/mainwindow.ui index a527eaf6..d8a6d37d 100644 --- a/src/leap/gui/ui/mainwindow.ui +++ b/src/leap/gui/ui/mainwindow.ui @@ -171,16 +171,6 @@        </widget>        <widget class="QWidget" name="page_2">         <layout class="QGridLayout" name="gridLayout_3"> -        <item row="1" column="0" colspan="6"> -         <widget class="QLabel" name="lblEIPStatus"> -          <property name="text"> -           <string>Disconnected</string> -          </property> -          <property name="alignment"> -           <set>Qt::AlignCenter</set> -          </property> -         </widget> -        </item>          <item row="0" column="0" colspan="6">           <widget class="QLabel" name="lblVPNStatusIcon">            <property name="text"> @@ -194,20 +184,7 @@            </property>           </widget>          </item> -        <item row="2" column="0"> -         <spacer name="horizontalSpacer_5"> -          <property name="orientation"> -           <enum>Qt::Horizontal</enum> -          </property> -          <property name="sizeHint" stdset="0"> -           <size> -            <width>40</width> -            <height>20</height> -           </size> -          </property> -         </spacer> -        </item> -        <item row="2" column="2"> +        <item row="3" column="2">           <widget class="QLabel" name="lblUpload">            <property name="minimumSize">             <size> @@ -220,7 +197,7 @@            </property>           </widget>          </item> -        <item row="2" column="4"> +        <item row="3" column="4">           <widget class="QLabel" name="lblDownload">            <property name="minimumSize">             <size> @@ -233,7 +210,7 @@            </property>           </widget>          </item> -        <item row="2" column="5"> +        <item row="3" column="5">           <spacer name="horizontalSpacer_6">            <property name="orientation">             <enum>Qt::Horizontal</enum> @@ -246,7 +223,7 @@            </property>           </spacer>          </item> -        <item row="2" column="3"> +        <item row="3" column="3">           <widget class="QLabel" name="label_7">            <property name="text">             <string/> @@ -256,7 +233,7 @@            </property>           </widget>          </item> -        <item row="2" column="1"> +        <item row="3" column="1">           <widget class="QLabel" name="label_5">            <property name="text">             <string/> @@ -266,6 +243,36 @@            </property>           </widget>          </item> +        <item row="3" column="0"> +         <spacer name="horizontalSpacer_5"> +          <property name="orientation"> +           <enum>Qt::Horizontal</enum> +          </property> +          <property name="sizeHint" stdset="0"> +           <size> +            <width>40</width> +            <height>20</height> +           </size> +          </property> +         </spacer> +        </item> +        <item row="1" column="0" colspan="6"> +         <widget class="QLabel" name="lblEIPStatus"> +          <property name="text"> +           <string>Disconnected</string> +          </property> +          <property name="alignment"> +           <set>Qt::AlignCenter</set> +          </property> +         </widget> +        </item> +        <item row="2" column="1" colspan="4"> +         <widget class="QPushButton" name="btnEipStartStop"> +          <property name="text"> +           <string>Start EIP</string> +          </property> +         </widget> +        </item>         </layout>        </widget>       </widget> diff --git a/src/leap/services/eip/vpn.py b/src/leap/services/eip/vpn.py index 88692442..71944f50 100644 --- a/src/leap/services/eip/vpn.py +++ b/src/leap/services/eip/vpn.py @@ -22,7 +22,6 @@ import logging  import sys  from PySide import QtCore, QtGui -from subprocess import Popen, PIPE  from functools import partial  from leap.config.providerconfig import ProviderConfig @@ -46,6 +45,8 @@ class VPN(QtCore.QThread):      state_changed = QtCore.Signal(dict)      status_changed = QtCore.Signal(dict) +    process_finished = QtCore.Signal(int) +      CONNECTION_RETRY_TIME = 1000      POLL_TIME = 100 @@ -69,7 +70,6 @@ class VPN(QtCore.QThread):          self._launcher = get_platform_launcher()          self._subp = None -        self._started = False          self._tn = None          self._host = None @@ -100,15 +100,14 @@ class VPN(QtCore.QThread):              return          try: -            self._disconnect() +            self._send_command("signal SIGTERM") +            self._tn.close()              self._subp.terminate()          except Exception as e:              logger.debug("Could not terminate process, trying command " +                           "signal SIGNINT: %r" % (e,)) -            self._send_command("signal SIGINT") -        self._subp.wait() -        self.wait() -        self._started = False +        finally: +            self._tn = None      def start(self, eipconfig, providerconfig, socket_host, socket_port):          """ @@ -128,7 +127,7 @@ class VPN(QtCore.QThread):          leap_assert_type(eipconfig, EIPConfig)          leap_assert(providerconfig, "We need a provider config")          leap_assert_type(providerconfig, ProviderConfig) -        leap_assert(not self._started, "Starting process more than once!") +        leap_assert(not self.isRunning(), "Starting process more than once!")          logger.debug("Starting VPN...") @@ -140,8 +139,12 @@ class VPN(QtCore.QThread):                                                   socket_host=socket_host,                                                   socket_port=socket_port)          try: -            self._subp = Popen(command, stdout=PIPE, stderr=PIPE, -                               bufsize=1, close_fds=ON_POSIX) +            self._subp = QtCore.QProcess() +            self._subp.finished.connect(self.process_finished) +            self._subp.start(command[:1][0], command[1:]) +            logger.debug("Waiting for started...") +            self._subp.waitForStarted() +            logger.debug("Started!")              self._host = socket_host              self._port = socket_port @@ -296,12 +299,18 @@ class VPN(QtCore.QThread):                  logger.debug("Quitting VPN thread")                  return +            if self._subp and self._subp.state() != QtCore.QProcess.Running: +                QtCore.QThread.msleep(self.CONNECTION_RETRY_TIME) +              if self._tn is None:                  self._connect(self._host, self._port)                  QtCore.QThread.msleep(self.CONNECTION_RETRY_TIME)              else:                  self._parse_state_and_notify(self._send_command("state"))                  self._parse_status_and_notify(self._send_command("status")) +                output_sofar = self._subp.readAllStandardOutput() +                if len(output_sofar) > 0: +                    logger.debug(output_sofar)                  QtCore.QThread.msleep(self.POLL_TIME)  | 
