wpa_gui: More informative tray icon tool tip message
[mech_eap.git] / wpa_supplicant / wpa_gui-qt4 / wpagui.cpp
index cd700a1..09e547f 100644 (file)
@@ -1,30 +1,25 @@
 /*
  * wpa_gui - WpaGui class
- * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
-#ifdef __MINGW32__
-/* Need to get getopt() */
-#include <unistd.h>
-#endif
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <windows.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
 
 #include <cstdio>
+#include <unistd.h>
 #include <QMessageBox>
 #include <QCloseEvent>
 #include <QImageReader>
+#include <QSettings>
 
 #include "wpagui.h"
 #include "dirent.h"
-#include "wpa_ctrl.h"
+#include "common/wpa_ctrl.h"
 #include "userdatarequest.h"
 #include "networkconfig.h"
 
@@ -37,17 +32,51 @@ static int wpagui_printf(const char *, ...)
 }
 #endif
 
-WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
-       : QMainWindow(parent)
+WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags)
+       : QMainWindow(parent), app(_app)
 {
        setupUi(this);
+       this->setWindowFlags(Qt::Dialog);
+
+#ifdef CONFIG_NATIVE_WINDOWS
+       fileStopServiceAction = new QAction(this);
+       fileStopServiceAction->setObjectName("Stop Service");
+       fileStopServiceAction->setIconText(tr("Stop Service"));
+       fileMenu->insertAction(actionWPS, fileStopServiceAction);
+
+       fileStartServiceAction = new QAction(this);
+       fileStartServiceAction->setObjectName("Start Service");
+       fileStartServiceAction->setIconText(tr("Start Service"));
+       fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction);
+
+       connect(fileStartServiceAction, SIGNAL(triggered()), this,
+               SLOT(startService()));
+       connect(fileStopServiceAction, SIGNAL(triggered()), this,
+               SLOT(stopService()));
+
+       addInterfaceAction = new QAction(this);
+       addInterfaceAction->setIconText(tr("Add Interface"));
+       fileMenu->insertAction(fileStartServiceAction, addInterfaceAction);
+
+       connect(addInterfaceAction, SIGNAL(triggered()), this,
+               SLOT(addInterface()));
+#endif /* CONFIG_NATIVE_WINDOWS */
 
        (void) statusBar();
 
+       /*
+        * Disable WPS tab by default; it will be enabled if wpa_supplicant is
+        * built with WPS support.
+        */
+       wpsTab->setEnabled(false);
+       wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false);
+
        connect(fileEventHistoryAction, SIGNAL(triggered()), this,
                SLOT(eventHistory()));
        connect(fileSaveConfigAction, SIGNAL(triggered()), this,
                SLOT(saveConfig()));
+       connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog()));
+       connect(actionPeers, SIGNAL(triggered()), this, SLOT(peersDialog()));
        connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
        connect(networkAddAction, SIGNAL(triggered()), this,
                SLOT(addNetwork()));
@@ -86,9 +115,18 @@ WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
        connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan()));
        connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
                this, SLOT(editListedNetwork()));
+       connect(wpaguiTab, SIGNAL(currentChanged(int)), this,
+               SLOT(tabChanged(int)));
+       connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc()));
+       connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin()));
+       connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this,
+               SLOT(wpsApPinChanged(const QString &)));
+       connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin()));
 
        eh = NULL;
        scanres = NULL;
+       peers = NULL;
+       add_iface = NULL;
        udr = NULL;
        tray_icon = NULL;
        startInTray = false;
@@ -100,12 +138,24 @@ WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
 
        parse_argv();
 
+#ifndef QT_NO_SESSIONMANAGER
+       if (app->isSessionRestored()) {
+               QSettings settings("wpa_supplicant", "wpa_gui");
+               settings.beginGroup("state");
+               if (app->sessionId().compare(settings.value("session_id").
+                                            toString()) == 0)
+                       startInTray = settings.value("in_tray").toBool();
+               settings.endGroup();
+       }
+#endif
+
        if (QSystemTrayIcon::isSystemTrayAvailable())
                createTrayIcon(startInTray);
        else
                show();
 
-       textStatus->setText("connecting to wpa_supplicant");
+       connectedToService = false;
+       textStatus->setText(tr("connecting to wpa_supplicant"));
        timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), SLOT(ping()));
        timer->setSingleShot(FALSE);
