2 * wpa_gui - WpaGui class
3 * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #ifdef CONFIG_NATIVE_WINDOWS
11 #endif /* CONFIG_NATIVE_WINDOWS */
15 #include <QMessageBox>
16 #include <QCloseEvent>
17 #include <QImageReader>
22 #include "common/wpa_ctrl.h"
23 #include "userdatarequest.h"
24 #include "networkconfig.h"
28 #define debug(M, ...) qDebug("DEBUG %d: " M, __LINE__, ##__VA_ARGS__)
30 #define debug(M, ...) do {} while (0)
34 WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *,
36 : QMainWindow(parent), app(_app)
39 this->setWindowFlags(Qt::Dialog);
41 #ifdef CONFIG_NATIVE_WINDOWS
42 fileStopServiceAction = new QAction(this);
43 fileStopServiceAction->setObjectName("Stop Service");
44 fileStopServiceAction->setIconText(tr("Stop Service"));
45 fileMenu->insertAction(actionWPS, fileStopServiceAction);
47 fileStartServiceAction = new QAction(this);
48 fileStartServiceAction->setObjectName("Start Service");
49 fileStartServiceAction->setIconText(tr("Start Service"));
50 fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction);
52 connect(fileStartServiceAction, SIGNAL(triggered()), this,
53 SLOT(startService()));
54 connect(fileStopServiceAction, SIGNAL(triggered()), this,
57 addInterfaceAction = new QAction(this);
58 addInterfaceAction->setIconText(tr("Add Interface"));
59 fileMenu->insertAction(fileStartServiceAction, addInterfaceAction);
61 connect(addInterfaceAction, SIGNAL(triggered()), this,
62 SLOT(addInterface()));
63 #endif /* CONFIG_NATIVE_WINDOWS */
68 * Disable WPS tab by default; it will be enabled if wpa_supplicant is
69 * built with WPS support.
71 wpsTab->setEnabled(false);
72 wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false);
74 connect(fileEventHistoryAction, SIGNAL(triggered()), this,
75 SLOT(eventHistory()));
76 connect(fileSaveConfigAction, SIGNAL(triggered()), this,
78 connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog()));
79 connect(actionPeers, SIGNAL(triggered()), this, SLOT(peersDialog()));
80 connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
81 connect(networkAddAction, SIGNAL(triggered()), this,
83 connect(networkEditAction, SIGNAL(triggered()), this,
84 SLOT(editSelectedNetwork()));
85 connect(networkRemoveAction, SIGNAL(triggered()), this,
86 SLOT(removeSelectedNetwork()));
87 connect(networkEnableAllAction, SIGNAL(triggered()), this,
88 SLOT(enableAllNetworks()));
89 connect(networkDisableAllAction, SIGNAL(triggered()), this,
90 SLOT(disableAllNetworks()));
91 connect(networkRemoveAllAction, SIGNAL(triggered()), this,
92 SLOT(removeAllNetworks()));
93 connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex()));
94 connect(helpContentsAction, SIGNAL(triggered()), this,
95 SLOT(helpContents()));
96 connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout()));
97 connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
98 connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
99 connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
100 connect(adapterSelect, SIGNAL(activated(const QString&)), this,
101 SLOT(selectAdapter(const QString&)));
102 connect(networkSelect, SIGNAL(activated(const QString&)), this,
103 SLOT(selectNetwork(const QString&)));
104 connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
105 connect(editNetworkButton, SIGNAL(clicked()), this,
106 SLOT(editListedNetwork()));
107 connect(removeNetworkButton, SIGNAL(clicked()), this,
108 SLOT(removeListedNetwork()));
109 connect(networkList, SIGNAL(itemSelectionChanged()), this,
110 SLOT(updateNetworkDisabledStatus()));
111 connect(enableRadioButton, SIGNAL(toggled(bool)), this,
112 SLOT(enableListedNetwork(bool)));
113 connect(disableRadioButton, SIGNAL(toggled(bool)), this,
114 SLOT(disableListedNetwork(bool)));
115 connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan()));
116 connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
117 this, SLOT(editListedNetwork()));
118 connect(wpaguiTab, SIGNAL(currentChanged(int)), this,
119 SLOT(tabChanged(int)));
120 connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc()));
121 connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin()));
122 connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this,
123 SLOT(wpsApPinChanged(const QString &)));
124 connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin()));
138 ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
139 signalMeterInterval = 0;
143 #ifndef QT_NO_SESSIONMANAGER
144 if (app->isSessionRestored()) {
145 QSettings settings("wpa_supplicant", "wpa_gui");
146 settings.beginGroup("state");
147 if (app->sessionId().compare(settings.value("session_id").
149 startInTray = settings.value("in_tray").toBool();
154 if (QSystemTrayIcon::isSystemTrayAvailable())
155 createTrayIcon(startInTray);
159 connectedToService = false;
160 textStatus->setText(tr("connecting to wpa_supplicant"));
161 timer = new QTimer(this);
162 connect(timer, SIGNAL(timeout()), SLOT(ping()));
163 timer->setSingleShot(false);
166 signalMeterTimer = new QTimer(this);
167 signalMeterTimer->setInterval(signalMeterInterval);
168 connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate()));
170 if (openCtrlConnection(ctrl_iface) < 0) {
171 debug("Failed to open control connection to "
176 networkMayHaveChanged = true;
186 wpa_ctrl_detach(monitor_conn);
187 wpa_ctrl_close(monitor_conn);
191 wpa_ctrl_close(ctrl_conn);
228 free(ctrl_iface_dir);
229 ctrl_iface_dir = NULL;
233 void WpaGui::languageChange()
239 void WpaGui::parse_argv()
242 WpaGuiApp *app = qobject_cast<WpaGuiApp*>(qApp);
244 c = getopt(app->argc, app->argv, "i:m:p:tq");
250 ctrl_iface = strdup(optarg);
253 signalMeterInterval = atoi(optarg) * 1000;
256 free(ctrl_iface_dir);
257 ctrl_iface_dir = strdup(optarg);
270 int WpaGui::openCtrlConnection(const char *ifname)
274 char buf[2048], *pos, *pos2;
278 if (ifname != ctrl_iface) {
280 ctrl_iface = strdup(ifname);
283 #ifdef CONFIG_CTRL_IFACE_UDP
285 ctrl_iface = strdup("udp");
286 #endif /* CONFIG_CTRL_IFACE_UDP */
287 #ifdef CONFIG_CTRL_IFACE_UNIX
289 DIR *dir = opendir(ctrl_iface_dir);
293 while ((dent = readdir(dir))) {
294 #ifdef _DIRENT_HAVE_D_TYPE
295 /* Skip the file if it is not a socket.
296 * Also accept DT_UNKNOWN (0) in case
297 * the C library or underlying file
298 * system does not support d_type. */
299 if (dent->d_type != DT_SOCK &&
300 dent->d_type != DT_UNKNOWN)
302 #endif /* _DIRENT_HAVE_D_TYPE */
304 if (strcmp(dent->d_name, ".") == 0 ||
305 strcmp(dent->d_name, "..") == 0)
307 debug("Selected interface '%s'",
309 ctrl_iface = strdup(dent->d_name);
314 #endif /* CONFIG_CTRL_IFACE_UNIX */
315 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
316 struct wpa_ctrl *ctrl;
322 ctrl = wpa_ctrl_open(NULL);
324 len = sizeof(buf) - 1;
325 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
328 connectedToService = true;
330 pos = strchr(buf, '\n');
333 ctrl_iface = strdup(buf);
335 wpa_ctrl_close(ctrl);
337 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
340 if (ctrl_iface == NULL) {
341 #ifdef CONFIG_NATIVE_WINDOWS
342 static bool first = true;
343 if (first && !serviceRunning()) {
345 if (QMessageBox::warning(
347 tr("wpa_supplicant service is not "
349 "Do you want to start it?"),
350 QMessageBox::Yes | QMessageBox::No) ==
354 #endif /* CONFIG_NATIVE_WINDOWS */
358 #ifdef CONFIG_CTRL_IFACE_UNIX
359 flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
360 cfile = (char *) malloc(flen);
363 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
364 #else /* CONFIG_CTRL_IFACE_UNIX */
365 flen = strlen(ctrl_iface) + 1;
366 cfile = (char *) malloc(flen);
369 snprintf(cfile, flen, "%s", ctrl_iface);
370 #endif /* CONFIG_CTRL_IFACE_UNIX */
373 wpa_ctrl_close(ctrl_conn);
380 wpa_ctrl_detach(monitor_conn);
381 wpa_ctrl_close(monitor_conn);
385 debug("Trying to connect to '%s'", cfile);
386 ctrl_conn = wpa_ctrl_open(cfile);
387 if (ctrl_conn == NULL) {
391 monitor_conn = wpa_ctrl_open(cfile);
393 if (monitor_conn == NULL) {
394 wpa_ctrl_close(ctrl_conn);
397 if (wpa_ctrl_attach(monitor_conn)) {
398 debug("Failed to attach to wpa_supplicant");
399 wpa_ctrl_close(monitor_conn);
401 wpa_ctrl_close(ctrl_conn);
406 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
407 msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
408 QSocketNotifier::Read, this);
409 connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
412 adapterSelect->clear();
413 adapterSelect->addItem(ctrl_iface);
414 adapterSelect->setCurrentIndex(0);
416 len = sizeof(buf) - 1;
417 if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
422 pos2 = strchr(pos, '\n');
425 if (strcmp(pos, ctrl_iface) != 0)
426 adapterSelect->addItem(pos);
434 len = sizeof(buf) - 1;
435 if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len,
440 QStringList types = res.split(QChar(' '));
441 bool wps = types.contains("WSC");
442 actionWPS->setEnabled(wps);
443 wpsTab->setEnabled(wps);
444 wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps);
451 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
455 if (ctrl_conn == NULL)
457 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL);
459 debug("'%s' command timed out.", cmd);
461 debug("'%s' command failed.", cmd);
467 QString WpaGui::wpaStateTranslate(char *state)
469 if (!strcmp(state, "DISCONNECTED"))
470 return tr("Disconnected");
471 else if (!strcmp(state, "INACTIVE"))
472 return tr("Inactive");
473 else if (!strcmp(state, "SCANNING"))
474 return tr("Scanning");
475 else if (!strcmp(state, "AUTHENTICATING"))
476 return tr("Authenticating");
477 else if (!strcmp(state, "ASSOCIATING"))
478 return tr("Associating");
479 else if (!strcmp(state, "ASSOCIATED"))
480 return tr("Associated");
481 else if (!strcmp(state, "4WAY_HANDSHAKE"))
482 return tr("4-Way Handshake");
483 else if (!strcmp(state, "GROUP_HANDSHAKE"))
484 return tr("Group Handshake");
485 else if (!strcmp(state, "COMPLETED"))
486 return tr("Completed");
488 return tr("Unknown");
492 void WpaGui::updateStatus()
494 char buf[2048], *start, *end, *pos;
497 pingsToStatusUpdate = 10;
499 len = sizeof(buf) - 1;
500 if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
501 textStatus->setText(tr("Could not get status from "
503 textAuthentication->clear();
504 textEncryption->clear();
507 textIpAddress->clear();
508 updateTrayToolTip(tr("no status information"));
509 updateTrayIcon(TrayIconOffline);
510 signalMeterTimer->stop();
512 #ifdef CONFIG_NATIVE_WINDOWS
513 static bool first = true;
514 if (first && connectedToService &&
515 (ctrl_iface == NULL || *ctrl_iface == '\0')) {
517 if (QMessageBox::information(
519 tr("No network interfaces in use.\n"
520 "Would you like to add one?"),
521 QMessageBox::Yes | QMessageBox::No) ==
525 #endif /* CONFIG_NATIVE_WINDOWS */
531 bool auth_updated = false, ssid_updated = false;
532 bool bssid_updated = false, ipaddr_updated = false;
533 bool status_updated = false;
534 char *pairwise_cipher = NULL, *group_cipher = NULL;
540 end = strchr(start, '\n');
544 while (end[0] && end[1])
549 pos = strchr(start, '=');
552 if (strcmp(start, "bssid") == 0) {
553 bssid_updated = true;
554 textBssid->setText(pos);
555 } else if (strcmp(start, "ssid") == 0) {
557 textSsid->setText(pos);
558 updateTrayToolTip(pos + tr(" (associated)"));
559 if (!signalMeterInterval) {
560 /* if signal meter is not enabled show
561 * full signal strength */
562 updateTrayIcon(TrayIconSignalExcellent);
564 } else if (strcmp(start, "ip_address") == 0) {
565 ipaddr_updated = true;
566 textIpAddress->setText(pos);
567 } else if (strcmp(start, "wpa_state") == 0) {
568 status_updated = true;
569 textStatus->setText(wpaStateTranslate(pos));
570 } else if (strcmp(start, "key_mgmt") == 0) {
572 textAuthentication->setText(pos);
573 /* TODO: could add EAP status to this */
574 } else if (strcmp(start, "pairwise_cipher") == 0) {
575 pairwise_cipher = pos;
576 } else if (strcmp(start, "group_cipher") == 0) {
578 } else if (strcmp(start, "mode") == 0) {
587 if (status_updated && mode)
588 textStatus->setText(textStatus->text() + " (" + mode + ")");
590 if (pairwise_cipher || group_cipher) {
592 if (pairwise_cipher && group_cipher &&
593 strcmp(pairwise_cipher, group_cipher) != 0) {
594 encr.append(pairwise_cipher);
596 encr.append(group_cipher);
597 } else if (pairwise_cipher) {
598 encr.append(pairwise_cipher);
600 encr.append(group_cipher);
601 encr.append(" [group key only]");
603 textEncryption->setText(encr);
605 textEncryption->clear();
607 if (signalMeterInterval) {
609 * Handle signal meter service. When network is not associated,
610 * deactivate timer, otherwise keep it going. Tray icon has to
611 * be initialized here, because of the initial delay of the
615 if (!signalMeterTimer->isActive()) {
616 updateTrayIcon(TrayIconConnected);
617 signalMeterTimer->start();
620 signalMeterTimer->stop();
627 textAuthentication->clear();
630 updateTrayToolTip(tr("(not-associated)"));
631 updateTrayIcon(TrayIconOffline);
636 textIpAddress->clear();
640 void WpaGui::updateNetworks()
642 char buf[4096], *start, *end, *id, *ssid, *bssid, *flags;
644 int first_active = -1;
645 int was_selected = -1;
646 bool current = false;
648 if (!networkMayHaveChanged)
651 if (networkList->currentRow() >= 0)
652 was_selected = networkList->currentRow();
654 networkSelect->clear();
655 networkList->clear();
657 if (ctrl_conn == NULL)
660 len = sizeof(buf) - 1;
661 if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
665 start = strchr(buf, '\n');
672 end = strchr(start, '\n');
676 while (end[0] && end[1])
682 ssid = strchr(id, '\t');
686 bssid = strchr(ssid, '\t');
690 flags = strchr(bssid, '\t');
695 if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) {
703 network.append(": ");
704 network.append(ssid);
705 networkSelect->addItem(network);
706 networkList->addItem(network);
708 if (strstr(flags, "[CURRENT]")) {
709 networkSelect->setCurrentIndex(networkSelect->count() -
712 } else if (first_active < 0 &&
713 strstr(flags, "[DISABLED]") == NULL)
714 first_active = networkSelect->count() - 1;
721 if (networkSelect->count() > 1)
722 networkSelect->addItem(tr("Select any network"));
724 if (!current && first_active >= 0)
725 networkSelect->setCurrentIndex(first_active);
727 if (was_selected >= 0 && networkList->count() > 0) {
728 if (was_selected < networkList->count())
729 networkList->setCurrentRow(was_selected);
731 networkList->setCurrentRow(networkList->count() - 1);
734 networkList->setCurrentRow(networkSelect->currentIndex());
736 networkMayHaveChanged = false;
740 void WpaGui::helpIndex()
746 void WpaGui::helpContents()
748 debug("helpContents");
752 void WpaGui::helpAbout()
754 QMessageBox::about(this, "wpa_gui for wpa_supplicant",
755 "Copyright (c) 2003-2015,\n"
756 "Jouni Malinen <j@w1.fi>\n"
757 "and contributors.\n"
759 "This software may be distributed under\n"
760 "the terms of the BSD license.\n"
761 "See README for more details.\n"
763 "This product includes software developed\n"
764 "by the OpenSSL Project for use in the\n"
765 "OpenSSL Toolkit (http://www.openssl.org/)\n");
769 void WpaGui::disconnect()
772 size_t reply_len = sizeof(reply);
773 ctrlRequest("DISCONNECT", reply, &reply_len);
785 scanres = new ScanResults();
788 scanres->setWpaGui(this);
794 void WpaGui::eventHistory()
801 eh = new EventHistory();
815 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
817 * QSocketNotifier cannot be used with Windows named pipes, so use a
818 * timer to check for received messages for now. This could be
819 * optimized be doing something specific to named pipes or Windows
820 * events, but it is not clear what would be the best way of doing that
824 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
826 if (scanres && !scanres->isVisible()) {
831 if (eh && !eh->isVisible()) {
836 if (udr && !udr->isVisible()) {
841 len = sizeof(buf) - 1;
842 if (ctrlRequest("PING", buf, &len) < 0) {
843 debug("PING failed - trying to reconnect");
844 if (openCtrlConnection(ctrl_iface) >= 0) {
845 debug("Reconnected successfully");
846 pingsToStatusUpdate = 0;
850 pingsToStatusUpdate--;
851 if (pingsToStatusUpdate <= 0) {
856 #ifndef CONFIG_CTRL_IFACE_NAMED_PIPE
857 /* Use less frequent pings and status updates when the main window is
858 * hidden (running in taskbar). */
859 int interval = isHidden() ? 5000 : 1000;
860 if (timer->interval() != interval)
861 timer->setInterval(interval);
862 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
866 void WpaGui::signalMeterUpdate()
869 size_t reply_len = sizeof(reply);
873 ctrlRequest("SIGNAL_POLL", reply, &reply_len);
875 /* In order to eliminate signal strength fluctuations, try
876 * to obtain averaged RSSI value in the first place. */
877 if ((rssi = strstr(reply, "AVG_RSSI=")) != NULL)
878 rssi_value = atoi(&rssi[sizeof("AVG_RSSI")]);
879 else if ((rssi = strstr(reply, "RSSI=")) != NULL)
880 rssi_value = atoi(&rssi[sizeof("RSSI")]);
882 debug("Failed to get RSSI value");
883 updateTrayIcon(TrayIconSignalNone);
887 debug("RSSI value: %d", rssi_value);
890 * NOTE: The code below assumes, that the unit of the value returned
891 * by the SIGNAL POLL request is dBm. It might not be true for all
892 * wpa_supplicant drivers.
896 * Calibration is based on "various Internet sources". Nonetheless,
897 * it seems to be compatible with the Windows 8.1 strength meter -
898 * tested on Intel Centrino Advanced-N 6235.
900 if (rssi_value >= -60)
901 updateTrayIcon(TrayIconSignalExcellent);
902 else if (rssi_value >= -68)
903 updateTrayIcon(TrayIconSignalGood);
904 else if (rssi_value >= -76)
905 updateTrayIcon(TrayIconSignalOk);
906 else if (rssi_value >= -84)
907 updateTrayIcon(TrayIconSignalWeak);
909 updateTrayIcon(TrayIconSignalNone);
913 static int str_match(const char *a, const char *b)
915 return strncmp(a, b, strlen(b)) == 0;
919 void WpaGui::processMsg(char *msg)
921 char *pos = msg, *pos2;
927 priority = atoi(pos);
928 pos = strchr(pos, '>');
935 WpaMsg wm(pos, priority);
939 peers->event_notify(wm);
941 while (msgs.count() > 100)
944 /* Update last message with truncated version of the event */
945 if (strncmp(pos, "CTRL-", 5) == 0) {
946 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
953 QString lastmsg = pos2;
954 lastmsg.truncate(40);
955 textLastMessage->setText(lastmsg);
957 pingsToStatusUpdate = 0;
958 networkMayHaveChanged = true;
960 if (str_match(pos, WPA_CTRL_REQ))
961 processCtrlReq(pos + strlen(WPA_CTRL_REQ));
962 else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres)
963 scanres->updateResults();
964 else if (str_match(pos, WPA_EVENT_DISCONNECTED))
965 showTrayMessage(QSystemTrayIcon::Information, 3,
966 tr("Disconnected from network."));
967 else if (str_match(pos, WPA_EVENT_CONNECTED)) {
968 showTrayMessage(QSystemTrayIcon::Information, 3,
969 tr("Connection to network established."));
970 QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus()));
972 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) {
973 wpsStatusText->setText(tr("WPS AP in active PBC mode found"));
974 if (textStatus->text() == "INACTIVE" ||
975 textStatus->text() == "DISCONNECTED")
976 wpaguiTab->setCurrentWidget(wpsTab);
977 wpsInstructions->setText(tr("Press the PBC button on the "
978 "screen to start registration"));
979 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) {
980 wpsStatusText->setText(tr("WPS AP with recently selected "
982 if (textStatus->text() == "INACTIVE" ||
983 textStatus->text() == "DISCONNECTED")
984 wpaguiTab->setCurrentWidget(wpsTab);
985 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) {
986 showTrayMessage(QSystemTrayIcon::Information, 3,
987 "Wi-Fi Protected Setup (WPS) AP\n"
988 "indicating this client is authorized.");
989 wpsStatusText->setText("WPS AP indicating this client is "
991 if (textStatus->text() == "INACTIVE" ||
992 textStatus->text() == "DISCONNECTED")
993 wpaguiTab->setCurrentWidget(wpsTab);
994 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
995 wpsStatusText->setText(tr("WPS AP detected"));
996 } else if (str_match(pos, WPS_EVENT_OVERLAP)) {
997 wpsStatusText->setText(tr("PBC mode overlap detected"));
998 wpsInstructions->setText(tr("More than one AP is currently in "
999 "active WPS PBC mode. Wait couple "
1000 "of minutes and try again"));
1001 wpaguiTab->setCurrentWidget(wpsTab);
1002 } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) {
1003 wpsStatusText->setText(tr("Network configuration received"));
1004 wpaguiTab->setCurrentWidget(wpsTab);
1005 } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) {
1006 if (strstr(pos, "(WSC)"))
1007 wpsStatusText->setText(tr("Registration started"));
1008 } else if (str_match(pos, WPS_EVENT_M2D)) {
1009 wpsStatusText->setText(tr("Registrar does not yet know PIN"));
1010 } else if (str_match(pos, WPS_EVENT_FAIL)) {
1011 wpsStatusText->setText(tr("Registration failed"));
1012 } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
1013 wpsStatusText->setText(tr("Registration succeeded"));
1018 void WpaGui::processCtrlReq(const char *req)
1024 udr = new UserDataRequest();
1027 if (udr->setParams(this, req) < 0) {
1037 void WpaGui::receiveMsgs()
1042 while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
1043 len = sizeof(buf) - 1;
1044 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
1052 void WpaGui::connectB()
1055 size_t reply_len = sizeof(reply);
1056 ctrlRequest("REASSOCIATE", reply, &reply_len);
1060 void WpaGui::selectNetwork( const QString &sel )
1064 size_t reply_len = sizeof(reply);
1066 if (cmd.contains(QRegExp("^\\d+:")))
1067 cmd.truncate(cmd.indexOf(':'));
1070 cmd.prepend("SELECT_NETWORK ");
1071 ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len);
1077 void WpaGui::enableNetwork(const QString &sel)
1081 size_t reply_len = sizeof(reply);
1083 if (cmd.contains(QRegExp("^\\d+:")))
1084 cmd.truncate(cmd.indexOf(':'));
1085 else if (!cmd.startsWith("all")) {
1086 debug("Invalid editNetwork '%s'",
1087 cmd.toLocal8Bit().constData());
1090 cmd.prepend("ENABLE_NETWORK ");
1091 ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len);
1096 void WpaGui::disableNetwork(const QString &sel)
1100 size_t reply_len = sizeof(reply);
1102 if (cmd.contains(QRegExp("^\\d+:")))
1103 cmd.truncate(cmd.indexOf(':'));
1104 else if (!cmd.startsWith("all")) {
1105 debug("Invalid editNetwork '%s'",
1106 cmd.toLocal8Bit().constData());
1109 cmd.prepend("DISABLE_NETWORK ");
1110 ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len);
1115 void WpaGui::editNetwork(const QString &sel)
1120 if (cmd.contains(QRegExp("^\\d+:"))) {
1121 cmd.truncate(cmd.indexOf(':'));
1125 NetworkConfig *nc = new NetworkConfig();
1128 nc->setWpaGui(this);
1131 nc->paramsFromConfig(id);
1140 void WpaGui::editSelectedNetwork()
1142 if (networkSelect->count() < 1) {
1143 QMessageBox::information(
1144 this, tr("No Networks"),
1145 tr("There are no networks to edit.\n"));
1148 QString sel(networkSelect->currentText());
1153 void WpaGui::editListedNetwork()
1155 if (networkList->currentRow() < 0) {
1156 QMessageBox::information(this, tr("Select A Network"),
1157 tr("Select a network from the list to"
1161 QString sel(networkList->currentItem()->text());
1166 void WpaGui::triggerUpdate()
1169 networkMayHaveChanged = true;
1174 void WpaGui::addNetwork()
1176 NetworkConfig *nc = new NetworkConfig();
1179 nc->setWpaGui(this);
1186 void WpaGui::removeNetwork(const QString &sel)
1190 size_t reply_len = sizeof(reply);
1192 if (cmd.contains(QRegExp("^\\d+:")))
1193 cmd.truncate(cmd.indexOf(':'));
1194 else if (!cmd.startsWith("all")) {
1195 debug("Invalid editNetwork '%s'",
1196 cmd.toLocal8Bit().constData());
1199 cmd.prepend("REMOVE_NETWORK ");
1200 ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len);
1205 void WpaGui::removeSelectedNetwork()
1207 if (networkSelect->count() < 1) {
1208 QMessageBox::information(this, tr("No Networks"),
1209 tr("There are no networks to remove."
1213 QString sel(networkSelect->currentText());
1218 void WpaGui::removeListedNetwork()
1220 if (networkList->currentRow() < 0) {
1221 QMessageBox::information(this, tr("Select A Network"),
1222 tr("Select a network from the list "
1223 "to remove it.\n"));
1226 QString sel(networkList->currentItem()->text());
1231 void WpaGui::enableAllNetworks()
1238 void WpaGui::disableAllNetworks()
1241 disableNetwork(sel);
1245 void WpaGui::removeAllNetworks()
1252 int WpaGui::getNetworkDisabled(const QString &sel)
1256 size_t reply_len = sizeof(reply) - 1;
1257 int pos = cmd.indexOf(':');
1259 debug("Invalid getNetworkDisabled '%s'",
1260 cmd.toLocal8Bit().constData());
1264 cmd.prepend("GET_NETWORK ");
1265 cmd.append(" disabled");
1267 if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) >= 0
1268 && reply_len >= 1) {
1269 reply[reply_len] = '\0';
1270 if (!str_match(reply, "FAIL"))
1278 void WpaGui::updateNetworkDisabledStatus()
1280 if (networkList->currentRow() < 0)
1283 QString sel(networkList->currentItem()->text());
1285 switch (getNetworkDisabled(sel)) {
1287 if (!enableRadioButton->isChecked())
1288 enableRadioButton->setChecked(true);
1291 if (!disableRadioButton->isChecked())
1292 disableRadioButton->setChecked(true);
1298 void WpaGui::enableListedNetwork(bool enabled)
1300 if (networkList->currentRow() < 0 || !enabled)
1303 QString sel(networkList->currentItem()->text());
1305 if (getNetworkDisabled(sel) == 1)
1310 void WpaGui::disableListedNetwork(bool disabled)
1312 if (networkList->currentRow() < 0 || !disabled)
1315 QString sel(networkList->currentItem()->text());
1317 if (getNetworkDisabled(sel) == 0)
1318 disableNetwork(sel);
1322 void WpaGui::saveConfig()
1327 len = sizeof(buf) - 1;
1328 ctrlRequest("SAVE_CONFIG", buf, &len);
1332 if (str_match(buf, "FAIL"))
1333 QMessageBox::warning(
1334 this, tr("Failed to save configuration"),
1335 tr("The configuration could not be saved.\n"
1337 "The update_config=1 configuration option\n"
1338 "must be used for configuration saving to\n"
1339 "be permitted.\n"));
1341 QMessageBox::information(
1342 this, tr("Saved configuration"),
1343 tr("The current configuration was saved."
1348 void WpaGui::selectAdapter( const QString & sel )
1350 if (openCtrlConnection(sel.toLocal8Bit().constData()) < 0)
1351 debug("Failed to open control connection to "
1358 void WpaGui::createTrayIcon(bool trayOnly)
1360 QApplication::setQuitOnLastWindowClosed(false);
1362 tray_icon = new QSystemTrayIcon(this);
1363 updateTrayIcon(TrayIconOffline);
1366 SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
1367 this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
1369 ackTrayIcon = false;
1371 tray_menu = new QMenu(this);
1373 disconnectAction = new QAction(tr("&Disconnect"), this);
1374 reconnectAction = new QAction(tr("Re&connect"), this);
1375 connect(disconnectAction, SIGNAL(triggered()), this,
1376 SLOT(disconnect()));
1377 connect(reconnectAction, SIGNAL(triggered()), this,
1379 tray_menu->addAction(disconnectAction);
1380 tray_menu->addAction(reconnectAction);
1381 tray_menu->addSeparator();
1383 eventAction = new QAction(tr("&Event History"), this);
1384 scanAction = new QAction(tr("Scan &Results"), this);
1385 statAction = new QAction(tr("S&tatus"), this);
1386 connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
1387 connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
1388 connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
1389 tray_menu->addAction(eventAction);
1390 tray_menu->addAction(scanAction);
1391 tray_menu->addAction(statAction);
1392 tray_menu->addSeparator();
1394 showAction = new QAction(tr("&Show Window"), this);
1395 hideAction = new QAction(tr("&Hide Window"), this);
1396 quitAction = new QAction(tr("&Quit"), this);
1397 connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
1398 connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
1399 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1400 tray_menu->addAction(showAction);
1401 tray_menu->addAction(hideAction);
1402 tray_menu->addSeparator();
1403 tray_menu->addAction(quitAction);
1405 tray_icon->setContextMenu(tray_menu);
1415 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
1416 const QString & msg)
1418 if (!QSystemTrayIcon::supportsMessages())
1421 if (isVisible() || !tray_icon || !tray_icon->isVisible() || quietMode)
1424 tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
1428 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
1431 /* use close() here instead of hide() and allow the
1432 * custom closeEvent handler take care of children */
1433 case QSystemTrayIcon::Trigger:
1443 case QSystemTrayIcon::MiddleClick:
1452 void WpaGui::showTrayStatus()
1457 len = sizeof(buf) - 1;
1458 if (ctrlRequest("STATUS", buf, &len) < 0)
1462 QString msg, status(buf);
1464 QStringList lines = status.split(QRegExp("\\n"));
1465 for (QStringList::Iterator it = lines.begin();
1466 it != lines.end(); it++) {
1467 int pos = (*it).indexOf('=') + 1;
1471 if ((*it).startsWith("bssid="))
1472 msg.append("BSSID:\t" + (*it).mid(pos) + "\n");
1473 else if ((*it).startsWith("ssid="))
1474 msg.append("SSID: \t" + (*it).mid(pos) + "\n");
1475 else if ((*it).startsWith("pairwise_cipher="))
1476 msg.append("PAIR: \t" + (*it).mid(pos) + "\n");
1477 else if ((*it).startsWith("group_cipher="))
1478 msg.append("GROUP:\t" + (*it).mid(pos) + "\n");
1479 else if ((*it).startsWith("key_mgmt="))
1480 msg.append("AUTH: \t" + (*it).mid(pos) + "\n");
1481 else if ((*it).startsWith("wpa_state="))
1482 msg.append("STATE:\t" + (*it).mid(pos) + "\n");
1483 else if ((*it).startsWith("ip_address="))
1484 msg.append("IP: \t" + (*it).mid(pos) + "\n");
1485 else if ((*it).startsWith("Supplicant PAE state="))
1486 msg.append("PAE: \t" + (*it).mid(pos) + "\n");
1487 else if ((*it).startsWith("EAP state="))
1488 msg.append("EAP: \t" + (*it).mid(pos) + "\n");
1492 showTrayMessage(QSystemTrayIcon::Information, 10, msg);
1496 void WpaGui::updateTrayToolTip(const QString &msg)
1499 tray_icon->setToolTip(msg);
1503 void WpaGui::updateTrayIcon(TrayIconType type)
1505 if (!tray_icon || currentIconType == type)
1508 QIcon fallback_icon;
1511 if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
1512 fallback_icon = QIcon(":/icons/wpa_gui.svg");
1514 fallback_icon = QIcon(":/icons/wpa_gui.png");
1517 case TrayIconOffline:
1518 names << "network-wireless-offline-symbolic"
1519 << "network-wireless-offline"
1520 << "network-wireless-signal-none-symbolic"
1521 << "network-wireless-signal-none";
1523 case TrayIconAcquiring:
1524 names << "network-wireless-acquiring-symbolic"
1525 << "network-wireless-acquiring";
1527 case TrayIconConnected:
1528 names << "network-wireless-connected-symbolic"
1529 << "network-wireless-connected";
1531 case TrayIconSignalNone:
1532 names << "network-wireless-signal-none-symbolic"
1533 << "network-wireless-signal-none";
1535 case TrayIconSignalWeak:
1536 names << "network-wireless-signal-weak-symbolic"
1537 << "network-wireless-signal-weak";
1539 case TrayIconSignalOk:
1540 names << "network-wireless-signal-ok-symbolic"
1541 << "network-wireless-signal-ok";
1543 case TrayIconSignalGood:
1544 names << "network-wireless-signal-good-symbolic"
1545 << "network-wireless-signal-good";
1547 case TrayIconSignalExcellent:
1548 names << "network-wireless-signal-excellent-symbolic"
1549 << "network-wireless-signal-excellent";
1553 currentIconType = type;
1554 tray_icon->setIcon(loadThemedIcon(names, fallback_icon));
1558 QIcon WpaGui::loadThemedIcon(const QStringList &names,
1559 const QIcon &fallback)
1563 for (QStringList::ConstIterator it = names.begin();
1564 it != names.end(); it++) {
1565 icon = QIcon::fromTheme(*it);
1574 void WpaGui::closeEvent(QCloseEvent *event)
1600 if (tray_icon && !ackTrayIcon) {
1601 /* give user a visual hint that the tray icon exists */
1602 if (QSystemTrayIcon::supportsMessages()) {
1604 showTrayMessage(QSystemTrayIcon::Information, 3,
1606 tr(" will keep running in "
1607 "the system tray."));
1609 QMessageBox::information(this, qAppName() +
1611 tr("The program will keep "
1612 "running in the system "
1622 void WpaGui::wpsDialog()
1624 wpaguiTab->setCurrentWidget(wpsTab);
1628 void WpaGui::peersDialog()
1635 peers = new Peers();
1638 peers->setWpaGui(this);
1644 void WpaGui::tabChanged(int index)
1652 wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1653 if (bssFromScan.isEmpty())
1654 wpsApPinButton->setEnabled(false);
1658 void WpaGui::wpsPbc()
1661 size_t reply_len = sizeof(reply);
1663 if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
1666 wpsPinEdit->setEnabled(false);
1667 if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) {
1668 wpsInstructions->setText(tr("Press the push button on the AP to "
1669 "start the PBC mode."));
1671 wpsInstructions->setText(tr("If you have not yet done so, press "
1672 "the push button on the AP to start "
1675 wpsStatusText->setText(tr("Waiting for Registrar"));
1680 void WpaGui::wpsGeneratePin()
1683 size_t reply_len = sizeof(reply) - 1;
1685 if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
1688 reply[reply_len] = '\0';
1690 wpsPinEdit->setText(reply);
1691 wpsPinEdit->setEnabled(true);
1692 wpsInstructions->setText(tr("Enter the generated PIN into the Registrar "
1693 "(either the internal one in the AP or an "
1695 wpsStatusText->setText(tr("Waiting for Registrar"));
1700 void WpaGui::setBssFromScan(const QString &bssid)
1702 bssFromScan = bssid;
1703 wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1704 wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
1705 wpsStatusText->setText(tr("WPS AP selected from scan results"));
1706 wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., "
1707 "from a label in the device, enter the eight "
1708 "digit AP PIN and click Use AP PIN button."));
1712 void WpaGui::wpsApPinChanged(const QString &text)
1714 wpsApPinButton->setEnabled(text.length() == 8);
1718 void WpaGui::wpsApPin()
1721 size_t reply_len = sizeof(reply);
1723 QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
1724 if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) < 0)
1727 wpsStatusText->setText(tr("Waiting for AP/Enrollee"));
1732 void WpaGui::stopWpsRun(bool success)
1735 wpsStatusText->setText(success ? tr("Connected to the network") :
1738 wpsStatusText->setText("");
1739 wpsPinEdit->setEnabled(false);
1740 wpsInstructions->setText("");
1743 wpsApPinEdit->setEnabled(false);
1744 wpsApPinButton->setEnabled(false);
1748 #ifdef CONFIG_NATIVE_WINDOWS
1751 #define WPASVC_NAME TEXT("wpasvc")
1754 class ErrorMsg : public QMessageBox {
1756 ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
1757 void showMsg(QString msg);
1762 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
1763 QMessageBox(parent), err(last_err)
1765 setWindowTitle(tr("wpa_gui error"));
1766 setIcon(QMessageBox::Warning);
1769 void ErrorMsg::showMsg(QString msg)
1774 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1775 FORMAT_MESSAGE_FROM_SYSTEM,
1776 NULL, err, 0, (LPTSTR) (void *) &buf,
1778 QString msg = QString::fromWCharArray(buf);
1779 setInformativeText(QString("[%1] %2").arg(err).arg(msg));
1782 setInformativeText(QString("[%1]").arg(err));
1789 void WpaGui::startService()
1793 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1795 ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
1799 svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
1801 ErrorMsg(this).showMsg(tr("OpenService failed"));
1802 CloseServiceHandle(scm);
1806 if (!StartService(svc, 0, NULL)) {
1807 ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant "
1811 CloseServiceHandle(svc);
1812 CloseServiceHandle(scm);
1816 void WpaGui::stopService()
1819 SERVICE_STATUS status;
1821 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1823 ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
1827 svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
1829 ErrorMsg(this).showMsg(tr("OpenService failed"));
1830 CloseServiceHandle(scm);
1834 if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
1835 ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant "
1839 CloseServiceHandle(svc);
1840 CloseServiceHandle(scm);
1844 bool WpaGui::serviceRunning()
1847 SERVICE_STATUS status;
1848 bool running = false;
1850 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1852 debug("OpenSCManager failed: %d", (int) GetLastError());
1856 svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
1858 debug("OpenService failed: %d", (int) GetLastError());
1859 CloseServiceHandle(scm);
1863 if (QueryServiceStatus(svc, &status)) {
1864 if (status.dwCurrentState != SERVICE_STOPPED)
1868 CloseServiceHandle(svc);
1869 CloseServiceHandle(scm);
1874 #endif /* CONFIG_NATIVE_WINDOWS */
1877 void WpaGui::addInterface()
1883 add_iface = new AddInterface(this, this);
1889 #ifndef QT_NO_SESSIONMANAGER
1890 void WpaGui::saveState()
1892 QSettings settings("wpa_supplicant", "wpa_gui");
1893 settings.beginGroup("state");
1894 settings.setValue("session_id", app->sessionId());
1895 settings.setValue("in_tray", inTray);
1896 settings.endGroup();