Display the PSK entry box near the mouse.
[dhcpcd-ui] / src / dhcpcd-qt / dhcpcd-qt.cpp
index 57c278e5cbfd4326ffe6c4b559da12981b148347..f1589c4fdabe93578e7225374bf2db75f0610c7b 100644 (file)
 #include "dhcpcd-ifmenu.h"
 #include "dhcpcd-ssidmenu.h"
 
+#ifdef NOTIFY
+#include <knotification.h>
+#endif
+
 DhcpcdQt::DhcpcdQt()
 {
 
@@ -66,17 +70,21 @@ DhcpcdQt::DhcpcdQt()
                exit(EXIT_FAILURE);
                return;
        }
+       dhcpcd_set_progname(con, "dhcpcd-qt");
        dhcpcd_set_status_callback(con, dhcpcd_status_cb, this);
        dhcpcd_set_if_callback(con, dhcpcd_if_cb, this);
        dhcpcd_wpa_set_scan_callback(con, dhcpcd_wpa_scan_cb, this);
+       dhcpcd_wpa_set_status_callback(con, dhcpcd_wpa_status_cb, this);
        tryOpen();
 }
 
 DhcpcdQt::~DhcpcdQt()
 {
 
-       qDeleteAll(*wis);
-       delete wis;
+       if (ssidMenu) {
+               ssidMenu->setVisible(false);
+               ssidMenu->deleteLater();
+       }
 
        if (con != NULL) {
                dhcpcd_close(con);
@@ -84,11 +92,66 @@ DhcpcdQt::~DhcpcdQt()
        }
 
        free(lastStatus);
+
+       for (auto &wi : *wis)
+               wi->deleteLater();
+       delete wis;
+}
+
+DHCPCD_CONNECTION *DhcpcdQt::getConnection()
+{
+
+       return con;
+}
+
+QList<DhcpcdWi *> *DhcpcdQt::getWis()
+{
+
+       return wis;
+}
+
+const char * DhcpcdQt::signalStrengthIcon(DHCPCD_WI_SCAN *scan)
+{
+
+       if (scan->strength.value > 80)
+               return "network-wireless-connected-100";
+       else if (scan->strength.value > 55)
+               return "network-wireless-connected-75";
+       else if (scan->strength.value > 30)
+               return "network-wireless-connected-50";
+       else if (scan->strength.value > 5)
+               return "network-wireless-connected-25";
+       else
+               return "network-wireless-connected-00";
+}
+
+DHCPCD_WI_SCAN * DhcpcdQt::getStrongestSignal()
+{
+       DHCPCD_WI_SCAN *scan, *scans, *s;
+       DHCPCD_WPA *wpa;
+       DHCPCD_IF *i;
+
+       scan = NULL;
+       for (auto &wi : *wis) {
+               wpa = wi->getWpa();
+               i = dhcpcd_wpa_if(wpa);
+               scans = wi->getScans();
+               for (s = scans; s; s = s->next) {
+                       if (dhcpcd_wi_associated(i, s) &&
+                           (scan == NULL ||
+                           s->strength.value > scan->strength.value))
+                               scan = s;
+               }
+       }
+       return scan;
 }
 
 void DhcpcdQt::animate()
 {
        const char *icon;
+       DHCPCD_WI_SCAN *scan;
+
+       scan = getStrongestSignal();
 
        if (onLine) {
                if (aniCounter++ > 6) {
@@ -98,20 +161,42 @@ void DhcpcdQt::animate()
                }
 
                if (aniCounter % 2 == 0)
-                       icon = "network-idle";
+                       icon = scan ? "network-wireless-connected-00" :
+                           "network-idle";
                else
-                       icon = "network-transmit-receive";
+                       icon = scan ? DhcpcdQt::signalStrengthIcon(scan) :
+                           "network-transmit-receive";
        } else {
-               switch(aniCounter++) {
-               case 0:
-                       icon = "network-transmit";
-                       break;
-               case 1:
-                       icon = "network-receive";
-                       break;
-               default:
-                       icon = "network-idle";
-                       aniCounter = 0;
+               if (scan) {
+                       switch(aniCounter++) {
+                       case 0:
+                               icon = "network-wireless-connected-00";
+                               break;
+                       case 1:
+                               icon = "network-wireless-connected-25";
+                               break;
+                       case 2:
+                               icon = "network-wireless-connected-50";
+                               break;
+                       case 3:
+                               icon = "network-wireless-connected-75";
+                               break;
+                       default:
+                               icon = "network-wireless-connected-100";
+                               aniCounter = 0;
+                       }
+               } else {
+                       switch(aniCounter++) {
+                       case 0:
+                               icon = "network-transmit";
+                               break;
+                       case 1:
+                               icon = "network-receive";
+                               break;
+                       default:
+                               icon = "network-idle";
+                               aniCounter = 0;
+                       }
                }
        }
 
@@ -173,12 +258,24 @@ void DhcpcdQt::statusCallback(const char *status)
        if (strcmp(status, "down") == 0) {
                aniTimer->stop();
                aniCounter = 0;
+               onLine = carrier = false;
                setIcon("status", "network-offline");
+               trayIcon->setToolTip(tr("Not connected to dhcpcd"));
+               /* Close down everything */
                if (notifier) {
-                       delete notifier;
+                       notifier->setEnabled(false);
+                       notifier->deleteLater();
                        notifier = NULL;
                }
-               trayIcon->setToolTip(tr("Not connected to dhcpcd"));
+               if (ssidMenu) {
+                       ssidMenu->deleteLater();
+                       ssidMenu = NULL;
+               }
+               preferencesAction->setEnabled(false);
+               if (preferences) {
+                       preferences->deleteLater();
+                       preferences = NULL;
+               }
        } else {
                bool refresh;
 
@@ -227,14 +324,27 @@ void DhcpcdQt::ifCallback(DHCPCD_IF *i)
                                QSystemTrayIcon::MessageIcon icon =
                                    i->up ? QSystemTrayIcon::Information :
                                    QSystemTrayIcon::Warning;
-                               trayIcon->showMessage(tr("Network Event"),
-                                   msg, icon);
+                               QString t = tr("Network Event");
+                               QString m = msg;
+                               notify(t, m, icon);
                        }
                        free(msg);
                }
        }
 
        updateOnline(false);