@@ -148,6 +198,18 @@ WpaGui::~WpaGui()
                scanres = NULL;
        }
 
+       if (peers) {
+               peers->close();
+               delete peers;
+               peers = NULL;
+       }
+
+       if (add_iface) {
+               add_iface->close();
+               delete add_iface;
+               add_iface = NULL;
+       }
+
        if (udr) {
                udr->close();
                delete udr;
@@ -250,6 +312,7 @@ int WpaGui::openCtrlConnection(const char *ifname)
                        ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
                                               &len, NULL);
                        if (ret >= 0) {
+                               connectedToService = true;
                                buf[len] = '\0';
                                pos = strchr(buf, '\n');
                                if (pos)
@@ -261,8 +324,23 @@ int WpaGui::openCtrlConnection(const char *ifname)
 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
        }
 
-       if (ctrl_iface == NULL)
+       if (ctrl_iface == NULL) {
+#ifdef CONFIG_NATIVE_WINDOWS
+               static bool first = true;
+               if (first && !serviceRunning()) {
+                       first = false;
+                       if (QMessageBox::warning(
+                                   this, qAppName(),
+                                   tr("wpa_supplicant service is not "
+                                      "running.\n"
+                                      "Do you want to start it?"),
+                                   QMessageBox::Yes | QMessageBox::No) ==
+                           QMessageBox::Yes)
+                               startService();
+               }
+#endif /* CONFIG_NATIVE_WINDOWS */
                return -1;
+       }
 
 #ifdef CONFIG_CTRL_IFACE_UNIX
        flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
@@ -340,15 +418,20 @@ int WpaGui::openCtrlConnection(const char *ifname)
                }
        }
 
-       return 0;
-}
+       len = sizeof(buf) - 1;
+       if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len,
+                            NULL) >= 0) {
+               buf[len] = '\0';
 
+               QString res(buf);
+               QStringList types = res.split(QChar(' '));
+               bool wps = types.contains("WSC");
+               actionWPS->setEnabled(wps);
+               wpsTab->setEnabled(wps);
+               wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps);
+       }
 
-static void wpa_gui_msg_cb(char *msg, size_t)
-{
-       /* This should not happen anymore since two control connections are
-        * used. */
-       printf("missed message: %s\n", msg);
+       return 0;
 }
 
 
@@ -358,8 +441,7 @@ int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
 
        if (ctrl_conn == NULL)
                return -3;
-       ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
-                              wpa_gui_msg_cb);
+       ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL);
        if (ret == -2)
                printf("'%s' command timed out.\n", cmd);
        else if (ret < 0)
@@ -369,6 +451,31 @@ int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
 }
 
 
+QString WpaGui::wpaStateTranslate(char *state)
+{
+       if (!strcmp(state, "DISCONNECTED"))
+               return tr("Disconnected");
+       else if (!strcmp(state, "INACTIVE"))
+               return tr("Inactive");
+       else if (!strcmp(state, "SCANNING"))
+               return tr("Scanning");
+       else if (!strcmp(state, "AUTHENTICATING"))
+               return tr("Authenticating");
+       else if (!strcmp(state, "ASSOCIATING"))
+               return tr("Associating");
+       else if (!strcmp(state, "ASSOCIATED"))
+               return tr("Associated");
+       else if (!strcmp(state, "4WAY_HANDSHAKE"))
+               return tr("4-Way Handshake");
+       else if (!strcmp(state, "GROUP_HANDSHAKE"))
+               return tr("Group Handshake");
+       else if (!strcmp(state, "COMPLETED"))
+               return tr("Completed");
+       else
+               return tr("Unknown");
+}
+
+
 void WpaGui::updateStatus()
 {
        char buf[2048], *start, *end, *pos;
@@ -378,13 +485,29 @@ void WpaGui::updateStatus()
 
        len = sizeof(buf) - 1;
        if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
-               textStatus->setText("Could not get status from "
-                                   "wpa_supplicant");
+               textStatus->setText(tr("Could not get status from "
+                                      "wpa_supplicant"));
                textAuthentication->clear();
                textEncryption->clear();
                textSsid->clear();
                textBssid->clear();
                textIpAddress->clear();
+               updateTrayToolTip(tr("no status information"));
+
+#ifdef CONFIG_NATIVE_WINDOWS
+               static bool first = true;
+               if (first && connectedToService &&
+                   (ctrl_iface == NULL || *ctrl_iface == '\0')) {
+                       first = false;
+                       if (QMessageBox::information(
+                                   this, qAppName(),
+                                   tr("No network interfaces in use.\n"
+                                      "Would you like to add one?"),
+                                   QMessageBox::Yes | QMessageBox::No) ==
+                           QMessageBox::Yes)
+                               addInterface();
+               }
+#endif /* CONFIG_NATIVE_WINDOWS */
                return;
        }
 
