Home | History | Annotate | Download | only in wpa_gui-qt4
      1 /*
      2  * wpa_gui - WpaGui class
      3  * Copyright (c) 2005-2011, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #ifdef CONFIG_NATIVE_WINDOWS
     10 #include <windows.h>
     11 #endif /* CONFIG_NATIVE_WINDOWS */
     12 
     13 #include <cstdio>
     14 #include <unistd.h>
     15 #include <QMessageBox>
     16 #include <QCloseEvent>
     17 #include <QImageReader>
     18 #include <QSettings>
     19 
     20 #include "wpagui.h"
     21 #include "dirent.h"
     22 #include "common/wpa_ctrl.h"
     23 #include "userdatarequest.h"
     24 #include "networkconfig.h"
     25 
     26 
     27 #ifndef QT_NO_DEBUG
     28 #define debug(M, ...) qDebug("DEBUG %d: " M, __LINE__, ##__VA_ARGS__)
     29 #else
     30 #define debug(M, ...) do {} while (0)
     31 #endif
     32 
     33 
     34 WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *,
     35 	       Qt::WindowFlags)
     36 	: QMainWindow(parent), app(_app)
     37 {
     38 	setupUi(this);
     39 	this->setWindowFlags(Qt::Dialog);
     40 
     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);
     46 
     47 	fileStartServiceAction = new QAction(this);
     48 	fileStartServiceAction->setObjectName("Start Service");
     49 	fileStartServiceAction->setIconText(tr("Start Service"));
     50 	fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction);
     51 
     52 	connect(fileStartServiceAction, SIGNAL(triggered()), this,
     53 		SLOT(startService()));
     54 	connect(fileStopServiceAction, SIGNAL(triggered()), this,
     55 		SLOT(stopService()));
     56 
     57 	addInterfaceAction = new QAction(this);
     58 	addInterfaceAction->setIconText(tr("Add Interface"));
     59 	fileMenu->insertAction(fileStartServiceAction, addInterfaceAction);
     60 
     61 	connect(addInterfaceAction, SIGNAL(triggered()), this,
     62 		SLOT(addInterface()));
     63 #endif /* CONFIG_NATIVE_WINDOWS */
     64 
     65 	(void) statusBar();
     66 
     67 	/*
     68 	 * Disable WPS tab by default; it will be enabled if wpa_supplicant is
     69 	 * built with WPS support.
     70 	 */
     71 	wpsTab->setEnabled(false);
     72 	wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false);
     73 
     74 	connect(fileEventHistoryAction, SIGNAL(triggered()), this,
     75 		SLOT(eventHistory()));
     76 	connect(fileSaveConfigAction, SIGNAL(triggered()), this,
     77 		SLOT(saveConfig()));
     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,
     82 		SLOT(addNetwork()));
     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()));
    125 
    126 	eh = NULL;
    127 	scanres = NULL;
    128 	peers = NULL;
    129 	add_iface = NULL;
    130 	udr = NULL;
    131 	tray_icon = NULL;
    132 	startInTray = false;
    133 	quietMode = false;
    134 	ctrl_iface = NULL;
    135 	ctrl_conn = NULL;
    136 	monitor_conn = NULL;
    137 	msgNotifier = NULL;
    138 	ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
    139 	signalMeterInterval = 0;
    140 
    141 	parse_argv();
    142 
    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").
    148 					     toString()) == 0)
    149 			startInTray = settings.value("in_tray").toBool();
    150 		settings.endGroup();
    151 	}
    152 #endif
    153 
    154 	if (QSystemTrayIcon::isSystemTrayAvailable())
    155 		createTrayIcon(startInTray);
    156 	else
    157 		show();
    158 
    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);
    164 	timer->start(1000);
    165 
    166 	signalMeterTimer = new QTimer(this);
    167 	signalMeterTimer->setInterval(signalMeterInterval);
    168 	connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate()));
    169 
    170 	if (openCtrlConnection(ctrl_iface) < 0) {
    171 		debug("Failed to open control connection to "
    172 		      "wpa_supplicant.");
    173 	}
    174 
    175 	updateStatus();
    176 	networkMayHaveChanged = true;
    177 	updateNetworks();
    178 }
    179 
    180 
    181 WpaGui::~WpaGui()
    182 {
    183 	delete msgNotifier;
    184 
    185 	if (monitor_conn) {
    186 		wpa_ctrl_detach(monitor_conn);
    187 		wpa_ctrl_close(monitor_conn);
    188 		monitor_conn = NULL;
    189 	}
    190 	if (ctrl_conn) {
    191 		wpa_ctrl_close(ctrl_conn);
    192 		ctrl_conn = NULL;
    193 	}
    194 
    195 	if (eh) {
    196 		eh->close();
    197 		delete eh;
    198 		eh = NULL;
    199 	}
    200 
    201 	if (scanres) {
    202 		scanres->close();
    203 		delete scanres;
    204 		scanres = NULL;
    205 	}
    206 
    207 	if (peers) {
    208 		peers->close();
    209 		delete peers;
    210 		peers = NULL;
    211 	}
    212 
    213 	if (add_iface) {
    214 		add_iface->close();
    215 		delete add_iface;
    216 		add_iface = NULL;
    217 	}
    218 
    219 	if (udr) {
    220 		udr->close();
    221 		delete udr;
    222 		udr = NULL;
    223 	}
    224 
    225 	free(ctrl_iface);
    226 	ctrl_iface = NULL;
    227 
    228 	free(ctrl_iface_dir);
    229 	ctrl_iface_dir = NULL;
    230 }
    231 
    232 
    233 void WpaGui::languageChange()
    234 {
    235 	retranslateUi(this);
    236 }
    237 
    238 
    239 void WpaGui::parse_argv()
    240 {
    241 	int c;
    242 	WpaGuiApp *app = qobject_cast<WpaGuiApp*>(qApp);
    243 	for (;;) {
    244 		c = getopt(app->argc, app->argv, "i:m:p:tq");
    245 		if (c < 0)
    246 			break;
    247 		switch (c) {
    248 		case 'i':
    249 			free(ctrl_iface);
    250 			ctrl_iface = strdup(optarg);
    251 			break;
    252 		case 'm':
    253 			signalMeterInterval = atoi(optarg) * 1000;
    254 			break;
    255 		case 'p':
    256 			free(ctrl_iface_dir);
    257 			ctrl_iface_dir = strdup(optarg);
    258 			break;
    259 		case 't':
    260 			startInTray = true;
    261 			break;
    262 		case 'q':
    263 			quietMode = true;
    264 			break;
    265 		}
    266 	}
    267 }
    268 
    269 
    270 int WpaGui::openCtrlConnection(const char *ifname)
    271 {
    272 	char *cfile;
    273 	int flen;
    274 	char buf[2048], *pos, *pos2;
    275 	size_t len;
    276 
    277 	if (ifname) {
    278 		if (ifname != ctrl_iface) {
    279 			free(ctrl_iface);
    280 			ctrl_iface = strdup(ifname);
    281 		}
    282 	} else {
    283 #ifdef CONFIG_CTRL_IFACE_UDP
    284 		free(ctrl_iface);
    285 		ctrl_iface = strdup("udp");
    286 #endif /* CONFIG_CTRL_IFACE_UDP */
    287 #ifdef CONFIG_CTRL_IFACE_UNIX
    288 		struct dirent *dent;
    289 		DIR *dir = opendir(ctrl_iface_dir);
    290 		free(ctrl_iface);
    291 		ctrl_iface = NULL;
    292 		if (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)
    301 					continue;
    302 #endif /* _DIRENT_HAVE_D_TYPE */
    303 
    304 				if (strcmp(dent->d_name, ".") == 0 ||
    305 				    strcmp(dent->d_name, "..") == 0)
    306 					continue;
    307 				debug("Selected interface '%s'",
    308 				      dent->d_name);
    309 				ctrl_iface = strdup(dent->d_name);
    310 				break;
    311 			}
    312 			closedir(dir);
    313 		}
    314 #endif /* CONFIG_CTRL_IFACE_UNIX */
    315 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    316 		struct wpa_ctrl *ctrl;
    317 		int ret;
    318 
    319 		free(ctrl_iface);
    320 		ctrl_iface = NULL;
    321 
    322 		ctrl = wpa_ctrl_open(NULL);
    323 		if (ctrl) {
    324 			len = sizeof(buf) - 1;
    325 			ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
    326 					       &len, NULL);
    327 			if (ret >= 0) {
    328 				connectedToService = true;
    329 				buf[len] = '\0';
    330 				pos = strchr(buf, '\n');
    331 				if (pos)
    332 					*pos = '\0';
    333 				ctrl_iface = strdup(buf);
    334 			}
    335 			wpa_ctrl_close(ctrl);
    336 		}
    337 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    338 	}
    339 
    340 	if (ctrl_iface == NULL) {
    341 #ifdef CONFIG_NATIVE_WINDOWS
    342 		static bool first = true;
    343 		if (first && !serviceRunning()) {
    344 			first = false;
    345 			if (QMessageBox::warning(
    346 				    this, qAppName(),
    347 				    tr("wpa_supplicant service is not "
    348 				       "running.\n"
    349 				       "Do you want to start it?"),
    350 				    QMessageBox::Yes | QMessageBox::No) ==
    351 			    QMessageBox::Yes)
    352 				startService();
    353 		}
    354 #endif /* CONFIG_NATIVE_WINDOWS */
    355 		return -1;
    356 	}
    357 
    358 #ifdef CONFIG_CTRL_IFACE_UNIX
    359 	flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
    360 	cfile = (char *) malloc(flen);
    361 	if (cfile == NULL)
    362 		return -1;
    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);
    367 	if (cfile == NULL)
    368 		return -1;
    369 	snprintf(cfile, flen, "%s", ctrl_iface);
    370 #endif /* CONFIG_CTRL_IFACE_UNIX */
    371 
    372 	if (ctrl_conn) {
    373 		wpa_ctrl_close(ctrl_conn);
    374 		ctrl_conn = NULL;
    375 	}
    376 
    377 	if (monitor_conn) {
    378 		delete msgNotifier;
    379 		msgNotifier = NULL;
    380 		wpa_ctrl_detach(monitor_conn);
    381 		wpa_ctrl_close(monitor_conn);
    382 		monitor_conn = NULL;
    383 	}
    384 
    385 	debug("Trying to connect to '%s'", cfile);
    386 	ctrl_conn = wpa_ctrl_open(cfile);
    387 	if (ctrl_conn == NULL) {
    388 		free(cfile);
    389 		return -1;
    390 	}
    391 	monitor_conn = wpa_ctrl_open(cfile);
    392 	free(cfile);
    393 	if (monitor_conn == NULL) {
    394 		wpa_ctrl_close(ctrl_conn);
    395 		return -1;
    396 	}
    397 	if (wpa_ctrl_attach(monitor_conn)) {
    398 		debug("Failed to attach to wpa_supplicant");
    399 		wpa_ctrl_close(monitor_conn);
    400 		monitor_conn = NULL;
    401 		wpa_ctrl_close(ctrl_conn);
    402 		ctrl_conn = NULL;
    403 		return -1;
    404 	}
    405 
    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()));
    410 #endif
    411 
    412 	adapterSelect->clear();
    413 	adapterSelect->addItem(ctrl_iface);
    414 	adapterSelect->setCurrentIndex(0);
    415 
    416 	len = sizeof(buf) - 1;
    417 	if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
    418 	    0) {
    419 		buf[len] = '\0';
    420 		pos = buf;
    421 		while (*pos) {
    422 			pos2 = strchr(pos, '\n');
    423 			if (pos2)
    424 				*pos2 = '\0';
    425 			if (strcmp(pos, ctrl_iface) != 0)
    426 				adapterSelect->addItem(pos);
    427 			if (pos2)
    428 				pos = pos2 + 1;
    429 			else
    430 				break;
    431 		}
    432 	}
    433 
    434 	len = sizeof(buf) - 1;
    435 	if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len,
    436 			     NULL) >= 0) {
    437 		buf[len] = '\0';
    438 
    439 		QString res(buf);
    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);
    445 	}
    446 
    447 	return 0;
    448 }
    449 
    450 
    451 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
    452 {
    453 	int ret;
    454 
    455 	if (ctrl_conn == NULL)
    456 		return -3;
    457 	ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL);
    458 	if (ret == -2)
    459 		debug("'%s' command timed out.", cmd);
    460 	else if (ret < 0)
    461 		debug("'%s' command failed.", cmd);
    462 
    463 	return ret;
    464 }
    465 
    466 
    467 QString WpaGui::wpaStateTranslate(char *state)
    468 {
    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");
    487 	else
    488 		return tr("Unknown");
    489 }
    490 
    491 
    492 void WpaGui::updateStatus()
    493 {
    494 	char buf[2048], *start, *end, *pos;
    495 	size_t len;
    496 
    497 	pingsToStatusUpdate = 10;
    498 
    499 	len = sizeof(buf) - 1;
    500 	if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
    501 		textStatus->setText(tr("Could not get status from "
    502 				       "wpa_supplicant"));
    503 		textAuthentication->clear();
    504 		textEncryption->clear();
    505 		textSsid->clear();
    506 		textBssid->clear();
    507 		textIpAddress->clear();
    508 		updateTrayToolTip(tr("no status information"));
    509 		updateTrayIcon(TrayIconOffline);
    510 		signalMeterTimer->stop();
    511 
    512 #ifdef CONFIG_NATIVE_WINDOWS
    513 		static bool first = true;
    514 		if (first && connectedToService &&
    515 		    (ctrl_iface == NULL || *ctrl_iface == '\0')) {
    516 			first = false;
    517 			if (QMessageBox::information(
    518 				    this, qAppName(),
    519 				    tr("No network interfaces in use.\n"
    520 				       "Would you like to add one?"),
    521 				    QMessageBox::Yes | QMessageBox::No) ==
    522 			    QMessageBox::Yes)
    523 				addInterface();
    524 		}
    525 #endif /* CONFIG_NATIVE_WINDOWS */
    526 		return;
    527 	}
    528 
    529 	buf[len] = '\0';
    530 
    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;
    535 	char *mode = NULL;
    536 
    537 	start = buf;
    538 	while (*start) {
    539 		bool last = false;
    540 		end = strchr(start, '\n');
    541 		if (end == NULL) {
    542 			last = true;
    543 			end = start;
    544 			while (end[0] && end[1])
    545 				end++;
    546 		}
    547 		*end = '\0';
    548 
    549 		pos = strchr(start, '=');
    550 		if (pos) {
    551 			*pos++ = '\0';
    552 			if (strcmp(start, "bssid") == 0) {
    553 				bssid_updated = true;
    554 				textBssid->setText(pos);
    555 			} else if (strcmp(start, "ssid") == 0) {
    556 				ssid_updated = true;
    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);
    563 				}
    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) {
    571 				auth_updated = true;
    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) {
    577 				group_cipher = pos;
    578 			} else if (strcmp(start, "mode") == 0) {
    579 				mode = pos;
    580 			}
    581 		}
    582 
    583 		if (last)
    584 			break;
    585 		start = end + 1;
    586 	}
    587 	if (status_updated && mode)
    588 		textStatus->setText(textStatus->text() + " (" + mode + ")");
    589 
    590 	if (pairwise_cipher || group_cipher) {
    591 		QString encr;
    592 		if (pairwise_cipher && group_cipher &&
    593 		    strcmp(pairwise_cipher, group_cipher) != 0) {
    594 			encr.append(pairwise_cipher);
    595 			encr.append(" + ");
    596 			encr.append(group_cipher);
    597 		} else if (pairwise_cipher) {
    598 			encr.append(pairwise_cipher);
    599 		} else {
    600 			encr.append(group_cipher);
    601 			encr.append(" [group key only]");
    602 		}
    603 		textEncryption->setText(encr);
    604 	} else
    605 		textEncryption->clear();
    606 
    607 	if (signalMeterInterval) {
    608 		/*
    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
    612 		 * timer.
    613 		 */
    614 		if (ssid_updated) {
    615 			if (!signalMeterTimer->isActive()) {
    616 				updateTrayIcon(TrayIconConnected);
    617 				signalMeterTimer->start();
    618 			}
    619 		} else {
    620 			signalMeterTimer->stop();
    621 		}
    622 	}
    623 
    624 	if (!status_updated)
    625 		textStatus->clear();
    626 	if (!auth_updated)
    627 		textAuthentication->clear();
    628 	if (!ssid_updated) {
    629 		textSsid->clear();
    630 		updateTrayToolTip(tr("(not-associated)"));
    631 		updateTrayIcon(TrayIconOffline);
    632 	}
    633 	if (!bssid_updated)
    634 		textBssid->clear();
    635 	if (!ipaddr_updated)
    636 		textIpAddress->clear();
    637 }
    638 
    639 
    640 void WpaGui::updateNetworks()
    641 {
    642 	char buf[4096], *start, *end, *id, *ssid, *bssid, *flags;
    643 	size_t len;
    644 	int first_active = -1;
    645 	int was_selected = -1;
    646 	bool current = false;
    647 
    648 	if (!networkMayHaveChanged)
    649 		return;
    650 
    651 	if (networkList->currentRow() >= 0)
    652 		was_selected = networkList->currentRow();
    653 
    654 	networkSelect->clear();
    655 	networkList->clear();
    656 
    657 	if (ctrl_conn == NULL)
    658 		return;
    659 
    660 	len = sizeof(buf) - 1;
    661 	if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
    662 		return;
    663 
    664 	buf[len] = '\0';
    665 	start = strchr(buf, '\n');
    666 	if (start == NULL)
    667 		return;
    668 	start++;
    669 
    670 	while (*start) {
    671 		bool last = false;
    672 		end = strchr(start, '\n');
    673 		if (end == NULL) {
    674 			last = true;
    675 			end = start;
    676 			while (end[0] && end[1])
    677 				end++;
    678 		}
    679 		*end = '\0';
    680 
    681 		id = start;
    682 		ssid = strchr(id, '\t');
    683 		if (ssid == NULL)
    684 			break;
    685 		*ssid++ = '\0';
    686 		bssid = strchr(ssid, '\t');
    687 		if (bssid == NULL)
    688 			break;
    689 		*bssid++ = '\0';
    690 		flags = strchr(bssid, '\t');
    691 		if (flags == NULL)
    692 			break;
    693 		*flags++ = '\0';
    694 
    695 		if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) {
    696 			if (last)
    697 				break;
    698 			start = end + 1;
    699 			continue;
    700 		}
    701 
    702 		QString network(id);
    703 		network.append(": ");
    704 		network.append(ssid);
    705 		networkSelect->addItem(network);
    706 		networkList->addItem(network);
    707 
    708 		if (strstr(flags, "[CURRENT]")) {
    709 			networkSelect->setCurrentIndex(networkSelect->count() -
    710 						      1);
    711 			current = true;
    712 		} else if (first_active < 0 &&
    713 			   strstr(flags, "[DISABLED]") == NULL)
    714 			first_active = networkSelect->count() - 1;
    715 
    716 		if (last)
    717 			break;
    718 		start = end + 1;
    719 	}
    720 
    721 	if (networkSelect->count() > 1)
    722 		networkSelect->addItem(tr("Select any network"));
    723 
    724 	if (!current && first_active >= 0)
    725 		networkSelect->setCurrentIndex(first_active);
    726 
    727 	if (was_selected >= 0 && networkList->count() > 0) {
    728 		if (was_selected < networkList->count())
    729 			networkList->setCurrentRow(was_selected);
    730 		else
    731 			networkList->setCurrentRow(networkList->count() - 1);
    732 	}
    733 	else
    734 		networkList->setCurrentRow(networkSelect->currentIndex());
    735 
    736 	networkMayHaveChanged = false;
    737 }
    738 
    739 
    740 void WpaGui::helpIndex()
    741 {
    742 	debug("helpIndex");
    743 }
    744 
    745 
    746 void WpaGui::helpContents()
    747 {
    748 	debug("helpContents");
    749 }
    750 
    751 
    752 void WpaGui::helpAbout()
    753 {
    754 	QMessageBox::about(this, "wpa_gui for wpa_supplicant",
    755 			   "Copyright (c) 2003-2015,\n"
    756 			   "Jouni Malinen <j (at) w1.fi>\n"
    757 			   "and contributors.\n"
    758 			   "\n"
    759 			   "This software may be distributed under\n"
    760 			   "the terms of the BSD license.\n"
    761 			   "See README for more details.\n"
    762 			   "\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");
    766 }
    767 
    768 
    769 void WpaGui::disconnect()
    770 {
    771 	char reply[10];
    772 	size_t reply_len = sizeof(reply);
    773 	ctrlRequest("DISCONNECT", reply, &reply_len);
    774 	stopWpsRun(false);
    775 }
    776 
    777 
    778 void WpaGui::scan()
    779 {
    780 	if (scanres) {
    781 		scanres->close();
    782 		delete scanres;
    783 	}
    784 
    785 	scanres = new ScanResults();
    786 	if (scanres == NULL)
    787 		return;
    788 	scanres->setWpaGui(this);
    789 	scanres->show();
    790 	scanres->exec();
    791 }
    792 
    793 
    794 void WpaGui::eventHistory()
    795 {
    796 	if (eh) {
    797 		eh->close();
    798 		delete eh;
    799 	}
    800 
    801 	eh = new EventHistory();
    802 	if (eh == NULL)
    803 		return;
    804 	eh->addEvents(msgs);
    805 	eh->show();
    806 	eh->exec();
    807 }
    808 
    809 
    810 void WpaGui::ping()
    811 {
    812 	char buf[10];
    813 	size_t len;
    814 
    815 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    816 	/*
    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
    821 	 * in Qt.
    822 	 */
    823 	receiveMsgs();
    824 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    825 
    826 	if (scanres && !scanres->isVisible()) {
    827 		delete scanres;
    828 		scanres = NULL;
    829 	}
    830 
    831 	if (eh && !eh->isVisible()) {
    832 		delete eh;
    833 		eh = NULL;
    834 	}
    835 
    836 	if (udr && !udr->isVisible()) {
    837 		delete udr;
    838 		udr = NULL;
    839 	}
    840 
    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;
    847 		}
    848 	}
    849 
    850 	pingsToStatusUpdate--;
    851 	if (pingsToStatusUpdate <= 0) {
    852 		updateStatus();
    853 		updateNetworks();
    854 	}
    855 
    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 */
    863 }
    864 
    865 
    866 void WpaGui::signalMeterUpdate()
    867 {
    868 	char reply[128];
    869 	size_t reply_len = sizeof(reply);
    870 	char *rssi;
    871 	int rssi_value;
    872 
    873 	ctrlRequest("SIGNAL_POLL", reply, &reply_len);
    874 
    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")]);
    881 	else {
    882 		debug("Failed to get RSSI value");
    883 		updateTrayIcon(TrayIconSignalNone);
    884 		return;
    885 	}
    886 
    887 	debug("RSSI value: %d", rssi_value);
    888 
    889 	/*
    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.
    893 	 */
    894 
    895 	/*
    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.
    899 	 */
    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);
    908 	else
    909 		updateTrayIcon(TrayIconSignalNone);
    910 }
    911 
    912 
    913 static int str_match(const char *a, const char *b)
    914 {
    915 	return strncmp(a, b, strlen(b)) == 0;
    916 }
    917 
    918 
    919 void WpaGui::processMsg(char *msg)
    920 {
    921 	char *pos = msg, *pos2;
    922 	int priority = 2;
    923 
    924 	if (*pos == '<') {
    925 		/* skip priority */
    926 		pos++;
    927 		priority = atoi(pos);
    928 		pos = strchr(pos, '>');
    929 		if (pos)
    930 			pos++;
    931 		else
    932 			pos = msg;
    933 	}
    934 
    935 	WpaMsg wm(pos, priority);
    936 	if (eh)
    937 		eh->addEvent(wm);
    938 	if (peers)
    939 		peers->event_notify(wm);
    940 	msgs.append(wm);
    941 	while (msgs.count() > 100)
    942 		msgs.pop_front();
    943 
    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) ? ':' : ' ');
    947 		if (pos2)
    948 			pos2++;
    949 		else
    950 			pos2 = pos;
    951 	} else
    952 		pos2 = pos;
    953 	QString lastmsg = pos2;
    954 	lastmsg.truncate(40);
    955 	textLastMessage->setText(lastmsg);
    956 
    957 	pingsToStatusUpdate = 0;
    958 	networkMayHaveChanged = true;
    959 
    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()));
    971 		stopWpsRun(true);
    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 "
    981 					  "registrar"));
    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 "
    990 				       "authorized");
    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"));
   1014 	}
   1015 }
   1016 
   1017 
   1018 void WpaGui::processCtrlReq(const char *req)
   1019 {
   1020 	if (udr) {
   1021 		udr->close();
   1022 		delete udr;
   1023 	}
   1024 	udr = new UserDataRequest();
   1025 	if (udr == NULL)
   1026 		return;
   1027 	if (udr->setParams(this, req) < 0) {
   1028 		delete udr;
   1029 		udr = NULL;
   1030 		return;
   1031 	}
   1032 	udr->show();
   1033 	udr->exec();
   1034 }
   1035 
   1036 
   1037 void WpaGui::receiveMsgs()
   1038 {
   1039 	char buf[256];
   1040 	size_t len;
   1041 
   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) {
   1045 			buf[len] = '\0';
   1046 			processMsg(buf);
   1047 		}
   1048 	}
   1049 }
   1050 
   1051 
   1052 void WpaGui::connectB()
   1053 {
   1054 	char reply[10];
   1055 	size_t reply_len = sizeof(reply);
   1056 	ctrlRequest("REASSOCIATE", reply, &reply_len);
   1057 }
   1058 
   1059 
   1060 void WpaGui::selectNetwork( const QString &sel )
   1061 {
   1062 	QString cmd(sel);
   1063 	char reply[10];
   1064 	size_t reply_len = sizeof(reply);
   1065 
   1066 	if (cmd.contains(QRegExp("^\\d+:")))
   1067 		cmd.truncate(cmd.indexOf(':'));
   1068 	else
   1069 		cmd = "any";
   1070 	cmd.prepend("SELECT_NETWORK ");
   1071 	ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len);
   1072 	triggerUpdate();
   1073 	stopWpsRun(false);
   1074 }
   1075 
   1076 
   1077 void WpaGui::enableNetwork(const QString &sel)
   1078 {
   1079 	QString cmd(sel);
   1080 	char reply[10];
   1081 	size_t reply_len = sizeof(reply);
   1082 
   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());
   1088 		return;
   1089 	}
   1090 	cmd.prepend("ENABLE_NETWORK ");
   1091 	ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len);
   1092 	triggerUpdate();
   1093 }
   1094 
   1095 
   1096 void WpaGui::disableNetwork(const QString &sel)
   1097 {
   1098 	QString cmd(sel);
   1099 	char reply[10];
   1100 	size_t reply_len = sizeof(reply);
   1101 
   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());
   1107 		return;
   1108 	}
   1109 	cmd.prepend("DISABLE_NETWORK ");
   1110 	ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len);
   1111 	triggerUpdate();
   1112 }
   1113 
   1114 
   1115 void WpaGui::editNetwork(const QString &sel)
   1116 {
   1117 	QString cmd(sel);
   1118 	int id = -1;
   1119 
   1120 	if (cmd.contains(QRegExp("^\\d+:"))) {
   1121 		cmd.truncate(cmd.indexOf(':'));
   1122 		id = cmd.toInt();
   1123 	}
   1124 
   1125 	NetworkConfig *nc = new NetworkConfig();
   1126 	if (nc == NULL)
   1127 		return;
   1128 	nc->setWpaGui(this);
   1129 
   1130 	if (id >= 0)
   1131 		nc->paramsFromConfig(id);
   1132 	else
   1133 		nc->newNetwork();
   1134 
   1135 	nc->show();
   1136 	nc->exec();
   1137 }
   1138 
   1139 
   1140 void WpaGui::editSelectedNetwork()
   1141 {
   1142 	if (networkSelect->count() < 1) {
   1143 		QMessageBox::information(
   1144 			this, tr("No Networks"),
   1145 			tr("There are no networks to edit.\n"));
   1146 		return;
   1147 	}
   1148 	QString sel(networkSelect->currentText());
   1149 	editNetwork(sel);
   1150 }
   1151 
   1152 
   1153 void WpaGui::editListedNetwork()
   1154 {
   1155 	if (networkList->currentRow() < 0) {
   1156 		QMessageBox::information(this, tr("Select A Network"),
   1157 					 tr("Select a network from the list to"
   1158 					    " edit it.\n"));
   1159 		return;
   1160 	}
   1161 	QString sel(networkList->currentItem()->text());
   1162 	editNetwork(sel);
   1163 }
   1164 
   1165 
   1166 void WpaGui::triggerUpdate()
   1167 {
   1168 	updateStatus();
   1169 	networkMayHaveChanged = true;
   1170 	updateNetworks();
   1171 }
   1172 
   1173 
   1174 void WpaGui::addNetwork()
   1175 {
   1176 	NetworkConfig *nc = new NetworkConfig();
   1177 	if (nc == NULL)
   1178 		return;
   1179 	nc->setWpaGui(this);
   1180 	nc->newNetwork();
   1181 	nc->show();
   1182 	nc->exec();
   1183 }
   1184 
   1185 
   1186 void WpaGui::removeNetwork(const QString &sel)
   1187 {
   1188 	QString cmd(sel);
   1189 	char reply[10];
   1190 	size_t reply_len = sizeof(reply);
   1191 
   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());
   1197 		return;
   1198 	}
   1199 	cmd.prepend("REMOVE_NETWORK ");
   1200 	ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len);
   1201 	triggerUpdate();
   1202 }
   1203 
   1204 
   1205 void WpaGui::removeSelectedNetwork()
   1206 {
   1207 	if (networkSelect->count() < 1) {
   1208 		QMessageBox::information(this, tr("No Networks"),
   1209 			                 tr("There are no networks to remove."
   1210 					    "\n"));
   1211 		return;
   1212 	}
   1213 	QString sel(networkSelect->currentText());
   1214 	removeNetwork(sel);
   1215 }
   1216 
   1217 
   1218 void WpaGui::removeListedNetwork()
   1219 {
   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"));
   1224 		return;
   1225 	}
   1226 	QString sel(networkList->currentItem()->text());
   1227 	removeNetwork(sel);
   1228 }
   1229 
   1230 
   1231 void WpaGui::enableAllNetworks()
   1232 {
   1233 	QString sel("all");
   1234 	enableNetwork(sel);
   1235 }
   1236 
   1237 
   1238 void WpaGui::disableAllNetworks()
   1239 {
   1240 	QString sel("all");
   1241 	disableNetwork(sel);
   1242 }
   1243 
   1244 
   1245 void WpaGui::removeAllNetworks()
   1246 {
   1247 	QString sel("all");
   1248 	removeNetwork(sel);
   1249 }
   1250 
   1251 
   1252 int WpaGui::getNetworkDisabled(const QString &sel)
   1253 {
   1254 	QString cmd(sel);
   1255 	char reply[10];
   1256 	size_t reply_len = sizeof(reply) - 1;
   1257 	int pos = cmd.indexOf(':');
   1258 	if (pos < 0) {
   1259 		debug("Invalid getNetworkDisabled '%s'",
   1260 		      cmd.toLocal8Bit().constData());
   1261 		return -1;
   1262 	}
   1263 	cmd.truncate(pos);
   1264 	cmd.prepend("GET_NETWORK ");
   1265 	cmd.append(" disabled");
   1266 
   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"))
   1271 			return atoi(reply);
   1272 	}
   1273 
   1274 	return -1;
   1275 }
   1276 
   1277 
   1278 void WpaGui::updateNetworkDisabledStatus()
   1279 {
   1280 	if (networkList->currentRow() < 0)
   1281 		return;
   1282 
   1283 	QString sel(networkList->currentItem()->text());
   1284 
   1285 	switch (getNetworkDisabled(sel)) {
   1286 	case 0:
   1287 		if (!enableRadioButton->isChecked())
   1288 			enableRadioButton->setChecked(true);
   1289 		return;
   1290 	case 1:
   1291 		if (!disableRadioButton->isChecked())
   1292 			disableRadioButton->setChecked(true);
   1293 		return;
   1294 	}
   1295 }
   1296 
   1297 
   1298 void WpaGui::enableListedNetwork(bool enabled)
   1299 {
   1300 	if (networkList->currentRow() < 0 || !enabled)
   1301 		return;
   1302 
   1303 	QString sel(networkList->currentItem()->text());
   1304 
   1305 	if (getNetworkDisabled(sel) == 1)
   1306 		enableNetwork(sel);
   1307 }
   1308 
   1309 
   1310 void WpaGui::disableListedNetwork(bool disabled)
   1311 {
   1312 	if (networkList->currentRow() < 0 || !disabled)
   1313 		return;
   1314 
   1315 	QString sel(networkList->currentItem()->text());
   1316 
   1317 	if (getNetworkDisabled(sel) == 0)
   1318 		disableNetwork(sel);
   1319 }
   1320 
   1321 
   1322 void WpaGui::saveConfig()
   1323 {
   1324 	char buf[10];
   1325 	size_t len;
   1326 
   1327 	len = sizeof(buf) - 1;
   1328 	ctrlRequest("SAVE_CONFIG", buf, &len);
   1329 
   1330 	buf[len] = '\0';
   1331 
   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"
   1336 			   "\n"
   1337 			   "The update_config=1 configuration option\n"
   1338 			   "must be used for configuration saving to\n"
   1339 			   "be permitted.\n"));
   1340 	else
   1341 		QMessageBox::information(
   1342 			this, tr("Saved configuration"),
   1343 			tr("The current configuration was saved."
   1344 			   "\n"));
   1345 }
   1346 
   1347 
   1348 void WpaGui::selectAdapter( const QString & sel )
   1349 {
   1350 	if (openCtrlConnection(sel.toLocal8Bit().constData()) < 0)
   1351 		debug("Failed to open control connection to "
   1352 		      "wpa_supplicant.");
   1353 	updateStatus();
   1354 	updateNetworks();
   1355 }
   1356 
   1357 
   1358 void WpaGui::createTrayIcon(bool trayOnly)
   1359 {
   1360 	QApplication::setQuitOnLastWindowClosed(false);
   1361 
   1362 	tray_icon = new QSystemTrayIcon(this);
   1363 	updateTrayIcon(TrayIconOffline);
   1364 
   1365 	connect(tray_icon,
   1366 		SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
   1367 		this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
   1368 
   1369 	ackTrayIcon = false;
   1370 
   1371 	tray_menu = new QMenu(this);
   1372 
   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,
   1378 		SLOT(connectB()));
   1379 	tray_menu->addAction(disconnectAction);
   1380 	tray_menu->addAction(reconnectAction);
   1381 	tray_menu->addSeparator();
   1382 
   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();
   1393 
   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);
   1404 
   1405 	tray_icon->setContextMenu(tray_menu);
   1406 
   1407 	tray_icon->show();
   1408 
   1409 	if (!trayOnly)
   1410 		show();
   1411 	inTray = trayOnly;
   1412 }
   1413 
   1414 
   1415 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
   1416 			     const QString & msg)
   1417 {
   1418 	if (!QSystemTrayIcon::supportsMessages())
   1419 		return;
   1420 
   1421 	if (isVisible() || !tray_icon || !tray_icon->isVisible() || quietMode)
   1422 		return;
   1423 
   1424 	tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
   1425 }
   1426 
   1427 
   1428 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
   1429  {
   1430 	switch (how) {
   1431 	/* use close() here instead of hide() and allow the
   1432 	 * custom closeEvent handler take care of children */
   1433 	case QSystemTrayIcon::Trigger:
   1434 		ackTrayIcon = true;
   1435 		if (isVisible()) {
   1436 			close();
   1437 			inTray = true;
   1438 		} else {
   1439 			show();
   1440 			inTray = false;
   1441 		}
   1442 		break;
   1443 	case QSystemTrayIcon::MiddleClick:
   1444 		showTrayStatus();
   1445 		break;
   1446 	default:
   1447 		break;
   1448 	}
   1449 }
   1450 
   1451 
   1452 void WpaGui::showTrayStatus()
   1453 {
   1454 	char buf[2048];
   1455 	size_t len;
   1456 
   1457 	len = sizeof(buf) - 1;
   1458 	if (ctrlRequest("STATUS", buf, &len) < 0)
   1459 		return;
   1460 	buf[len] = '\0';
   1461 
   1462 	QString msg, status(buf);
   1463 
   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;
   1468 		if (pos < 1)
   1469 			continue;
   1470 
   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");
   1489 	}
   1490 
   1491 	if (!msg.isEmpty())
   1492 		showTrayMessage(QSystemTrayIcon::Information, 10, msg);
   1493 }
   1494 
   1495 
   1496 void WpaGui::updateTrayToolTip(const QString &msg)
   1497 {
   1498 	if (tray_icon)
   1499 		tray_icon->setToolTip(msg);
   1500 }
   1501 
   1502 
   1503 void WpaGui::updateTrayIcon(TrayIconType type)
   1504 {
   1505 	if (!tray_icon || currentIconType == type)
   1506 		return;
   1507 
   1508 	QIcon fallback_icon;
   1509 	QStringList names;
   1510 
   1511 	if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
   1512 		fallback_icon = QIcon(":/icons/wpa_gui.svg");
   1513 	else
   1514 		fallback_icon = QIcon(":/icons/wpa_gui.png");
   1515 
   1516 	switch (type) {
   1517 	case TrayIconOffline:
   1518 		names << "network-wireless-offline-symbolic"
   1519 		      << "network-wireless-offline"
   1520 		      << "network-wireless-signal-none-symbolic"
   1521 		      << "network-wireless-signal-none";
   1522 		break;
   1523 	case TrayIconAcquiring:
   1524 		names << "network-wireless-acquiring-symbolic"
   1525 		      << "network-wireless-acquiring";
   1526 		break;
   1527 	case TrayIconConnected:
   1528 		names << "network-wireless-connected-symbolic"
   1529 		      << "network-wireless-connected";
   1530 		break;
   1531 	case TrayIconSignalNone:
   1532 		names << "network-wireless-signal-none-symbolic"
   1533 		      << "network-wireless-signal-none";
   1534 		break;
   1535 	case TrayIconSignalWeak:
   1536 		names << "network-wireless-signal-weak-symbolic"
   1537 		      << "network-wireless-signal-weak";
   1538 		break;
   1539 	case TrayIconSignalOk:
   1540 		names << "network-wireless-signal-ok-symbolic"
   1541 		      << "network-wireless-signal-ok";
   1542 		break;
   1543 	case TrayIconSignalGood:
   1544 		names << "network-wireless-signal-good-symbolic"
   1545 		      << "network-wireless-signal-good";
   1546 		break;
   1547 	case TrayIconSignalExcellent:
   1548 		names << "network-wireless-signal-excellent-symbolic"
   1549 		      << "network-wireless-signal-excellent";
   1550 		break;
   1551 	}
   1552 
   1553 	currentIconType = type;
   1554 	tray_icon->setIcon(loadThemedIcon(names, fallback_icon));
   1555 }
   1556 
   1557 
   1558 QIcon WpaGui::loadThemedIcon(const QStringList &names,
   1559 			     const QIcon &fallback)
   1560 {
   1561 	QIcon icon;
   1562 
   1563 	for (QStringList::ConstIterator it = names.begin();
   1564 	     it != names.end(); it++) {
   1565 		icon = QIcon::fromTheme(*it);
   1566 		if (!icon.isNull())
   1567 			return icon;
   1568 	}
   1569 
   1570 	return fallback;
   1571 }
   1572 
   1573 
   1574 void WpaGui::closeEvent(QCloseEvent *event)
   1575 {
   1576 	if (eh) {
   1577 		eh->close();
   1578 		delete eh;
   1579 		eh = NULL;
   1580 	}
   1581 
   1582 	if (scanres) {
   1583 		scanres->close();
   1584 		delete scanres;
   1585 		scanres = NULL;
   1586 	}
   1587 
   1588 	if (peers) {
   1589 		peers->close();
   1590 		delete peers;
   1591 		peers = NULL;
   1592 	}
   1593 
   1594 	if (udr) {
   1595 		udr->close();
   1596 		delete udr;
   1597 		udr = NULL;
   1598 	}
   1599 
   1600 	if (tray_icon && !ackTrayIcon) {
   1601 		/* give user a visual hint that the tray icon exists */
   1602 		if (QSystemTrayIcon::supportsMessages()) {
   1603 			hide();
   1604 			showTrayMessage(QSystemTrayIcon::Information, 3,
   1605 					qAppName() +
   1606 					tr(" will keep running in "
   1607 					   "the system tray."));
   1608 		} else {
   1609 			QMessageBox::information(this, qAppName() +
   1610 						 tr(" systray"),
   1611 						 tr("The program will keep "
   1612 						    "running in the system "
   1613 						    "tray."));
   1614 		}
   1615 		ackTrayIcon = true;
   1616 	}
   1617 
   1618 	event->accept();
   1619 }
   1620 
   1621 
   1622 void WpaGui::wpsDialog()
   1623 {
   1624 	wpaguiTab->setCurrentWidget(wpsTab);
   1625 }
   1626 
   1627 
   1628 void WpaGui::peersDialog()
   1629 {
   1630 	if (peers) {
   1631 		peers->close();
   1632 		delete peers;
   1633 	}
   1634 
   1635 	peers = new Peers();
   1636 	if (peers == NULL)
   1637 		return;
   1638 	peers->setWpaGui(this);
   1639 	peers->show();
   1640 	peers->exec();
   1641 }
   1642 
   1643 
   1644 void WpaGui::tabChanged(int index)
   1645 {
   1646 	if (index != 2)
   1647 		return;
   1648 
   1649 	if (wpsRunning)
   1650 		return;
   1651 
   1652 	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
   1653 	if (bssFromScan.isEmpty())
   1654 		wpsApPinButton->setEnabled(false);
   1655 }
   1656 
   1657 
   1658 void WpaGui::wpsPbc()
   1659 {
   1660 	char reply[20];
   1661 	size_t reply_len = sizeof(reply);
   1662 
   1663 	if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
   1664 		return;
   1665 
   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."));
   1670 	} else {
   1671 		wpsInstructions->setText(tr("If you have not yet done so, press "
   1672 					 "the push button on the AP to start "
   1673 					 "the PBC mode."));
   1674 	}
   1675 	wpsStatusText->setText(tr("Waiting for Registrar"));
   1676 	wpsRunning = true;
   1677 }
   1678 
   1679 
   1680 void WpaGui::wpsGeneratePin()
   1681 {
   1682 	char reply[20];
   1683 	size_t reply_len = sizeof(reply) - 1;
   1684 
   1685 	if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
   1686 		return;
   1687 
   1688 	reply[reply_len] = '\0';
   1689 
   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 "
   1694 				 "external one)."));
   1695 	wpsStatusText->setText(tr("Waiting for Registrar"));
   1696 	wpsRunning = true;
   1697 }
   1698 
   1699 
   1700 void WpaGui::setBssFromScan(const QString &bssid)
   1701 {
   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."));
   1709 }
   1710 
   1711 
   1712 void WpaGui::wpsApPinChanged(const QString &text)
   1713 {
   1714 	wpsApPinButton->setEnabled(text.length() == 8);
   1715 }
   1716 
   1717 
   1718 void WpaGui::wpsApPin()
   1719 {
   1720 	char reply[20];
   1721 	size_t reply_len = sizeof(reply);
   1722 
   1723 	QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
   1724 	if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) < 0)
   1725 		return;
   1726 
   1727 	wpsStatusText->setText(tr("Waiting for AP/Enrollee"));
   1728 	wpsRunning = true;
   1729 }
   1730 
   1731 
   1732 void WpaGui::stopWpsRun(bool success)
   1733 {
   1734 	if (wpsRunning)
   1735 		wpsStatusText->setText(success ? tr("Connected to the network") :
   1736 				       tr("Stopped"));
   1737 	else
   1738 		wpsStatusText->setText("");
   1739 	wpsPinEdit->setEnabled(false);
   1740 	wpsInstructions->setText("");
   1741 	wpsRunning = false;
   1742 	bssFromScan = "";
   1743 	wpsApPinEdit->setEnabled(false);
   1744 	wpsApPinButton->setEnabled(false);
   1745 }
   1746 
   1747 
   1748 #ifdef CONFIG_NATIVE_WINDOWS
   1749 
   1750 #ifndef WPASVC_NAME
   1751 #define WPASVC_NAME TEXT("wpasvc")
   1752 #endif
   1753 
   1754 class ErrorMsg : public QMessageBox {
   1755 public:
   1756 	ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
   1757 	void showMsg(QString msg);
   1758 private:
   1759 	DWORD err;
   1760 };
   1761 
   1762 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
   1763 	QMessageBox(parent), err(last_err)
   1764 {
   1765 	setWindowTitle(tr("wpa_gui error"));
   1766 	setIcon(QMessageBox::Warning);
   1767 }
   1768 
   1769 void ErrorMsg::showMsg(QString msg)
   1770 {
   1771 	LPTSTR buf;
   1772 
   1773 	setText(msg);
   1774 	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
   1775 			  FORMAT_MESSAGE_FROM_SYSTEM,
   1776 			  NULL, err, 0, (LPTSTR) (void *) &buf,
   1777 			  0, NULL) > 0) {
   1778 		QString msg = QString::fromWCharArray(buf);
   1779 		setInformativeText(QString("[%1] %2").arg(err).arg(msg));
   1780 		LocalFree(buf);
   1781 	} else {
   1782 		setInformativeText(QString("[%1]").arg(err));
   1783 	}
   1784 
   1785 	exec();
   1786 }
   1787 
   1788 
   1789 void WpaGui::startService()
   1790 {
   1791 	SC_HANDLE svc, scm;
   1792 
   1793 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
   1794 	if (!scm) {
   1795 		ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
   1796 		return;
   1797 	}
   1798 
   1799 	svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
   1800 	if (!svc) {
   1801 		ErrorMsg(this).showMsg(tr("OpenService failed"));
   1802 		CloseServiceHandle(scm);
   1803 		return;
   1804 	}
   1805 
   1806 	if (!StartService(svc, 0, NULL)) {
   1807 		ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant "
   1808 				       "service"));
   1809 	}
   1810 
   1811 	CloseServiceHandle(svc);
   1812 	CloseServiceHandle(scm);
   1813 }
   1814 
   1815 
   1816 void WpaGui::stopService()
   1817 {
   1818 	SC_HANDLE svc, scm;
   1819 	SERVICE_STATUS status;
   1820 
   1821 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
   1822 	if (!scm) {
   1823 		ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
   1824 		return;
   1825 	}
   1826 
   1827 	svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
   1828 	if (!svc) {
   1829 		ErrorMsg(this).showMsg(tr("OpenService failed"));
   1830 		CloseServiceHandle(scm);
   1831 		return;
   1832 	}
   1833 
   1834 	if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
   1835 		ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant "
   1836 				       "service"));
   1837 	}
   1838 
   1839 	CloseServiceHandle(svc);
   1840 	CloseServiceHandle(scm);
   1841 }
   1842 
   1843 
   1844 bool WpaGui::serviceRunning()
   1845 {
   1846 	SC_HANDLE svc, scm;
   1847 	SERVICE_STATUS status;
   1848 	bool running = false;
   1849 
   1850 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
   1851 	if (!scm) {
   1852 		debug("OpenSCManager failed: %d", (int) GetLastError());
   1853 		return false;
   1854 	}
   1855 
   1856 	svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
   1857 	if (!svc) {
   1858 		debug("OpenService failed: %d", (int) GetLastError());
   1859 		CloseServiceHandle(scm);
   1860 		return false;
   1861 	}
   1862 
   1863 	if (QueryServiceStatus(svc, &status)) {
   1864 		if (status.dwCurrentState != SERVICE_STOPPED)
   1865 			running = true;
   1866 	}
   1867 
   1868 	CloseServiceHandle(svc);
   1869 	CloseServiceHandle(scm);
   1870 
   1871 	return running;
   1872 }
   1873 
   1874 #endif /* CONFIG_NATIVE_WINDOWS */
   1875 
   1876 
   1877 void WpaGui::addInterface()
   1878 {
   1879 	if (add_iface) {
   1880 		add_iface->close();
   1881 		delete add_iface;
   1882 	}
   1883 	add_iface = new AddInterface(this, this);
   1884 	add_iface->show();
   1885 	add_iface->exec();
   1886 }
   1887 
   1888 
   1889 #ifndef QT_NO_SESSIONMANAGER
   1890 void WpaGui::saveState()
   1891 {
   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();
   1897 }
   1898 #endif
   1899