+
+       if (i->wireless) {
+               for (auto &wi : *wis) {
+                       DHCPCD_WPA *wpa = wi->getWpa();
+                       if (dhcpcd_wpa_if(wpa) == i) {
+                               DHCPCD_WI_SCAN *scans;
+
+                               scans = dhcpcd_wi_scans(i);
+                               processScans(wi, scans);
+                       }
+               }
+       }
 }
 
 void DhcpcdQt::dhcpcd_if_cb(DHCPCD_IF *i, void *d)
@@ -254,9 +364,36 @@ DhcpcdWi *DhcpcdQt::findWi(DHCPCD_WPA *wpa)
        return NULL;
 }
 
+void DhcpcdQt::processScans(DhcpcdWi *wi, DHCPCD_WI_SCAN *scans)
+{
+       DHCPCD_WI_SCAN *s1, *s2;
+
+       QString title = tr("New Access Point");
+       QString txt;
+       for (s1 = scans; s1; s1 = s1->next) {
+               for (s2 = wi->getScans(); s2; s2 = s2->next) {
+                       if (strcmp(s1->ssid, s2->ssid) == 0)
+                               break;
+               }
+               if (s2 == NULL) {
+                       if (!txt.isEmpty()) {
+                               title = tr("New Access Points");
+                               txt += '\n';
+                       }
+                       txt += s1->ssid;
+               }
+       }
+       if (!txt.isEmpty() &&
+           (ssidMenu == NULL || !ssidMenu->isVisible()))
+               notify(title, txt);
+
+       if (wi->setScans(scans) && ssidMenu && ssidMenu->isVisible())
+               ssidMenu->popup(ssidMenuPos);
+}
+
 void DhcpcdQt::scanCallback(DHCPCD_WPA *wpa)
 {
-       DHCPCD_WI_SCAN *scans, *s1, *s2;
+       DHCPCD_WI_SCAN *scans;
        int fd = dhcpcd_wpa_get_fd(wpa);
        DhcpcdWi *wi;
 
@@ -265,7 +402,7 @@ void DhcpcdQt::scanCallback(DHCPCD_WPA *wpa)
                qCritical("No fd for WPA");
                if (wi) {
                        wis->removeOne(wi);
-                       delete wi;
+                       wi->deleteLater();
                }
                return;
        }
@@ -275,7 +412,7 @@ void DhcpcdQt::scanCallback(DHCPCD_WPA *wpa)
                qCritical("No interface for WPA");
                if (wi) {
                        wis->removeOne(wi);
-                       delete wi;
+                       wi->deleteLater();
                }
                return;
        }
@@ -284,30 +421,21 @@ void DhcpcdQt::scanCallback(DHCPCD_WPA *wpa)
        scans = dhcpcd_wi_scans(i);
        if (wi == NULL) {
                wi = new DhcpcdWi(this, wpa);
-               wis->append(wi);
-       } else {
-               QString title = tr("New Access Point");
-               QString txt;
-               for (s1 = scans; s1; s1 = s1->next) {
-                       for (s2 = wi->getScans(); s2; s2 = s2->next) {
-                               if (strcmp(s1->ssid, s2->ssid) == 0)
-                                       break;
-                       }
-                       if (s2 == NULL) {
-                               if (!txt.isEmpty()) {
-                                       title = tr("New Access Points");
-                                       txt += '\n';
-                               }
-                               txt += s1->ssid;
-                       }
-               }
-               if (!txt.isEmpty() &&
-                   (ssidMenu == NULL || !ssidMenu->isVisible()))
-                       notify(title, txt);
-       }
+               if (wi->open()) {
+                       wis->append(wi);
+                       wi->setScans(scans);
+               } else
+                       wi->deleteLater();
+       } else
+               processScans(wi, scans);
 
