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 *, Qt::WFlags)
35 : QMainWindow(parent), app(_app)
38 this->setWindowFlags(Qt::Dialog);
40 #ifdef CONFIG_NATIVE_WINDOWS
41 fileStopServiceAction = new QAction(this);
42 fileStopServiceAction->setObjectName("Stop Service");
43 fileStopServiceAction->setIconText(tr("Stop Service"));
44 fileMenu->insertAction(actionWPS, fileStopServiceAction);
46 fileStartServiceAction = new QAction(this);
47 fileStartServiceAction->setObjectName("Start Service");
48 fileStartServiceAction->setIconText(tr("Start Service"));
49 fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction);
51 connect(fileStartServiceAction, SIGNAL(triggered()), this,
52 SLOT(startService()));
53 connect(fileStopServiceAction, SIGNAL(triggered()), this,
56 addInterfaceAction = new QAction(this);
57 addInterfaceAction->setIconText(tr("Add Interface"));
58 fileMenu->insertAction(fileStartServiceAction, addInterfaceAction);
60 connect(addInterfaceAction, SIGNAL(triggered()), this,
61 SLOT(addInterface()));
62 #endif /* CONFIG_NATIVE_WINDOWS */
67 * Disable WPS tab by default; it will be enabled if wpa_supplicant is
68 * built with WPS support.
70 wpsTab->setEnabled(false);
71 wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false);
73 connect(fileEventHistoryAction, SIGNAL(triggered()), this,
74 SLOT(eventHistory()));
75 connect(fileSaveConfigAction, SIGNAL(triggered()), this,
77 connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog()));
78 connect(actionPeers, SIGNAL(triggered()), this, SLOT(peersDialog()));
79 connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
80 connect(networkAddAction, SIGNAL(triggered()), this,
82 connect(networkEditAction, SIGNAL(triggered()), this,
83 SLOT(editSelectedNetwork()));
84 connect(networkRemoveAction, SIGNAL(triggered()), this,
85 SLOT(removeSelectedNetwork()));
86 connect(networkEnableAllAction, SIGNAL(triggered()), this,
87 SLOT(enableAllNetworks()));
88 connect(networkDisableAllAction, SIGNAL(triggered()), this,
89 SLOT(disableAllNetworks()));
90 connect(networkRemoveAllAction, SIGNAL(triggered()), this,
91 SLOT(removeAllNetworks()));
92 connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex()));
93 connect(helpContentsAction, SIGNAL(triggered()), this,
94 SLOT(helpContents()));
95 connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout()));
96 connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
97 connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
98 connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
99 connect(adapterSelect, SIGNAL(activated(const QString&)), this,
100 SLOT(selectAdapter(const QString&)));
101 connect(networkSelect, SIGNAL(activated(const QString&)), this,
102 SLOT(selectNetwork(const QString&)));
103 connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
104 connect(editNetworkButton, SIGNAL(clicked()), this,
105 SLOT(editListedNetwork()));
106 connect(removeNetworkButton, SIGNAL(clicked()), this,
107 SLOT(removeListedNetwork()));
108 connect(networkList, SIGNAL(itemSelectionChanged()), this,
109 SLOT(updateNetworkDisabledStatus()));
110 connect(enableRadioButton, SIGNAL(toggled(bool)), this,
111 SLOT(enableListedNetwork(bool)));
112 connect(disableRadioButton, SIGNAL(toggled(bool)), this,
113 SLOT(disableListedNetwork(bool)));
114 connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan()));
115 connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
116 this, SLOT(editListedNetwork()));
117 connect(wpaguiTab, SIGNAL(currentChanged(int)), this,
118 SLOT(tabChanged(int)));
119 connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc()));
120 connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin()));
121 connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this,
122 SLOT(wpsApPinChanged(const QString &)));
123 connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin()));
137 ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
138 signalMeterInterval = 0;
142 #ifndef QT_NO_SESSIONMANAGER
143 if (app->isSessionRestored()) {
144 QSettings settings("wpa_supplicant", "wpa_gui");
145 settings.beginGroup("state");
146 if (app->sessionId().compare(settings.value("session_id").
148 startInTray = settings.value("in_tray").toBool();
153 if (QSystemTrayIcon::isSystemTrayAvailable())
154 createTrayIcon(startInTray);
158 connectedToService = false;
159 textStatus->setText(tr("connecting to wpa_supplicant"));
160 timer = new QTimer(this);
161 connect(timer, SIGNAL(timeout()), SLOT(ping()));
162 timer->setSingleShot(FALSE);
165 signalMeterTimer = new QTimer(this);
166 signalMeterTimer->setInterval(signalMeterInterval);
167 connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate()));
169 if (openCtrlConnection(ctrl_iface) < 0) {
170 debug("Failed to open control connection to "
175 networkMayHaveChanged = true;
185 wpa_ctrl_detach(monitor_conn);
186 wpa_ctrl_close(monitor_conn);
190 wpa_ctrl_close(ctrl_conn);
227 free(ctrl_iface_dir);
228 ctrl_iface_dir = NULL;
232 void WpaGui::languageChange()
238 void WpaGui::parse_argv()
242 c = getopt(qApp->argc(), qApp->argv(), "i:m:p:tq");
248 ctrl_iface = strdup(optarg);
251 signalMeterInterval = atoi(optarg) * 1000;
254 free(ctrl_iface_dir);
255 ctrl_iface_dir = strdup(optarg);
268 int WpaGui::openCtrlConnection(const char *ifname)
272 char buf[2048], *pos, *pos2;
276 if (ifname != ctrl_iface) {
278 ctrl_iface = strdup(ifname);
281 #ifdef CONFIG_CTRL_IFACE_UDP
283 ctrl_iface = strdup("udp");
284 #endif /* CONFIG_CTRL_IFACE_UDP */
285 #ifdef CONFIG_CTRL_IFACE_UNIX
287 DIR *dir = opendir(ctrl_iface_dir);
291 while ((dent = readdir(dir))) {
292 #ifdef _DIRENT_HAVE_D_TYPE
293 /* Skip the file if it is not a socket.
294 * Also accept DT_UNKNOWN (0) in case
295 * the C library or underlying file
296 * system does not support d_type. */
297 if (dent->d_type != DT_SOCK &&
298 dent->d_type != DT_UNKNOWN)
300 #endif /* _DIRENT_HAVE_D_TYPE */
302 if (strcmp(dent->d_name, ".") == 0 ||
303 strcmp(dent->d_name, "..") == 0)
305 debug("Selected interface '%s'",
307 ctrl_iface = strdup(dent->d_name);
312 #endif /* CONFIG_CTRL_IFACE_UNIX */
313 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
314 struct wpa_ctrl *ctrl;
320 ctrl = wpa_ctrl_open(NULL);
322 len = sizeof(buf) - 1;
323 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
326 connectedToService = true;
328 pos = strchr(buf, '\n');
331 ctrl_iface = strdup(buf);
333 wpa_ctrl_close(ctrl);
335 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
338 if (ctrl_iface == NULL) {
339 #ifdef CONFIG_NATIVE_WINDOWS
340 static bool first = true;
341 if (first && !serviceRunning()) {
343 if (QMessageBox::warning(
345 tr("wpa_supplicant service is not "
347 "Do you want to start it?"),
348 QMessageBox::Yes | QMessageBox::No) ==
352 #endif /* CONFIG_NATIVE_WINDOWS */
356 #ifdef CONFIG_CTRL_IFACE_UNIX
357 flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
358 cfile = (char *) malloc(flen);
361 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
362 #else /* CONFIG_CTRL_IFACE_UNIX */
363 flen = strlen(ctrl_iface) + 1;
364 cfile = (char *) malloc(flen);
367 snprintf(cfile, flen, "%s", ctrl_iface);
368 #endif /* CONFIG_CTRL_IFACE_UNIX */
371 wpa_ctrl_close(ctrl_conn);
378 wpa_ctrl_detach(monitor_conn);
379 wpa_ctrl_close(monitor_conn);
383 debug("Trying to connect to '%s'", cfile);
384 ctrl_conn = wpa_ctrl_open(cfile);
385 if (ctrl_conn == NULL) {
389 monitor_conn = wpa_ctrl_open(cfile);
391 if (monitor_conn == NULL) {
392 wpa_ctrl_close(ctrl_conn);
395 if (wpa_ctrl_attach(monitor_conn)) {
396 debug("Failed to attach to wpa_supplicant");
397 wpa_ctrl_close(monitor_conn);
399 wpa_ctrl_close(ctrl_conn);
404 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
405 msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
406 QSocketNotifier::Read, this);
407 connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
410 adapterSelect->clear();
411 adapterSelect->addItem(ctrl_iface);
412 adapterSelect->setCurrentIndex(0);
414 len = sizeof(buf) - 1;
415 if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
420 pos2 = strchr(pos, '\n');
423 if (strcmp(pos, ctrl_iface) != 0)
424 adapterSelect->addItem(pos);
432 len = sizeof(buf) - 1;
433 if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len,
438 QStringList types = res.split(QChar(' '));
439 bool wps = types.contains("WSC");
440 actionWPS->setEnabled(wps);
441 wpsTab->setEnabled(wps);
442 wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps);
449 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
453 if (ctrl_conn == NULL)
455 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL);
457 debug("'%s' command timed out.", cmd);
459 debug("'%s' command failed.", cmd);
465 QString WpaGui::wpaStateTranslate(char *state)
467 if (!strcmp(state, "DISCONNECTED"))
468 return tr("Disconnected");
469 else if (!strcmp(state, "INACTIVE"))
470 return tr("Inactive");
471 else if (!strcmp(state, "SCANNING"))
472 return tr("Scanning");
473 else if (!strcmp(state, "AUTHENTICATING"))
474 return tr("Authenticating");
475 else if (!strcmp(state, "ASSOCIATING"))
476 return tr("Associating");
477 else if (!strcmp(state, "ASSOCIATED"))
478 return tr("Associated");
479 else if (!strcmp(state, "4WAY_HANDSHAKE"))
480 return tr("4-Way Handshake");
481 else if (!strcmp(state, "GROUP_HANDSHAKE"))
482 return tr("Group Handshake");
483 else if (!strcmp(state, "COMPLETED"))
484 return tr("Completed");
486 return tr("Unknown");
490 void WpaGui::updateStatus()
492 char buf[2048], *start, *end, *pos;
495 pingsToStatusUpdate = 10;
497 len = sizeof(buf) - 1;
498 if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
499 textStatus->setText(tr("Could not get status from "
501 textAuthentication->clear();
502 textEncryption->clear();
505 textIpAddress->clear();
506 updateTrayToolTip(tr("no status information"));
507 updateTrayIcon(TrayIconOffline);
508 signalMeterTimer->stop();
510 #ifdef CONFIG_NATIVE_WINDOWS
511 static bool first = true;
512 if (first && connectedToService &&
513 (ctrl_iface == NULL || *ctrl_iface == '\0')) {
515 if (QMessageBox::information(
517 tr("No network interfaces in use.\n"
518 "Would you like to add one?"),
519 QMessageBox::Yes | QMessageBox::No) ==
523 #endif /* CONFIG_NATIVE_WINDOWS */
529 bool auth_updated = false, ssid_updated = false;
530 bool bssid_updated = false, ipaddr_updated = false;
531 bool status_updated = false;
532 char *pairwise_cipher = NULL, *group_cipher = NULL;
538 end = strchr(start, '\n');
542 while (end[0] && end[1])
547 pos = strchr(start, '=');
550 if (strcmp(start, "bssid") == 0) {
551 bssid_updated = true;
552 textBssid->setText(pos);
553 } else if (strcmp(start, "ssid") == 0) {
555 textSsid->setText(pos);
556 updateTrayToolTip(pos + tr(" (associated)"));
557 if (!signalMeterInterval) {
558 /* if signal meter is not enabled show
559 * full signal strength */
560 updateTrayIcon(TrayIconSignalExcellent);
562 } else if (strcmp(start, "ip_address") == 0) {
563 ipaddr_updated = true;
564 textIpAddress->setText(pos);
565 } else if (strcmp(start, "wpa_state") == 0) {
566 status_updated = true;
567 textStatus->setText(wpaStateTranslate(pos));
568 } else if (strcmp(start, "key_mgmt") == 0) {
570 textAuthentication->setText(pos);
571 /* TODO: could add EAP status to this */
572 } else if (strcmp(start, "pairwise_cipher") == 0) {
573 pairwise_cipher = pos;
574 } else if (strcmp(start, "group_cipher") == 0) {
576 } else if (strcmp(start, "mode") == 0) {
585 if (status_updated && mode)
586 textStatus->setText(textStatus->text() + " (" + mode + ")");
588 if (pairwise_cipher || group_cipher) {
590 if (pairwise_cipher && group_cipher &&
591 strcmp(pairwise_cipher, group_cipher) != 0) {
592 encr.append(pairwise_cipher);
594 encr.append(group_cipher);
595 } else if (pairwise_cipher) {
596 encr.append(pairwise_cipher);
598 encr.append(group_cipher);
599 encr.append(" [group key only]");
601 textEncryption->setText(encr);
603 textEncryption->clear();
605 if (signalMeterInterval) {
607 * Handle signal meter service. When network is not associated,
608 * deactivate timer, otherwise keep it going. Tray icon has to
609 * be initialized here, because of the initial delay of the
613 if (!signalMeterTimer->isActive()) {
614 updateTrayIcon(TrayIconConnected);
615 signalMeterTimer->start();
618 signalMeterTimer->stop();
625 textAuthentication->clear();
628 updateTrayToolTip(tr("(not-associated)"));
629 updateTrayIcon(TrayIconOffline);
634 textIpAddress->clear();
638 void WpaGui::updateNetworks()
640 char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
642 int first_active = -1;
643 int was_selected = -1;
644 bool current = false;
646 if (!networkMayHaveChanged)
649 if (networkList->currentRow() >= 0)
650 was_selected = networkList->currentRow();
652 networkSelect->clear();
653 networkList->clear();
655 if (ctrl_conn == NULL)
658 len = sizeof(buf) - 1;
659 if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
663 start = strchr(buf, '\n');
670 end = strchr(start, '\n');
674 while (end[0] && end[1])
680 ssid = strchr(id, '\t');
684 bssid = strchr(ssid, '\t');
688 flags = strchr(bssid, '\t');
693 if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) {
701 network.append(": ");
702 network.append(ssid);
703 networkSelect->addItem(network);
704 networkList->addItem(network);
706 if (strstr(flags, "[CURRENT]")) {
707 networkSelect->setCurrentIndex(networkSelect->count() -
710 } else if (first_active < 0 &&
711 strstr(flags, "[DISABLED]") == NULL)
712 first_active = networkSelect->count() - 1;
719 if (networkSelect->count() > 1)
720 networkSelect->addItem(tr("Select any network"));
722 if (!current && first_active >= 0)
723 networkSelect->setCurrentIndex(first_active);
725 if (was_selected >= 0 && networkList->count() > 0) {
726 if (was_selected < networkList->count())
727 networkList->setCurrentRow(was_selected);
729 networkList->setCurrentRow(networkList->count() - 1);
732 networkList->setCurrentRow(networkSelect->currentIndex());
734 networkMayHaveChanged = false;
738 void WpaGui::helpIndex()
744 void WpaGui::helpContents()
746 debug("helpContents");
750 void WpaGui::helpAbout()
752 QMessageBox::about(this, "wpa_gui for wpa_supplicant",
753 "Copyright (c) 2003-2013,\n"
754 "Jouni Malinen <j@w1.fi>\n"
755 "and contributors.\n"
757 "This software may be distributed under\n"
758 "the terms of the BSD license.\n"
759 "See README for more details.\n"
761 "This product includes software developed\n"
762 "by the OpenSSL Project for use in the\n"
763 "OpenSSL Toolkit (http://www.openssl.org/)\n");
767 void WpaGui::disconnect()
770 size_t reply_len = sizeof(reply);
771 ctrlRequest("DISCONNECT", reply, &reply_len);
783 scanres = new ScanResults();
786 scanres->setWpaGui(this);
792 void WpaGui::eventHistory()
799 eh = new EventHistory();
813 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
815 * QSocketNotifier cannot be used with Windows named pipes, so use a
816 * timer to check for received messages for now. This could be
817 * optimized be doing something specific to named pipes or Windows
818 * events, but it is not clear what would be the best way of doing that
822 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
824 if (scanres && !scanres->isVisible()) {
829 if (eh && !eh->isVisible()) {
834 if (udr && !udr->isVisible()) {
839 len = sizeof(buf) - 1;
840 if (ctrlRequest("PING", buf, &len) < 0) {
841 debug("PING failed - trying to reconnect");
842 if (openCtrlConnection(ctrl_iface) >= 0) {
843 debug("Reconnected successfully");
844 pingsToStatusUpdate = 0;
848 pingsToStatusUpdate--;
849 if (pingsToStatusUpdate <= 0) {
854 #ifndef CONFIG_CTRL_IFACE_NAMED_PIPE
855 /* Use less frequent pings and status updates when the main window is
856 * hidden (running in taskbar). */
857 int interval = isHidden() ? 5000 : 1000;
858 if (timer->interval() != interval)
859 timer->setInterval(interval);
860 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
864 void WpaGui::signalMeterUpdate()
867 size_t reply_len = sizeof(reply);
871 ctrlRequest("SIGNAL_POLL", reply, &reply_len);
873 /* In order to eliminate signal strength fluctuations, try
874 * to obtain averaged RSSI value in the first place. */
875 if ((rssi = strstr(reply, "AVG_RSSI=")) != NULL)
876 rssi_value = atoi(&rssi[sizeof("AVG_RSSI")]);
877 else if ((rssi = strstr(reply, "RSSI=")) != NULL)
878 rssi_value = atoi(&rssi[sizeof("RSSI")]);
880 debug("Failed to get RSSI value");
881 updateTrayIcon(TrayIconSignalNone);
885 debug("RSSI value: %d", rssi_value);
888 * NOTE: The code below assumes, that the unit of the value returned
889 * by the SIGNAL POLL request is dBm. It might not be true for all
890 * wpa_supplicant drivers.
894 * Calibration is based on "various Internet sources". Nonetheless,
895 * it seems to be compatible with the Windows 8.1 strength meter -
896 * tested on Intel Centrino Advanced-N 6235.
898 if (rssi_value >= -60)
899 updateTrayIcon(TrayIconSignalExcellent);
900 else if (rssi_value >= -68)
901 updateTrayIcon(TrayIconSignalGood);
902 else if (rssi_value >= -76)
903 updateTrayIcon(TrayIconSignalOk);
904 else if (rssi_value >= -84)
905 updateTrayIcon(TrayIconSignalWeak);
907 updateTrayIcon(TrayIconSignalNone);
911 static int str_match(const char *a, const char *b)
913 return strncmp(a, b, strlen(b)) == 0;
917 void WpaGui::processMsg(char *msg)
919 char *pos = msg, *pos2;
925 priority = atoi(pos);
926 pos = strchr(pos, '>');
933 WpaMsg wm(pos, priority);
937 peers->event_notify(wm);
939 while (msgs.count() > 100)
942 /* Update last message with truncated version of the event */
943 if (strncmp(pos, "CTRL-", 5) == 0) {
944 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
951 QString lastmsg = pos2;
952 lastmsg.truncate(40);
953 textLastMessage->setText(lastmsg);
955 pingsToStatusUpdate = 0;
956 networkMayHaveChanged = true;
958 if (str_match(pos, WPA_CTRL_REQ))
959 processCtrlReq(pos + strlen(WPA_CTRL_REQ));
960 else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres)
961 scanres->updateResults();
962 else if (str_match(pos, WPA_EVENT_DISCONNECTED))
963 showTrayMessage(QSystemTrayIcon::Information, 3,
964 tr("Disconnected from network."));
965 else if (str_match(pos, WPA_EVENT_CONNECTED)) {
966 showTrayMessage(QSystemTrayIcon::Information, 3,
967 tr("Connection to network established."));
968 QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus()));
970 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) {
971 wpsStatusText->setText(tr("WPS AP in active PBC mode found"));
972 if (textStatus->text() == "INACTIVE" ||
973 textStatus->text() == "DISCONNECTED")
974 wpaguiTab->setCurrentWidget(wpsTab);
975 wpsInstructions->setText(tr("Press the PBC button on the "
976 "screen to start registration"));
977 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) {
978 wpsStatusText->setText(tr("WPS AP with recently selected "
980 if (textStatus->text() == "INACTIVE" ||
981 textStatus->text() == "DISCONNECTED")
982 wpaguiTab->setCurrentWidget(wpsTab);
983 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) {
984 showTrayMessage(QSystemTrayIcon::Information, 3,
985 "Wi-Fi Protected Setup (WPS) AP\n"
986 "indicating this client is authorized.");
987 wpsStatusText->setText("WPS AP indicating this client is "
989 if (textStatus->text() == "INACTIVE" ||
990 textStatus->text() == "DISCONNECTED")
991 wpaguiTab->setCurrentWidget(wpsTab);
992 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
993 wpsStatusText->setText(tr("WPS AP detected"));
994 } else if (str_match(pos, WPS_EVENT_OVERLAP)) {
995 wpsStatusText->setText(tr("PBC mode overlap detected"));
996 wpsInstructions->setText(tr("More than one AP is currently in "
997 "active WPS PBC mode. Wait couple "
998 "of minutes and try again"));
999 wpaguiTab->setCurrentWidget(wpsTab);
1000 } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) {
1001 wpsStatusText->setText(tr("Network configuration received"));
1002 wpaguiTab->setCurrentWidget(wpsTab);
1003 } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) {
1004 if (strstr(pos, "(WSC)"))
1005 wpsStatusText->setText(tr("Registration started"));
1006 } else if (str_match(pos, WPS_EVENT_M2D)) {
1007 wpsStatusText->setText(tr("Registrar does not yet know PIN"));
1008 } else if (str_match(pos, WPS_EVENT_FAIL)) {
1009 wpsStatusText->setText(tr("Registration failed"));
1010 } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
1011 wpsStatusText->setText(tr("Registration succeeded"));
1016 void WpaGui::processCtrlReq(const char *req)
1022 udr = new UserDataRequest();
1025 if (udr->setParams(this, req) < 0) {
1035 void WpaGui::receiveMsgs()
1040 while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
1041 len = sizeof(buf) - 1;
1042 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
1050 void WpaGui::connectB()
1053 size_t reply_len = sizeof(reply);
1054 ctrlRequest("REASSOCIATE", reply, &reply_len);
1058 void WpaGui::selectNetwork( const QString &sel )
1062 size_t reply_len = sizeof(reply);
1064 if (cmd.contains(QRegExp("^\\d+:")))
1065 cmd.truncate(cmd.indexOf(':'));
1068 cmd.prepend("SELECT_NETWORK ");
1069 ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1075 void WpaGui::enableNetwork(const QString &sel)
1079 size_t reply_len = sizeof(reply);
1081 if (cmd.contains(QRegExp("^\\d+:")))
1082 cmd.truncate(cmd.indexOf(':'));
1083 else if (!cmd.startsWith("all")) {
1084 debug("Invalid editNetwork '%s'",
1085 cmd.toAscii().constData());
1088 cmd.prepend("ENABLE_NETWORK ");
1089 ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1094 void WpaGui::disableNetwork(const QString &sel)
1098 size_t reply_len = sizeof(reply);
1100 if (cmd.contains(QRegExp("^\\d+:")))
1101 cmd.truncate(cmd.indexOf(':'));
1102 else if (!cmd.startsWith("all")) {
1103 debug("Invalid editNetwork '%s'",
1104 cmd.toAscii().constData());
1107 cmd.prepend("DISABLE_NETWORK ");
1108 ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1113 void WpaGui::editNetwork(const QString &sel)
1118 if (cmd.contains(QRegExp("^\\d+:"))) {
1119 cmd.truncate(cmd.indexOf(':'));
1123 NetworkConfig *nc = new NetworkConfig();
1126 nc->setWpaGui(this);
1129 nc->paramsFromConfig(id);
1138 void WpaGui::editSelectedNetwork()
1140 if (networkSelect->count() < 1) {
1141 QMessageBox::information(
1142 this, tr("No Networks"),
1143 tr("There are no networks to edit.\n"));
1146 QString sel(networkSelect->currentText());
1151 void WpaGui::editListedNetwork()
1153 if (networkList->currentRow() < 0) {
1154 QMessageBox::information(this, tr("Select A Network"),
1155 tr("Select a network from the list to"
1159 QString sel(networkList->currentItem()->text());
1164 void WpaGui::triggerUpdate()
1167 networkMayHaveChanged = true;
1172 void WpaGui::addNetwork()
1174 NetworkConfig *nc = new NetworkConfig();
1177 nc->setWpaGui(this);
1184 void WpaGui::removeNetwork(const QString &sel)
1188 size_t reply_len = sizeof(reply);
1190 if (cmd.contains(QRegExp("^\\d+:")))
1191 cmd.truncate(cmd.indexOf(':'));
1192 else if (!cmd.startsWith("all")) {
1193 debug("Invalid editNetwork '%s'",
1194 cmd.toAscii().constData());
1197 cmd.prepend("REMOVE_NETWORK ");
1198 ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1203 void WpaGui::removeSelectedNetwork()
1205 if (networkSelect->count() < 1) {
1206 QMessageBox::information(this, tr("No Networks"),
1207 tr("There are no networks to remove."
1211 QString sel(networkSelect->currentText());
1216 void WpaGui::removeListedNetwork()
1218 if (networkList->currentRow() < 0) {
1219 QMessageBox::information(this, tr("Select A Network"),
1220 tr("Select a network from the list "
1221 "to remove it.\n"));
1224 QString sel(networkList->currentItem()->text());
1229 void WpaGui::enableAllNetworks()
1236 void WpaGui::disableAllNetworks()
1239 disableNetwork(sel);
1243 void WpaGui::removeAllNetworks()
1250 int WpaGui::getNetworkDisabled(const QString &sel)
1254 size_t reply_len = sizeof(reply) - 1;
1255 int pos = cmd.indexOf(':');
1257 debug("Invalid getNetworkDisabled '%s'",
1258 cmd.toAscii().constData());
1262 cmd.prepend("GET_NETWORK ");
1263 cmd.append(" disabled");
1265 if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0
1266 && reply_len >= 1) {
1267 reply[reply_len] = '\0';
1268 if (!str_match(reply, "FAIL"))
1276 void WpaGui::updateNetworkDisabledStatus()
1278 if (networkList->currentRow() < 0)
1281 QString sel(networkList->currentItem()->text());
1283 switch (getNetworkDisabled(sel)) {
1285 if (!enableRadioButton->isChecked())
1286 enableRadioButton->setChecked(true);
1289 if (!disableRadioButton->isChecked())
1290 disableRadioButton->setChecked(true);
1296 void WpaGui::enableListedNetwork(bool enabled)
1298 if (networkList->currentRow() < 0 || !enabled)
1301 QString sel(networkList->currentItem()->text());
1303 if (getNetworkDisabled(sel) == 1)
1308 void WpaGui::disableListedNetwork(bool disabled)
1310 if (networkList->currentRow() < 0 || !disabled)
1313 QString sel(networkList->currentItem()->text());
1315 if (getNetworkDisabled(sel) == 0)
1316 disableNetwork(sel);
1320 void WpaGui::saveConfig()
1325 len = sizeof(buf) - 1;
1326 ctrlRequest("SAVE_CONFIG", buf, &len);
1330 if (str_match(buf, "FAIL"))
1331 QMessageBox::warning(
1332 this, tr("Failed to save configuration"),
1333 tr("The configuration could not be saved.\n"
1335 "The update_config=1 configuration option\n"
1336 "must be used for configuration saving to\n"
1337 "be permitted.\n"));
1339 QMessageBox::information(
1340 this, tr("Saved configuration"),
1341 tr("The current configuration was saved."
1346 void WpaGui::selectAdapter( const QString & sel )
1348 if (openCtrlConnection(sel.toAscii().constData()) < 0)
1349 debug("Failed to open control connection to "
1356 void WpaGui::createTrayIcon(bool trayOnly)
1358 QApplication::setQuitOnLastWindowClosed(false);
1360 tray_icon = new QSystemTrayIcon(this);
1361 updateTrayIcon(TrayIconOffline);
1364 SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
1365 this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
1367 ackTrayIcon = false;
1369 tray_menu = new QMenu(this);
1371 disconnectAction = new QAction(tr("&Disconnect"), this);
1372 reconnectAction = new QAction(tr("Re&connect"), this);
1373 connect(disconnectAction, SIGNAL(triggered()), this,
1374 SLOT(disconnect()));
1375 connect(reconnectAction, SIGNAL(triggered()), this,
1377 tray_menu->addAction(disconnectAction);
1378 tray_menu->addAction(reconnectAction);
1379 tray_menu->addSeparator();
1381 eventAction = new QAction(tr("&Event History"), this);
1382 scanAction = new QAction(tr("Scan &Results"), this);
1383 statAction = new QAction(tr("S&tatus"), this);
1384 connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
1385 connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
1386 connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
1387 tray_menu->addAction(eventAction);
1388 tray_menu->addAction(scanAction);
1389 tray_menu->addAction(statAction);
1390 tray_menu->addSeparator();
1392 showAction = new QAction(tr("&Show Window"), this);
1393 hideAction = new QAction(tr("&Hide Window"), this);
1394 quitAction = new QAction(tr("&Quit"), this);
1395 connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
1396 connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
1397 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1398 tray_menu->addAction(showAction);
1399 tray_menu->addAction(hideAction);
1400 tray_menu->addSeparator();
1401 tray_menu->addAction(quitAction);
1403 tray_icon->setContextMenu(tray_menu);
1413 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
1414 const QString & msg)
1416 if (!QSystemTrayIcon::supportsMessages())
1419 if (isVisible() || !tray_icon || !tray_icon->isVisible() || quietMode)
1422 tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
1426 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
1429 /* use close() here instead of hide() and allow the
1430 * custom closeEvent handler take care of children */
1431 case QSystemTrayIcon::Trigger:
1441 case QSystemTrayIcon::MiddleClick:
1450 void WpaGui::showTrayStatus()
1455 len = sizeof(buf) - 1;
1456 if (ctrlRequest("STATUS", buf, &len) < 0)
1460 QString msg, status(buf);
1462 QStringList lines = status.split(QRegExp("\\n"));
1463 for (QStringList::Iterator it = lines.begin();
1464 it != lines.end(); it++) {
1465 int pos = (*it).indexOf('=') + 1;
1469 if ((*it).startsWith("bssid="))
1470 msg.append("BSSID:\t" + (*it).mid(pos) + "\n");
1471 else if ((*it).startsWith("ssid="))
1472 msg.append("SSID: \t" + (*it).mid(pos) + "\n");
1473 else if ((*it).startsWith("pairwise_cipher="))
1474 msg.append("PAIR: \t" + (*it).mid(pos) + "\n");
1475 else if ((*it).startsWith("group_cipher="))
1476 msg.append("GROUP:\t" + (*it).mid(pos) + "\n");
1477 else if ((*it).startsWith("key_mgmt="))
1478 msg.append("AUTH: \t" + (*it).mid(pos) + "\n");
1479 else if ((*it).startsWith("wpa_state="))
1480 msg.append("STATE:\t" + (*it).mid(pos) + "\n");
1481 else if ((*it).startsWith("ip_address="))
1482 msg.append("IP: \t" + (*it).mid(pos) + "\n");
1483 else if ((*it).startsWith("Supplicant PAE state="))
1484 msg.append("PAE: \t" + (*it).mid(pos) + "\n");
1485 else if ((*it).startsWith("EAP state="))
1486 msg.append("EAP: \t" + (*it).mid(pos) + "\n");
1490 showTrayMessage(QSystemTrayIcon::Information, 10, msg);
1494 void WpaGui::updateTrayToolTip(const QString &msg)
1497 tray_icon->setToolTip(msg);
1501 void WpaGui::updateTrayIcon(TrayIconType type)
1503 if (!tray_icon || currentIconType == type)
1506 QIcon fallback_icon;
1509 if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
1510 fallback_icon = QIcon(":/icons/wpa_gui.svg");
1512 fallback_icon = QIcon(":/icons/wpa_gui.png");
1515 case TrayIconOffline:
1516 names << "network-wireless-offline-symbolic"
1517 << "network-wireless-offline"
1518 << "network-wireless-signal-none-symbolic"
1519 << "network-wireless-signal-none";
1521 case TrayIconAcquiring:
1522 names << "network-wireless-acquiring-symbolic"
1523 << "network-wireless-acquiring";
1525 case TrayIconConnected:
1526 names << "network-wireless-connected-symbolic"
1527 << "network-wireless-connected";
1529 case TrayIconSignalNone:
1530 names << "network-wireless-signal-none-symbolic"
1531 << "network-wireless-signal-none";
1533 case TrayIconSignalWeak:
1534 names << "network-wireless-signal-weak-symbolic"
1535 << "network-wireless-signal-weak";
1537 case TrayIconSignalOk:
1538 names << "network-wireless-signal-ok-symbolic"
1539 << "network-wireless-signal-ok";
1541 case TrayIconSignalGood:
1542 names << "network-wireless-signal-good-symbolic"
1543 << "network-wireless-signal-good";
1545 case TrayIconSignalExcellent:
1546 names << "network-wireless-signal-excellent-symbolic"
1547 << "network-wireless-signal-excellent";
1551 currentIconType = type;
1552 tray_icon->setIcon(loadThemedIcon(names, fallback_icon));
1556 QIcon WpaGui::loadThemedIcon(const QStringList &names,
1557 const QIcon &fallback)
1561 for (QStringList::ConstIterator it = names.begin();
1562 it != names.end(); it++) {
1563 icon = QIcon::fromTheme(*it);
1572 void WpaGui::closeEvent(QCloseEvent *event)
1598 if (tray_icon && !ackTrayIcon) {
1599 /* give user a visual hint that the tray icon exists */
1600 if (QSystemTrayIcon::supportsMessages()) {
1602 showTrayMessage(QSystemTrayIcon::Information, 3,
1604 tr(" will keep running in "
1605 "the system tray."));
1607 QMessageBox::information(this, qAppName() +
1609 tr("The program will keep "
1610 "running in the system "
1620 void WpaGui::wpsDialog()
1622 wpaguiTab->setCurrentWidget(wpsTab);
1626 void WpaGui::peersDialog()
1633 peers = new Peers();
1636 peers->setWpaGui(this);
1642 void WpaGui::tabChanged(int index)
1650 wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1651 if (bssFromScan.isEmpty())
1652 wpsApPinButton->setEnabled(false);
1656 void WpaGui::wpsPbc()
1659 size_t reply_len = sizeof(reply);
1661 if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
1664 wpsPinEdit->setEnabled(false);
1665 if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) {
1666 wpsInstructions->setText(tr("Press the push button on the AP to "
1667 "start the PBC mode."));
1669 wpsInstructions->setText(tr("If you have not yet done so, press "
1670 "the push button on the AP to start "
1673 wpsStatusText->setText(tr("Waiting for Registrar"));
1678 void WpaGui::wpsGeneratePin()
1681 size_t reply_len = sizeof(reply) - 1;
1683 if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
1686 reply[reply_len] = '\0';
1688 wpsPinEdit->setText(reply);
1689 wpsPinEdit->setEnabled(true);
1690 wpsInstructions->setText(tr("Enter the generated PIN into the Registrar "
1691 "(either the internal one in the AP or an "
1693 wpsStatusText->setText(tr("Waiting for Registrar"));
1698 void WpaGui::setBssFromScan(const QString &bssid)
1700 bssFromScan = bssid;
1701 wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1702 wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
1703 wpsStatusText->setText(tr("WPS AP selected from scan results"));
1704 wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., "
1705 "from a label in the device, enter the eight "
1706 "digit AP PIN and click Use AP PIN button."));
1710 void WpaGui::wpsApPinChanged(const QString &text)
1712 wpsApPinButton->setEnabled(text.length() == 8);
1716 void WpaGui::wpsApPin()
1719 size_t reply_len = sizeof(reply);
1721 QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
1722 if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0)
1725 wpsStatusText->setText(tr("Waiting for AP/Enrollee"));
1730 void WpaGui::stopWpsRun(bool success)
1733 wpsStatusText->setText(success ? tr("Connected to the network") :
1736 wpsStatusText->setText("");
1737 wpsPinEdit->setEnabled(false);
1738 wpsInstructions->setText("");
1741 wpsApPinEdit->setEnabled(false);
1742 wpsApPinButton->setEnabled(false);
1746 #ifdef CONFIG_NATIVE_WINDOWS
1749 #define WPASVC_NAME TEXT("wpasvc")
1752 class ErrorMsg : public QMessageBox {
1754 ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
1755 void showMsg(QString msg);
1760 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
1761 QMessageBox(parent), err(last_err)
1763 setWindowTitle(tr("wpa_gui error"));
1764 setIcon(QMessageBox::Warning);
1767 void ErrorMsg::showMsg(QString msg)
1772 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1773 FORMAT_MESSAGE_FROM_SYSTEM,
1774 NULL, err, 0, (LPTSTR) (void *) &buf,
1776 QString msg = QString::fromWCharArray(buf);
1777 setInformativeText(QString("[%1] %2").arg(err).arg(msg));
1780 setInformativeText(QString("[%1]").arg(err));
1787 void WpaGui::startService()
1791 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1793 ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
1797 svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
1799 ErrorMsg(this).showMsg(tr("OpenService failed"));
1800 CloseServiceHandle(scm);
1804 if (!StartService(svc, 0, NULL)) {
1805 ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant "
1809 CloseServiceHandle(svc);
1810 CloseServiceHandle(scm);
1814 void WpaGui::stopService()
1817 SERVICE_STATUS status;
1819 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1821 ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
1825 svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
1827 ErrorMsg(this).showMsg(tr("OpenService failed"));
1828 CloseServiceHandle(scm);
1832 if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
1833 ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant "
1837 CloseServiceHandle(svc);
1838 CloseServiceHandle(scm);
1842 bool WpaGui::serviceRunning()
1845 SERVICE_STATUS status;
1846 bool running = false;
1848 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1850 debug("OpenSCManager failed: %d", (int) GetLastError());
1854 svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
1856 debug("OpenService failed: %d", (int) GetLastError());
1857 CloseServiceHandle(scm);
1861 if (QueryServiceStatus(svc, &status)) {
1862 if (status.dwCurrentState != SERVICE_STOPPED)
1866 CloseServiceHandle(svc);
1867 CloseServiceHandle(scm);
1872 #endif /* CONFIG_NATIVE_WINDOWS */
1875 void WpaGui::addInterface()
1881 add_iface = new AddInterface(this, this);
1887 #ifndef QT_NO_SESSIONMANAGER
1888 void WpaGui::saveState()
1890 QSettings settings("wpa_supplicant", "wpa_gui");
1891 settings.beginGroup("state");
1892 settings.setValue("session_id", app->sessionId());
1893 settings.setValue("in_tray", inTray);
1894 settings.endGroup();