@@ -394,6 +517,7 @@ void WpaGui::updateStatus()
        bool bssid_updated = false, ipaddr_updated = false;
        bool status_updated = false;
        char *pairwise_cipher = NULL, *group_cipher = NULL;
+       char *mode = NULL;
 
        start = buf;
        while (*start) {
@@ -416,12 +540,13 @@ void WpaGui::updateStatus()
                        } else if (strcmp(start, "ssid") == 0) {
                                ssid_updated = true;
                                textSsid->setText(pos);
+                               updateTrayToolTip(pos + tr(" (associated)"));
                        } else if (strcmp(start, "ip_address") == 0) {
                                ipaddr_updated = true;
                                textIpAddress->setText(pos);
                        } else if (strcmp(start, "wpa_state") == 0) {
                                status_updated = true;
-                               textStatus->setText(pos);
+                               textStatus->setText(wpaStateTranslate(pos));
                        } else if (strcmp(start, "key_mgmt") == 0) {
                                auth_updated = true;
                                textAuthentication->setText(pos);
@@ -430,6 +555,8 @@ void WpaGui::updateStatus()
                                pairwise_cipher = pos;
                        } else if (strcmp(start, "group_cipher") == 0) {
                                group_cipher = pos;
+                       } else if (strcmp(start, "mode") == 0) {
+                               mode = pos;
                        }
                }
 
@@ -437,6 +564,8 @@ void WpaGui::updateStatus()
                        break;
                start = end + 1;
        }
+       if (status_updated && mode)
+               textStatus->setText(textStatus->text() + " (" + mode + ")");
 
        if (pairwise_cipher || group_cipher) {
                QString encr;
@@ -459,8 +588,10 @@ void WpaGui::updateStatus()
                textStatus->clear();
        if (!auth_updated)
                textAuthentication->clear();
-       if (!ssid_updated)
+       if (!ssid_updated) {
                textSsid->clear();
+               updateTrayToolTip(tr("(not-associated)"));
+       }
        if (!bssid_updated)
                textBssid->clear();
        if (!ipaddr_updated)
@@ -523,6 +654,13 @@ void WpaGui::updateNetworks()
                        break;
                *flags++ = '\0';
 
+               if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) {
+                       if (last)
+                               break;
+                       start = end + 1;
+                       continue;
+               }
+
                QString network(id);
                network.append(": ");
                network.append(ssid);
@@ -543,7 +681,7 @@ void WpaGui::updateNetworks()
        }
 
        if (networkSelect->count() > 1)
-               networkSelect->addItem("Select any network");
+               networkSelect->addItem(tr("Select any network"));
 
        if (!current && first_active >= 0)
                networkSelect->setCurrentIndex(first_active);
@@ -576,17 +714,13 @@ void WpaGui::helpContents()
 void WpaGui::helpAbout()
 {
        QMessageBox::about(this, "wpa_gui for wpa_supplicant",
-                          "Copyright (c) 2003-2008,\n"
+                          "Copyright (c) 2003-2013,\n"
                           "Jouni Malinen <j@w1.fi>\n"
                           "and contributors.\n"
                           "\n"
-                          "This program is free software. You can\n"
-                          "distribute it and/or modify it under the terms "
-                          "of\n"
-                          "the GNU General Public License version 2.\n"
-                          "\n"
-                          "Alternatively, this software may be distributed\n"
-                          "under the terms of the BSD license.\n"
+                          "This software may be distributed under\n"
+                          "the terms of the BSD license.\n"
+                          "See README for more details.\n"
                           "\n"
                           "This product includes software developed\n"
                           "by the OpenSSL Project for use in the\n"
@@ -599,6 +733,7 @@ void WpaGui::disconnect()
        char reply[10];
        size_t reply_len = sizeof(reply);
        ctrlRequest("DISCONNECT", reply, &reply_len);
+       stopWpsRun(false);
 }
 
 
@@ -679,6 +814,14 @@ void WpaGui::ping()
                updateStatus();
                updateNetworks();
        }