-       if (wi->setScans(scans) && ssidMenu->isVisible())
-               ssidMenu->popup(ssidMenuPos);
+       if (!aniTimer->isActive()) {
+               DHCPCD_WI_SCAN *scan;
+
+               scan = getStrongestSignal();
+               if (scan)
+                       setIcon("status", DhcpcdQt::signalStrengthIcon(scan));
+       }
 }
 
 void DhcpcdQt::dhcpcd_wpa_scan_cb(DHCPCD_WPA *wpa, void *d)
@@ -317,14 +445,44 @@ void DhcpcdQt::dhcpcd_wpa_scan_cb(DHCPCD_WPA *wpa, void *d)
        dhcpcdQt->scanCallback(wpa);
 }
 
+void DhcpcdQt::wpaStatusCallback(DHCPCD_WPA *wpa, const char *status)
+{
+       DHCPCD_IF *i;
+
+       i = dhcpcd_wpa_if(wpa);
+       qDebug("%s: WPA status %s", i->ifname, status);
+       if (strcmp(status, "down") == 0) {
+               DhcpcdWi *wi = findWi(wpa);
+               if (wi) {
+                       wis->removeOne(wi);
+                       wi->deleteLater();
+               }
+       }
+}
+
+void DhcpcdQt::dhcpcd_wpa_status_cb(DHCPCD_WPA *wpa, const char *status,
+    void *d)
+{
+       DhcpcdQt *dhcpcdQt = (DhcpcdQt *)d;
+
+       dhcpcdQt->wpaStatusCallback(wpa, status);
+}
+
 void DhcpcdQt::tryOpen() {
-       int fd = dhcpcd_open(con);
+       int fd = dhcpcd_open(con, true);
        static int last_error;
 
        if (fd == -1) {
+               if (errno == EACCES || errno == EPERM) {
+                       if ((fd = dhcpcd_open(con, false)) != -1)
+                               goto unprived;
+               }
                if (errno != last_error) {
                        last_error = errno;
-                       qCritical("dhcpcd_open: %s", strerror(errno));
+                       const char *errt = strerror(errno);
+                       qCritical("dhcpcd_open: %s", errt);
+                       trayIcon->setToolTip(
+                           tr("Error connecting to dhcpcd: %1").arg(errt));
                }
                if (retryOpenTimer == NULL) {
                        retryOpenTimer = new QTimer(this);
@@ -335,37 +493,47 @@ void DhcpcdQt::tryOpen() {
                return;
        }
 
+unprived:
        /* Start listening to WPA events */
        dhcpcd_wpa_start(con);
 
        if (retryOpenTimer) {
-               delete retryOpenTimer;
+               retryOpenTimer->stop();
+               retryOpenTimer->deleteLater();
                retryOpenTimer = NULL;
        }
 
        notifier = new QSocketNotifier(fd, QSocketNotifier::Read);
        connect(notifier, SIGNAL(activated(int)), this, SLOT(dispatch()));
-}
 
-void DhcpcdQt::dispatch() {
+       preferencesAction->setEnabled(dhcpcd_privileged(con));
+}
 
-       if (dhcpcd_get_fd(con) == -1) {
-               qWarning("dhcpcd connection lost");
-               return;
-       }
+void DhcpcdQt::dispatch()
+{
 
        dhcpcd_dispatch(con);
 }
 
 void DhcpcdQt::notify(QString &title, QString &msg,
-    QSystemTrayIcon::MessageIcon icon)
+#ifdef NOTIFY
+    QSystemTrayIcon::MessageIcon
+#else
+    QSystemTrayIcon::MessageIcon icon
+#endif
+    )
 {
 
-       qDebug("%s", qPrintable(msg));
-       trayIcon->showMessage(title, msg, icon);
+#ifdef NOTIFY
+       KNotification *n = new KNotification("event", this);
+       n->setTitle(title);
+       n->setText(msg);
+       n->sendEvent();
+#else
+       //trayIcon->showMessage(title, msg, icon);
+#endif
 }
 
-
 void DhcpcdQt::closeEvent(QCloseEvent *event)
 {
 
@@ -383,6 +551,7 @@ QIcon DhcpcdQt::getIcon(QString category, QString name)
                icon = QIcon::fromTheme(name);
        else
                icon = QIcon(ICONDIR "/hicolor/scalable/" + category + "/" + name + ".svg");
+
        return icon;
 }
 
@@ -399,11 +568,18 @@ QIcon DhcpcdQt::icon()
        return getIcon("status", "network-transmit-receive");
 }
 
+void DhcpcdQt::menuDeleted(QMenu *menu)
+{
+
+       if (ssidMenu == menu)
+               ssidMenu = NULL;
+}
+
 void DhcpcdQt::createSsidMenu()
 {
 
        if (ssidMenu) {
-               delete ssidMenu;
+               ssidMenu->deleteLater();
                ssidMenu = NULL;
        }
        if (wis->size() == 0)
@@ -461,6 +637,7 @@ void DhcpcdQt::createActions()
 
        preferencesAction = new QAction(tr("&Preferences"), this);
        preferencesAction->setIcon(QIcon::fromTheme("preferences-system-network"));
+       preferencesAction->setEnabled(false);
        connect(preferencesAction, SIGNAL(triggered()),
            this, SLOT(showPreferences()));