+
+#ifndef CONFIG_CTRL_IFACE_NAMED_PIPE
+       /* Use less frequent pings and status updates when the main window is
+        * hidden (running in taskbar). */
+       int interval = isHidden() ? 5000 : 1000;
+       if (timer->interval() != interval)
+               timer->setInterval(interval);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
 }
 
 
@@ -707,6 +850,8 @@ void WpaGui::processMsg(char *msg)
        WpaMsg wm(pos, priority);
        if (eh)
                eh->addEvent(wm);
+       if (peers)
+               peers->event_notify(wm);
        msgs.append(wm);
        while (msgs.count() > 100)
                msgs.pop_front();
@@ -733,11 +878,54 @@ void WpaGui::processMsg(char *msg)
                scanres->updateResults();
        else if (str_match(pos, WPA_EVENT_DISCONNECTED))
                showTrayMessage(QSystemTrayIcon::Information, 3,
-                               "Disconnected from network.");
+                               tr("Disconnected from network."));
        else if (str_match(pos, WPA_EVENT_CONNECTED)) {
                showTrayMessage(QSystemTrayIcon::Information, 3,
-                               "Connection to network established.");
+                               tr("Connection to network established."));
                QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus()));
+               stopWpsRun(true);
+       } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) {
+               wpsStatusText->setText(tr("WPS AP in active PBC mode found"));
+               if (textStatus->text() == "INACTIVE" ||
+                   textStatus->text() == "DISCONNECTED")
+                       wpaguiTab->setCurrentWidget(wpsTab);
+               wpsInstructions->setText(tr("Press the PBC button on the "
+                                           "screen to start registration"));
+       } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) {
+               wpsStatusText->setText(tr("WPS AP with recently selected "
+                                         "registrar"));
+               if (textStatus->text() == "INACTIVE" ||
+                   textStatus->text() == "DISCONNECTED")
+                       wpaguiTab->setCurrentWidget(wpsTab);
+       } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) {
+               showTrayMessage(QSystemTrayIcon::Information, 3,
+                               "Wi-Fi Protected Setup (WPS) AP\n"
+                               "indicating this client is authorized.");
+               wpsStatusText->setText("WPS AP indicating this client is "
+                                      "authorized");
+               if (textStatus->text() == "INACTIVE" ||
+                   textStatus->text() == "DISCONNECTED")
+                       wpaguiTab->setCurrentWidget(wpsTab);
+       } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
+               wpsStatusText->setText(tr("WPS AP detected"));
+       } else if (str_match(pos, WPS_EVENT_OVERLAP)) {
+               wpsStatusText->setText(tr("PBC mode overlap detected"));
+               wpsInstructions->setText(tr("More than one AP is currently in "
+                                           "active WPS PBC mode. Wait couple "
+                                           "of minutes and try again"));
+               wpaguiTab->setCurrentWidget(wpsTab);
+       } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) {
+               wpsStatusText->setText(tr("Network configuration received"));
+               wpaguiTab->setCurrentWidget(wpsTab);
+       } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) {
+               if (strstr(pos, "(WSC)"))
+                       wpsStatusText->setText(tr("Registration started"));
+       } else if (str_match(pos, WPS_EVENT_M2D)) {
+               wpsStatusText->setText(tr("Registrar does not yet know PIN"));
+       } else if (str_match(pos, WPS_EVENT_FAIL)) {
+               wpsStatusText->setText(tr("Registration failed"));
+       } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+               wpsStatusText->setText(tr("Registration succeeded"));
        }
 }
 
@@ -790,20 +978,14 @@ void WpaGui::selectNetwork( const QString &sel )
        char reply[10];
        size_t reply_len = sizeof(reply);
 
-       if (cmd.startsWith("Select any")) {
+       if (cmd.contains(QRegExp("^\\d+:")))
+               cmd.truncate(cmd.indexOf(':'));
+       else
                cmd = "any";
-       } else {
-               int pos = cmd.indexOf(':');
-               if (pos < 0) {
-                       printf("Invalid selectNetwork '%s'\n",
-                              cmd.toAscii().constData());
-                       return;
-               }
-               cmd.truncate(pos);
-       }
        cmd.prepend("SELECT_NETWORK ");
        ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
        triggerUpdate();
+       stopWpsRun(false);
 }
 
 
@@ -813,14 +995,12 @@ void WpaGui::enableNetwork(const QString &sel)
        char reply[10];
        size_t reply_len = sizeof(reply);
 
-       if (!cmd.startsWith("all")) {
-               int pos = cmd.indexOf(':');
-               if (pos < 0) {
-                       printf("Invalid enableNetwork '%s'\n",
-                              cmd.toAscii().constData());
-                       return;
-               }
-               cmd.truncate(pos);
+       if (cmd.contains(QRegExp("^\\d+:")))
+               cmd.truncate(cmd.indexOf(':'));
+       else if (!cmd.startsWith("all")) {
+               printf("Invalid editNetwork '%s'\n",
+                      cmd.toAscii().constData());
+               return;
        }
        cmd.prepend("ENABLE_NETWORK ");
        ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
@@ -834,14 +1014,12 @@ void WpaGui::disableNetwork(const QString &sel)
        char reply[10];
        size_t reply_len = sizeof(reply);
 
-       if (!cmd.startsWith("all")) {
-               int pos = cmd.indexOf(':');
-               if (pos < 0) {
-                       printf("Invalid disableNetwork '%s'\n",
-                              cmd.toAscii().constData());
-                       return;
-               }
-               cmd.truncate(pos);
+       if (cmd.contains(QRegExp("^\\d+:")))
+               cmd.truncate(cmd.indexOf(':'));
+       else if (!cmd.startsWith("all")) {
+               printf("Invalid editNetwork '%s'\n",
+                      cmd.toAscii().constData());
+               return;
        }
        cmd.prepend("DISABLE_NETWORK ");
        ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
@@ -854,14 +1032,8 @@ void WpaGui::editNetwork(const QString &sel)
        QString cmd(sel);
        int id = -1;
 
-       if (!cmd.startsWith("Select any")) {
-               int pos = sel.indexOf(':');
-               if (pos < 0) {
-                       printf("Invalid editNetwork '%s'\n",
-                              cmd.toAscii().constData());
-                       return;
-               }
-               cmd.truncate(pos);
+       if (cmd.contains(QRegExp("^\\d+:"))) {
+               cmd.truncate(cmd.indexOf(':'));
                id = cmd.toInt();
        }
 
@@ -883,8 +1055,9 @@ void WpaGui::editNetwork(const QString &sel)
 void WpaGui::editSelectedNetwork()
 {
        if (networkSelect->count() < 1) {
-               QMessageBox::information(this, "No Networks",
-                                        "There are no networks to edit.\n");
+               QMessageBox::information(
+                       this, tr("No Networks"),
+                       tr("There are no networks to edit.\n"));
                return;
        }
        QString sel(networkSelect->currentText());
@@ -895,9 +1068,9 @@ void WpaGui::editSelectedNetwork()
 void WpaGui::editListedNetwork()
 {
        if (networkList->currentRow() < 0) {
-               QMessageBox::information(this, "Select A Network",
-                                        "Select a network from the list to"
-                                        " edit it.\n");
+               QMessageBox::information(this, tr("Select A Network"),
+                                        tr("Select a network from the list to"
+                                           " edit it.\n"));
                return;
        }
        QString sel(networkList->currentItem()->text());
@@ -931,17 +1104,12 @@ void WpaGui::removeNetwork(const QString &sel)
        char reply[10];
        size_t reply_len = sizeof(reply);
 
-       if (cmd.startsWith("Select any"))
+       if (cmd.contains(QRegExp("^\\d+:")))
+               cmd.truncate(cmd.indexOf(':'));
+       else if (!cmd.startsWith("all")) {
+               printf("Invalid editNetwork '%s'\n",
+                      cmd.toAscii().constData());
                return;
-
-       if (!cmd.startsWith("all")) {
-               int pos = cmd.indexOf(':');
-               if (pos < 0) {
-                       printf("Invalid removeNetwork '%s'\n",
-                              cmd.toAscii().constData());
-                       return;
-               }
-               cmd.truncate(pos);
        }
        cmd.prepend("REMOVE_NETWORK ");
        ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
@@ -952,8 +1120,9 @@ void WpaGui::removeNetwork(const QString &sel)
 void WpaGui::removeSelectedNetwork()
 {
        if (networkSelect->count() < 1) {
-               QMessageBox::information(this, "No Networks",
-                                        "There are no networks to remove.\n");
+               QMessageBox::information(this, tr("No Networks"),
+                                        tr("There are no networks to remove."
+                                           "\n"));
                return;
        }
        QString sel(networkSelect->currentText());
@@ -964,9 +1133,9 @@ void WpaGui::removeSelectedNetwork()
 void WpaGui::removeListedNetwork()
 {
        if (networkList->currentRow() < 0) {
-               QMessageBox::information(this, "Select A Network",
-                                        "Select a network from the list to"
-                                        " remove it.\n");
+               QMessageBox::information(this, tr("Select A Network"),
+                                        tr("Select a network from the list "
+                                           "to remove it.\n"));
                return;
        }
        QString sel(networkList->currentItem()->text());
@@ -1076,16 +1245,18 @@ void WpaGui::saveConfig()
        buf[len] = '\0';
 
        if (str_match(buf, "FAIL"))
-               QMessageBox::warning(this, "Failed to save configuration",
-                                    "The configuration could not be saved.\n"
-                                    "\n"
-                                    "The update_config=1 configuration option\n"
-                                    "must be used for configuration saving to\n"
-                                    "be permitted.\n");
+               QMessageBox::warning(
+                       this, tr("Failed to save configuration"),
+                       tr("The configuration could not be saved.\n"
+                          "\n"
+                          "The update_config=1 configuration option\n"
+                          "must be used for configuration saving to\n"
+                          "be permitted.\n"));
        else
-               QMessageBox::information(this, "Saved configuration",
-                                        "The current configuration was saved."
-                                        "\n");
+               QMessageBox::information(
+                       this, tr("Saved configuration"),
+                       tr("The current configuration was saved."
+                          "\n"));
 }
 
 
@@ -1104,7 +1275,6 @@ void WpaGui::createTrayIcon(bool trayOnly)
        QApplication::setQuitOnLastWindowClosed(false);
 
        tray_icon = new QSystemTrayIcon(this);
-       tray_icon->setToolTip(qAppName() + " - wpa_supplicant user interface");
        if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
                tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
        else
@@ -1118,8 +1288,8 @@ void WpaGui::createTrayIcon(bool trayOnly)
 
        tray_menu = new QMenu(this);
 
-       disconnectAction = new QAction("&Disconnect", this);
-       reconnectAction = new QAction("Re&connect", this);
+       disconnectAction = new QAction(tr("&Disconnect"), this);
+       reconnectAction = new QAction(tr("Re&connect"), this);
        connect(disconnectAction, SIGNAL(triggered()), this,
                SLOT(disconnect()));
        connect(reconnectAction, SIGNAL(triggered()), this,
@@ -1128,9 +1298,9 @@ void WpaGui::createTrayIcon(bool trayOnly)
        tray_menu->addAction(reconnectAction);
        tray_menu->addSeparator();
 
-       eventAction = new QAction("&Event History", this);
-       scanAction = new QAction("Scan &Results", this);
-       statAction = new QAction("S&tatus", this);
+       eventAction = new QAction(tr("&Event History"), this);
+       scanAction = new QAction(tr("Scan &Results"), this);
+       statAction = new QAction(tr("S&tatus"), this);
        connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
        connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
        connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
@@ -1139,9 +1309,9 @@ void WpaGui::createTrayIcon(bool trayOnly)
        tray_menu->addAction(statAction);
        tray_menu->addSeparator();
 
-       showAction = new QAction("&Show Window", this);
-       hideAction = new QAction("&Hide Window", this);
-       quitAction = new QAction("&Quit", this);
+       showAction = new QAction(tr("&Show Window"), this);
+       hideAction = new QAction(tr("&Hide Window"), this);
+       quitAction = new QAction(tr("&Quit"), this);
        connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
        connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
        connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
@@ -1156,6 +1326,7 @@ void WpaGui::createTrayIcon(bool trayOnly)
 
        if (!trayOnly)
                show();
+       inTray = trayOnly;
 }
 
 
@@ -1179,10 +1350,13 @@ void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
         * custom closeEvent handler take care of children */
        case QSystemTrayIcon::Trigger:
                ackTrayIcon = true;
-               if (isVisible())
+               if (isVisible()) {
                        close();
-               else
+                       inTray = true;
+               } else {
                        show();
+                       inTray = false;
+               }
                break;
        case QSystemTrayIcon::MiddleClick:
                showTrayStatus();
@@ -1237,6 +1411,13 @@ void WpaGui::showTrayStatus()
 }
 
 
+void WpaGui::updateTrayToolTip(const QString &msg)
+{
+       if (tray_icon)
+               tray_icon->setToolTip(msg);
+}
+
+
 void WpaGui::closeEvent(QCloseEvent *event)
 {
        if (eh) {
@@ -1251,6 +1432,12 @@ void WpaGui::closeEvent(QCloseEvent *event)
                scanres = NULL;
        }
 
+       if (peers) {
+               peers->close();
+               delete peers;
+               peers = NULL;
+       }
+
        if (udr) {
                udr->close();
                delete udr;
@@ -1262,16 +1449,297 @@ void WpaGui::closeEvent(QCloseEvent *event)
                if (QSystemTrayIcon::supportsMessages()) {
                        hide();
                        showTrayMessage(QSystemTrayIcon::Information, 3,
-                                       qAppName() + " will keep running in "
-                                       "the system tray.");
+                                       qAppName() +
+                                       tr(" will keep running in "
+                                          "the system tray."));
                } else {
-                       QMessageBox::information(this, qAppName() + " systray",
-                                                "The program will keep "
-                                                "running in the system "
-                                                "tray.");
+                       QMessageBox::information(this, qAppName() +
+                                                tr(" systray"),
+                                                tr("The program will keep "
+                                                   "running in the system "
+                                                   "tray."));
                }
                ackTrayIcon = true;
        }
 
        event->accept();
 }
+
+
+void WpaGui::wpsDialog()
+{
+       wpaguiTab->setCurrentWidget(wpsTab);
+}
+
+
+void WpaGui::peersDialog()
+{
+       if (peers) {
+               peers->close();
+               delete peers;
+       }
+
+       peers = new Peers();
+       if (peers == NULL)
+               return;
+       peers->setWpaGui(this);
+       peers->show();
+       peers->exec();
+}
+
+
+void WpaGui::tabChanged(int index)
+{
+       if (index != 2)
+               return;
+
+       if (wpsRunning)
+               return;
+
+       wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
+       if (bssFromScan.isEmpty())
+               wpsApPinButton->setEnabled(false);
+}
+
+
+void WpaGui::wpsPbc()
+{
+       char reply[20];
+       size_t reply_len = sizeof(reply);
+
+       if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
+               return;
+
+       wpsPinEdit->setEnabled(false);
+       if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) {
+               wpsInstructions->setText(tr("Press the push button on the AP to "
+                                        "start the PBC mode."));
+       } else {
+               wpsInstructions->setText(tr("If you have not yet done so, press "
+                                        "the push button on the AP to start "
+                                        "the PBC mode."));
+       }
+       wpsStatusText->setText(tr("Waiting for Registrar"));
+       wpsRunning = true;
+}
+
+
+void WpaGui::wpsGeneratePin()
+{
+       char reply[20];
+       size_t reply_len = sizeof(reply) - 1;
+
+       if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
+               return;
+
+       reply[reply_len] = '\0';
+
+       wpsPinEdit->setText(reply);
+       wpsPinEdit->setEnabled(true);
+       wpsInstructions->setText(tr("Enter the generated PIN into the Registrar "
+                                "(either the internal one in the AP or an "
+                                "external one)."));
+       wpsStatusText->setText(tr("Waiting for Registrar"));
+       wpsRunning = true;
+}
+
+
+void WpaGui::setBssFromScan(const QString &bssid)
+{
+       bssFromScan = bssid;
+       wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
+       wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
+       wpsStatusText->setText(tr("WPS AP selected from scan results"));
+       wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., "
+                                "from a label in the device, enter the eight "
+                                "digit AP PIN and click Use AP PIN button."));
+}
+
+
+void WpaGui::wpsApPinChanged(const QString &text)
+{
+       wpsApPinButton->setEnabled(text.length() == 8);
+}
+
+
+void WpaGui::wpsApPin()
+{
+       char reply[20];
+       size_t reply_len = sizeof(reply);
+
+       QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
+       if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0)
+               return;
+
+       wpsStatusText->setText(tr("Waiting for AP/Enrollee"));
+       wpsRunning = true;
+}
+
+
+void WpaGui::stopWpsRun(bool success)
+{
+       if (wpsRunning)
+               wpsStatusText->setText(success ? tr("Connected to the network") :
+                                      tr("Stopped"));
+       else
+               wpsStatusText->setText("");
+       wpsPinEdit->setEnabled(false);
+       wpsInstructions->setText("");
+       wpsRunning = false;
+       bssFromScan = "";
+       wpsApPinEdit->setEnabled(false);
+       wpsApPinButton->setEnabled(false);
+}
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+#ifndef WPASVC_NAME
+#define WPASVC_NAME TEXT("wpasvc")
+#endif
+
+class ErrorMsg : public QMessageBox {
+public:
+       ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
+       void showMsg(QString msg);
+private:
+       DWORD err;
+};
+
+ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
+       QMessageBox(parent), err(last_err)
+{
+       setWindowTitle(tr("wpa_gui error"));
+       setIcon(QMessageBox::Warning);
+}
+
+void ErrorMsg::showMsg(QString msg)
+{
+       LPTSTR buf;
+
+       setText(msg);
+       if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                         FORMAT_MESSAGE_FROM_SYSTEM,
+                         NULL, err, 0, (LPTSTR) (void *) &buf,
+                         0, NULL) > 0) {
+               QString msg = QString::fromWCharArray(buf);
+               setInformativeText(QString("[%1] %2").arg(err).arg(msg));
+               LocalFree(buf);
+       } else {
+               setInformativeText(QString("[%1]").arg(err));
+       }
+
+       exec();
+}
+
+
+void WpaGui::startService()
+{
+       SC_HANDLE svc, scm;
+
+       scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+       if (!scm) {
+               ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
+               return;
+       }
+
+       svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
+       if (!svc) {
+               ErrorMsg(this).showMsg(tr("OpenService failed"));
+               CloseServiceHandle(scm);
+               return;
+       }
+
+       if (!StartService(svc, 0, NULL)) {
+               ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant "
+                                      "service"));
+       }
+
+       CloseServiceHandle(svc);
+       CloseServiceHandle(scm);
+}
+
+
+void WpaGui::stopService()
+{
+       SC_HANDLE svc, scm;
+       SERVICE_STATUS status;
+
+       scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+       if (!scm) {
+               ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
+               return;
+       }
+
+       svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
+       if (!svc) {
+               ErrorMsg(this).showMsg(tr("OpenService failed"));
+               CloseServiceHandle(scm);
+               return;
+       }
+
+       if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
+               ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant "
+                                      "service"));
+       }
+
+       CloseServiceHandle(svc);
+       CloseServiceHandle(scm);
+}
+
+
+bool WpaGui::serviceRunning()
+{
+       SC_HANDLE svc, scm;
+       SERVICE_STATUS status;
+       bool running = false;
+
+       scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+       if (!scm) {
+               printf("OpenSCManager failed: %d\n", (int) GetLastError());
+               return false;
+       }
+
+       svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
+       if (!svc) {
+               printf("OpenService failed: %d\n\n", (int) GetLastError());
+               CloseServiceHandle(scm);
+               return false;
+       }
+
+       if (QueryServiceStatus(svc, &status)) {
+               if (status.dwCurrentState != SERVICE_STOPPED)
+                       running = true;
+       }
+
+       CloseServiceHandle(svc);
+       CloseServiceHandle(scm);
+
+       return running;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+void WpaGui::addInterface()
+{
+       if (add_iface) {
+               add_iface->close();
+               delete add_iface;
+       }
+       add_iface = new AddInterface(this, this);
+       add_iface->show();
+       add_iface->exec();
+}
+
+
+#ifndef QT_NO_SESSIONMANAGER
+void WpaGui::saveState()
+{
+       QSettings settings("wpa_supplicant", "wpa_gui");
+       settings.beginGroup("state");
+       settings.setValue("session_id", app->sessionId());
+       settings.setValue("in_tray", inTray);
+       settings.endGroup();
+}
+#endif