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 #if 1
     27 /* Silence stdout */
     28 #define printf wpagui_printf
     29 static int wpagui_printf(const char *, ...)
     30 {
     31 	return 0;
     32 }
     33 #endif
     34 
     35 WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags)
     36 	: QMainWindow(parent), app(_app)
     37 {
     38 	setupUi(this);
     39 
     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);
     45 
     46 	fileStartServiceAction = new QAction(this);
     47 	fileStartServiceAction->setObjectName("Start Service");
     48 	fileStartServiceAction->setIconText(tr("Start Service"));
     49 	fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction);
     50 
     51 	connect(fileStartServiceAction, SIGNAL(triggered()), this,
     52 		SLOT(startService()));
     53 	connect(fileStopServiceAction, SIGNAL(triggered()), this,
     54 		SLOT(stopService()));
     55 
     56 	addInterfaceAction = new QAction(this);
     57 	addInterfaceAction->setIconText(tr("Add Interface"));
     58 	fileMenu->insertAction(fileStartServiceAction, addInterfaceAction);
     59 
     60 	connect(addInterfaceAction, SIGNAL(triggered()), this,
     61 		SLOT(addInterface()));
     62 #endif /* CONFIG_NATIVE_WINDOWS */
     63 
     64 	(void) statusBar();
     65 
     66 	/*
     67 	 * Disable WPS tab by default; it will be enabled if wpa_supplicant is
     68 	 * built with WPS support.
     69 	 */
     70 	wpsTab->setEnabled(false);
     71 	wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false);
     72 
     73 	connect(fileEventHistoryAction, SIGNAL(triggered()), this,
     74 		SLOT(eventHistory()));
     75 	connect(fileSaveConfigAction, SIGNAL(triggered()), this,
     76 		SLOT(saveConfig()));
     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,
     81 		SLOT(addNetwork()));
     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()));
    124 
    125 	eh = NULL;
    126 	scanres = NULL;
    127 	peers = NULL;
    128 	add_iface = NULL;
    129 	udr = NULL;
    130 	tray_icon = NULL;
    131 	startInTray = false;
    132 	ctrl_iface = NULL;
    133 	ctrl_conn = NULL;
    134 	monitor_conn = NULL;
    135 	msgNotifier = NULL;
    136 	ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
    137 
    138 	parse_argv();
    139 
    140 #ifndef QT_NO_SESSIONMANAGER
    141 	if (app->isSessionRestored()) {
    142 		QSettings settings("wpa_supplicant", "wpa_gui");
    143 		settings.beginGroup("state");
    144 		if (app->sessionId().compare(settings.value("session_id").
    145 					     toString()) == 0)
    146 			startInTray = settings.value("in_tray").toBool();
    147 		settings.endGroup();
    148 	}
    149 #endif
    150 
    151 	if (QSystemTrayIcon::isSystemTrayAvailable())
    152 		createTrayIcon(startInTray);
    153 	else
    154 		show();
    155 
    156 	connectedToService = false;
    157 	textStatus->setText(tr("connecting to wpa_supplicant"));
    158 	timer = new QTimer(this);
    159 	connect(timer, SIGNAL(timeout()), SLOT(ping()));
    160 	timer->setSingleShot(FALSE);
    161 	timer->start(1000);
    162 
    163 	if (openCtrlConnection(ctrl_iface) < 0) {
    164 		printf("Failed to open control connection to "
    165 		       "wpa_supplicant.\n");
    166 	}
    167 
    168 	updateStatus();
    169 	networkMayHaveChanged = true;
    170 	updateNetworks();
    171 }
    172 
    173 
    174 WpaGui::~WpaGui()
    175 {
    176 	delete msgNotifier;
    177 
    178 	if (monitor_conn) {
    179 		wpa_ctrl_detach(monitor_conn);
    180 		wpa_ctrl_close(monitor_conn);
    181 		monitor_conn = NULL;
    182 	}
    183 	if (ctrl_conn) {
    184 		wpa_ctrl_close(ctrl_conn);
    185 		ctrl_conn = NULL;
    186 	}
    187 
    188 	if (eh) {
    189 		eh->close();
    190 		delete eh;
    191 		eh = NULL;
    192 	}
    193 
    194 	if (scanres) {
    195 		scanres->close();
    196 		delete scanres;
    197 		scanres = NULL;
    198 	}
    199 
    200 	if (peers) {
    201 		peers->close();
    202 		delete peers;
    203 		peers = NULL;
    204 	}
    205 
    206 	if (add_iface) {
    207 		add_iface->close();
    208 		delete add_iface;
    209 		add_iface = NULL;
    210 	}
    211 
    212 	if (udr) {
    213 		udr->close();
    214 		delete udr;
    215 		udr = NULL;
    216 	}
    217 
    218 	free(ctrl_iface);
    219 	ctrl_iface = NULL;
    220 
    221 	free(ctrl_iface_dir);
    222 	ctrl_iface_dir = NULL;
    223 }
    224 
    225 
    226 void WpaGui::languageChange()
    227 {
    228 	retranslateUi(this);
    229 }
    230 
    231 
    232 void WpaGui::parse_argv()
    233 {
    234 	int c;
    235 	for (;;) {
    236 		c = getopt(qApp->argc(), qApp->argv(), "i:p:t");
    237 		if (c < 0)
    238 			break;
    239 		switch (c) {
    240 		case 'i':
    241 			free(ctrl_iface);
    242 			ctrl_iface = strdup(optarg);
    243 			break;
    244 		case 'p':
    245 			free(ctrl_iface_dir);
    246 			ctrl_iface_dir = strdup(optarg);
    247 			break;
    248 		case 't':
    249 			startInTray = true;
    250 			break;
    251 		}
    252 	}
    253 }
    254 
    255 
    256 int WpaGui::openCtrlConnection(const char *ifname)
    257 {
    258 	char *cfile;
    259 	int flen;
    260 	char buf[2048], *pos, *pos2;
    261 	size_t len;
    262 
    263 	if (ifname) {
    264 		if (ifname != ctrl_iface) {
    265 			free(ctrl_iface);
    266 			ctrl_iface = strdup(ifname);
    267 		}
    268 	} else {
    269 #ifdef CONFIG_CTRL_IFACE_UDP
    270 		free(ctrl_iface);
    271 		ctrl_iface = strdup("udp");
    272 #endif /* CONFIG_CTRL_IFACE_UDP */
    273 #ifdef CONFIG_CTRL_IFACE_UNIX
    274 		struct dirent *dent;
    275 		DIR *dir = opendir(ctrl_iface_dir);
    276 		free(ctrl_iface);
    277 		ctrl_iface = NULL;
    278 		if (dir) {
    279 			while ((dent = readdir(dir))) {
    280 #ifdef _DIRENT_HAVE_D_TYPE
    281 				/* Skip the file if it is not a socket.
    282 				 * Also accept DT_UNKNOWN (0) in case
    283 				 * the C library or underlying file
    284 				 * system does not support d_type. */
    285 				if (dent->d_type != DT_SOCK &&
    286 				    dent->d_type != DT_UNKNOWN)
    287 					continue;
    288 #endif /* _DIRENT_HAVE_D_TYPE */
    289 
    290 				if (strcmp(dent->d_name, ".") == 0 ||
    291 				    strcmp(dent->d_name, "..") == 0)
    292 					continue;
    293 				printf("Selected interface '%s'\n",
    294 				       dent->d_name);
    295 				ctrl_iface = strdup(dent->d_name);
    296 				break;
    297 			}
    298 			closedir(dir);
    299 		}
    300 #endif /* CONFIG_CTRL_IFACE_UNIX */
    301 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    302 		struct wpa_ctrl *ctrl;
    303 		int ret;
    304 
    305 		free(ctrl_iface);
    306 		ctrl_iface = NULL;
    307 
    308 		ctrl = wpa_ctrl_open(NULL);
    309 		if (ctrl) {
    310 			len = sizeof(buf) - 1;
    311 			ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
    312 					       &len, NULL);
    313 			if (ret >= 0) {
    314 				connectedToService = true;
    315 				buf[len] = '\0';
    316 				pos = strchr(buf, '\n');
    317 				if (pos)
    318 					*pos = '\0';
    319 				ctrl_iface = strdup(buf);
    320 			}
    321 			wpa_ctrl_close(ctrl);
    322 		}
    323 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    324 	}
    325 
    326 	if (ctrl_iface == NULL) {
    327 #ifdef CONFIG_NATIVE_WINDOWS
    328 		static bool first = true;
    329 		if (first && !serviceRunning()) {
    330 			first = false;
    331 			if (QMessageBox::warning(
    332 				    this, qAppName(),
    333 				    tr("wpa_supplicant service is not "
    334 				       "running.\n"
    335 				       "Do you want to start it?"),
    336 				    QMessageBox::Yes | QMessageBox::No) ==
    337 			    QMessageBox::Yes)
    338 				startService();
    339 		}
    340 #endif /* CONFIG_NATIVE_WINDOWS */
    341 		return -1;
    342 	}
    343 
    344 #ifdef CONFIG_CTRL_IFACE_UNIX
    345 	flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
    346 	cfile = (char *) malloc(flen);
    347 	if (cfile == NULL)
    348 		return -1;
    349 	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
    350 #else /* CONFIG_CTRL_IFACE_UNIX */
    351 	flen = strlen(ctrl_iface) + 1;
    352 	cfile = (char *) malloc(flen);
    353 	if (cfile == NULL)
    354 		return -1;
    355 	snprintf(cfile, flen, "%s", ctrl_iface);
    356 #endif /* CONFIG_CTRL_IFACE_UNIX */
    357 
    358 	if (ctrl_conn) {
    359 		wpa_ctrl_close(ctrl_conn);
    360 		ctrl_conn = NULL;
    361 	}
    362 
    363 	if (monitor_conn) {
    364 		delete msgNotifier;
    365 		msgNotifier = NULL;
    366 		wpa_ctrl_detach(monitor_conn);
    367 		wpa_ctrl_close(monitor_conn);
    368 		monitor_conn = NULL;
    369 	}
    370 
    371 	printf("Trying to connect to '%s'\n", cfile);
    372 	ctrl_conn = wpa_ctrl_open(cfile);
    373 	if (ctrl_conn == NULL) {
    374 		free(cfile);
    375 		return -1;
    376 	}
    377 	monitor_conn = wpa_ctrl_open(cfile);
    378 	free(cfile);
    379 	if (monitor_conn == NULL) {
    380 		wpa_ctrl_close(ctrl_conn);
    381 		return -1;
    382 	}
    383 	if (wpa_ctrl_attach(monitor_conn)) {
    384 		printf("Failed to attach to wpa_supplicant\n");
    385 		wpa_ctrl_close(monitor_conn);
    386 		monitor_conn = NULL;
    387 		wpa_ctrl_close(ctrl_conn);
    388 		ctrl_conn = NULL;
    389 		return -1;
    390 	}
    391 
    392 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
    393 	msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
    394 					  QSocketNotifier::Read, this);
    395 	connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
    396 #endif
    397 
    398 	adapterSelect->clear();
    399 	adapterSelect->addItem(ctrl_iface);
    400 	adapterSelect->setCurrentIndex(0);
    401 
    402 	len = sizeof(buf) - 1;
    403 	if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
    404 	    0) {
    405 		buf[len] = '\0';
    406 		pos = buf;
    407 		while (*pos) {
    408 			pos2 = strchr(pos, '\n');
    409 			if (pos2)
    410 				*pos2 = '\0';
    411 			if (strcmp(pos, ctrl_iface) != 0)
    412 				adapterSelect->addItem(pos);
    413 			if (pos2)
    414 				pos = pos2 + 1;
    415 			else
    416 				break;
    417 		}
    418 	}
    419 
    420 	len = sizeof(buf) - 1;
    421 	if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len,
    422 			     NULL) >= 0) {
    423 		buf[len] = '\0';
    424 
    425 		QString res(buf);
    426 		QStringList types = res.split(QChar(' '));
    427 		bool wps = types.contains("WSC");
    428 		actionWPS->setEnabled(wps);
    429 		wpsTab->setEnabled(wps);
    430 		wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps);
    431 	}
    432 
    433 	return 0;
    434 }
    435 
    436 
    437 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
    438 {
    439 	int ret;
    440 
    441 	if (ctrl_conn == NULL)
    442 		return -3;
    443 	ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL);
    444 	if (ret == -2)
    445 		printf("'%s' command timed out.\n", cmd);
    446 	else if (ret < 0)
    447 		printf("'%s' command failed.\n", cmd);
    448 
    449 	return ret;
    450 }
    451 
    452 
    453 QString WpaGui::wpaStateTranslate(char *state)
    454 {
    455 	if (!strcmp(state, "DISCONNECTED"))
    456 		return tr("Disconnected");
    457 	else if (!strcmp(state, "INACTIVE"))
    458 		return tr("Inactive");
    459 	else if (!strcmp(state, "SCANNING"))
    460 		return tr("Scanning");
    461 	else if (!strcmp(state, "AUTHENTICATING"))
    462 		return tr("Authenticating");
    463 	else if (!strcmp(state, "ASSOCIATING"))
    464 		return tr("Associating");
    465 	else if (!strcmp(state, "ASSOCIATED"))
    466 		return tr("Associated");
    467 	else if (!strcmp(state, "4WAY_HANDSHAKE"))
    468 		return tr("4-Way Handshake");
    469 	else if (!strcmp(state, "GROUP_HANDSHAKE"))
    470 		return tr("Group Handshake");
    471 	else if (!strcmp(state, "COMPLETED"))
    472 		return tr("Completed");
    473 	else
    474 		return tr("Unknown");
    475 }
    476 
    477 
    478 void WpaGui::updateStatus()
    479 {
    480 	char buf[2048], *start, *end, *pos;
    481 	size_t len;
    482 
    483 	pingsToStatusUpdate = 10;
    484 
    485 	len = sizeof(buf) - 1;
    486 	if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
    487 		textStatus->setText(tr("Could not get status from "
    488 				       "wpa_supplicant"));
    489 		textAuthentication->clear();
    490 		textEncryption->clear();
    491 		textSsid->clear();
    492 		textBssid->clear();
    493 		textIpAddress->clear();
    494 
    495 #ifdef CONFIG_NATIVE_WINDOWS
    496 		static bool first = true;
    497 		if (first && connectedToService &&
    498 		    (ctrl_iface == NULL || *ctrl_iface == '\0')) {
    499 			first = false;
    500 			if (QMessageBox::information(
    501 				    this, qAppName(),
    502 				    tr("No network interfaces in use.\n"
    503 				       "Would you like to add one?"),
    504 				    QMessageBox::Yes | QMessageBox::No) ==
    505 			    QMessageBox::Yes)
    506 				addInterface();
    507 		}
    508 #endif /* CONFIG_NATIVE_WINDOWS */
    509 		return;
    510 	}
    511 
    512 	buf[len] = '\0';
    513 
    514 	bool auth_updated = false, ssid_updated = false;
    515 	bool bssid_updated = false, ipaddr_updated = false;
    516 	bool status_updated = false;
    517 	char *pairwise_cipher = NULL, *group_cipher = NULL;
    518 	char *mode = NULL;
    519 
    520 	start = buf;
    521 	while (*start) {
    522 		bool last = false;
    523 		end = strchr(start, '\n');
    524 		if (end == NULL) {
    525 			last = true;
    526 			end = start;
    527 			while (end[0] && end[1])
    528 				end++;
    529 		}
    530 		*end = '\0';
    531 
    532 		pos = strchr(start, '=');
    533 		if (pos) {
    534 			*pos++ = '\0';
    535 			if (strcmp(start, "bssid") == 0) {
    536 				bssid_updated = true;
    537 				textBssid->setText(pos);
    538 			} else if (strcmp(start, "ssid") == 0) {
    539 				ssid_updated = true;
    540 				textSsid->setText(pos);
    541 			} else if (strcmp(start, "ip_address") == 0) {
    542 				ipaddr_updated = true;
    543 				textIpAddress->setText(pos);
    544 			} else if (strcmp(start, "wpa_state") == 0) {
    545 				status_updated = true;
    546 				textStatus->setText(wpaStateTranslate(pos));
    547 			} else if (strcmp(start, "key_mgmt") == 0) {
    548 				auth_updated = true;
    549 				textAuthentication->setText(pos);
    550 				/* TODO: could add EAP status to this */
    551 			} else if (strcmp(start, "pairwise_cipher") == 0) {
    552 				pairwise_cipher = pos;
    553 			} else if (strcmp(start, "group_cipher") == 0) {
    554 				group_cipher = pos;
    555 			} else if (strcmp(start, "mode") == 0) {
    556 				mode = pos;
    557 			}
    558 		}
    559 
    560 		if (last)
    561 			break;
    562 		start = end + 1;
    563 	}
    564 	if (status_updated && mode)
    565 		textStatus->setText(textStatus->text() + " (" + mode + ")");
    566 
    567 	if (pairwise_cipher || group_cipher) {
    568 		QString encr;
    569 		if (pairwise_cipher && group_cipher &&
    570 		    strcmp(pairwise_cipher, group_cipher) != 0) {
    571 			encr.append(pairwise_cipher);
    572 			encr.append(" + ");
    573 			encr.append(group_cipher);
    574 		} else if (pairwise_cipher) {
    575 			encr.append(pairwise_cipher);
    576 		} else {
    577 			encr.append(group_cipher);
    578 			encr.append(" [group key only]");
    579 		}
    580 		textEncryption->setText(encr);
    581 	} else
    582 		textEncryption->clear();
    583 
    584 	if (!status_updated)
    585 		textStatus->clear();
    586 	if (!auth_updated)
    587 		textAuthentication->clear();
    588 	if (!ssid_updated)
    589 		textSsid->clear();
    590 	if (!bssid_updated)
    591 		textBssid->clear();
    592 	if (!ipaddr_updated)
    593 		textIpAddress->clear();
    594 }
    595 
    596 
    597 void WpaGui::updateNetworks()
    598 {
    599 	char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
    600 	size_t len;
    601 	int first_active = -1;
    602 	int was_selected = -1;
    603 	bool current = false;
    604 
    605 	if (!networkMayHaveChanged)
    606 		return;
    607 
    608 	if (networkList->currentRow() >= 0)
    609 		was_selected = networkList->currentRow();
    610 
    611 	networkSelect->clear();
    612 	networkList->clear();
    613 
    614 	if (ctrl_conn == NULL)
    615 		return;
    616 
    617 	len = sizeof(buf) - 1;
    618 	if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
    619 		return;
    620 
    621 	buf[len] = '\0';
    622 	start = strchr(buf, '\n');
    623 	if (start == NULL)
    624 		return;
    625 	start++;
    626 
    627 	while (*start) {
    628 		bool last = false;
    629 		end = strchr(start, '\n');
    630 		if (end == NULL) {
    631 			last = true;
    632 			end = start;
    633 			while (end[0] && end[1])
    634 				end++;
    635 		}
    636 		*end = '\0';
    637 
    638 		id = start;
    639 		ssid = strchr(id, '\t');
    640 		if (ssid == NULL)
    641 			break;
    642 		*ssid++ = '\0';
    643 		bssid = strchr(ssid, '\t');
    644 		if (bssid == NULL)
    645 			break;
    646 		*bssid++ = '\0';
    647 		flags = strchr(bssid, '\t');
    648 		if (flags == NULL)
    649 			break;
    650 		*flags++ = '\0';
    651 
    652 		if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) {
    653 			if (last)
    654 				break;
    655 			start = end + 1;
    656 			continue;
    657 		}
    658 
    659 		QString network(id);
    660 		network.append(": ");
    661 		network.append(ssid);
    662 		networkSelect->addItem(network);
    663 		networkList->addItem(network);
    664 
    665 		if (strstr(flags, "[CURRENT]")) {
    666 			networkSelect->setCurrentIndex(networkSelect->count() -
    667 						      1);
    668 			current = true;
    669 		} else if (first_active < 0 &&
    670 			   strstr(flags, "[DISABLED]") == NULL)
    671 			first_active = networkSelect->count() - 1;
    672 
    673 		if (last)
    674 			break;
    675 		start = end + 1;
    676 	}
    677 
    678 	if (networkSelect->count() > 1)
    679 		networkSelect->addItem(tr("Select any network"));
    680 
    681 	if (!current && first_active >= 0)
    682 		networkSelect->setCurrentIndex(first_active);
    683 
    684 	if (was_selected >= 0 && networkList->count() > 0) {
    685 		if (was_selected < networkList->count())
    686 			networkList->setCurrentRow(was_selected);
    687 		else
    688 			networkList->setCurrentRow(networkList->count() - 1);
    689 	}
    690 	else
    691 		networkList->setCurrentRow(networkSelect->currentIndex());
    692 
    693 	networkMayHaveChanged = false;
    694 }
    695 
    696 
    697 void WpaGui::helpIndex()
    698 {
    699 	printf("helpIndex\n");
    700 }
    701 
    702 
    703 void WpaGui::helpContents()
    704 {
    705 	printf("helpContents\n");
    706 }
    707 
    708 
    709 void WpaGui::helpAbout()
    710 {
    711 	QMessageBox::about(this, "wpa_gui for wpa_supplicant",
    712 			   "Copyright (c) 2003-2013,\n"
    713 			   "Jouni Malinen <j (at) w1.fi>\n"
    714 			   "and contributors.\n"
    715 			   "\n"
    716 			   "This software may be distributed under\n"
    717 			   "the terms of the BSD license.\n"
    718 			   "See README for more details.\n"
    719 			   "\n"
    720 			   "This product includes software developed\n"
    721 			   "by the OpenSSL Project for use in the\n"
    722 			   "OpenSSL Toolkit (http://www.openssl.org/)\n");
    723 }
    724 
    725 
    726 void WpaGui::disconnect()
    727 {
    728 	char reply[10];
    729 	size_t reply_len = sizeof(reply);
    730 	ctrlRequest("DISCONNECT", reply, &reply_len);
    731 	stopWpsRun(false);
    732 }
    733 
    734 
    735 void WpaGui::scan()
    736 {
    737 	if (scanres) {
    738 		scanres->close();
    739 		delete scanres;
    740 	}
    741 
    742 	scanres = new ScanResults();
    743 	if (scanres == NULL)
    744 		return;
    745 	scanres->setWpaGui(this);
    746 	scanres->show();
    747 	scanres->exec();
    748 }
    749 
    750 
    751 void WpaGui::eventHistory()
    752 {
    753 	if (eh) {
    754 		eh->close();
    755 		delete eh;
    756 	}
    757 
    758 	eh = new EventHistory();
    759 	if (eh == NULL)
    760 		return;
    761 	eh->addEvents(msgs);
    762 	eh->show();
    763 	eh->exec();
    764 }
    765 
    766 
    767 void WpaGui::ping()
    768 {
    769 	char buf[10];
    770 	size_t len;
    771 
    772 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    773 	/*
    774 	 * QSocketNotifier cannot be used with Windows named pipes, so use a
    775 	 * timer to check for received messages for now. This could be
    776 	 * optimized be doing something specific to named pipes or Windows
    777 	 * events, but it is not clear what would be the best way of doing that
    778 	 * in Qt.
    779 	 */
    780 	receiveMsgs();
    781 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    782 
    783 	if (scanres && !scanres->isVisible()) {
    784 		delete scanres;
    785 		scanres = NULL;
    786 	}
    787 
    788 	if (eh && !eh->isVisible()) {
    789 		delete eh;
    790 		eh = NULL;
    791 	}
    792 
    793 	if (udr && !udr->isVisible()) {
    794 		delete udr;
    795 		udr = NULL;
    796 	}
    797 
    798 	len = sizeof(buf) - 1;
    799 	if (ctrlRequest("PING", buf, &len) < 0) {
    800 		printf("PING failed - trying to reconnect\n");
    801 		if (openCtrlConnection(ctrl_iface) >= 0) {
    802 			printf("Reconnected successfully\n");
    803 			pingsToStatusUpdate = 0;
    804 		}
    805 	}
    806 
    807 	pingsToStatusUpdate--;
    808 	if (pingsToStatusUpdate <= 0) {
    809 		updateStatus();
    810 		updateNetworks();
    811 	}
    812 
    813 #ifndef CONFIG_CTRL_IFACE_NAMED_PIPE
    814 	/* Use less frequent pings and status updates when the main window is
    815 	 * hidden (running in taskbar). */
    816 	int interval = isHidden() ? 5000 : 1000;
    817 	if (timer->interval() != interval)
    818 		timer->setInterval(interval);
    819 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    820 }
    821 
    822 
    823 static int str_match(const char *a, const char *b)
    824 {
    825 	return strncmp(a, b, strlen(b)) == 0;
    826 }
    827 
    828 
    829 void WpaGui::processMsg(char *msg)
    830 {
    831 	char *pos = msg, *pos2;
    832 	int priority = 2;
    833 
    834 	if (*pos == '<') {
    835 		/* skip priority */
    836 		pos++;
    837 		priority = atoi(pos);
    838 		pos = strchr(pos, '>');
    839 		if (pos)
    840 			pos++;
    841 		else
    842 			pos = msg;
    843 	}
    844 
    845 	WpaMsg wm(pos, priority);
    846 	if (eh)
    847 		eh->addEvent(wm);
    848 	if (peers)
    849 		peers->event_notify(wm);
    850 	msgs.append(wm);
    851 	while (msgs.count() > 100)
    852 		msgs.pop_front();
    853 
    854 	/* Update last message with truncated version of the event */
    855 	if (strncmp(pos, "CTRL-", 5) == 0) {
    856 		pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
    857 		if (pos2)
    858 			pos2++;
    859 		else
    860 			pos2 = pos;
    861 	} else
    862 		pos2 = pos;
    863 	QString lastmsg = pos2;
    864 	lastmsg.truncate(40);
    865 	textLastMessage->setText(lastmsg);
    866 
    867 	pingsToStatusUpdate = 0;
    868 	networkMayHaveChanged = true;
    869 
    870 	if (str_match(pos, WPA_CTRL_REQ))
    871 		processCtrlReq(pos + strlen(WPA_CTRL_REQ));
    872 	else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres)
    873 		scanres->updateResults();
    874 	else if (str_match(pos, WPA_EVENT_DISCONNECTED))
    875 		showTrayMessage(QSystemTrayIcon::Information, 3,
    876 				tr("Disconnected from network."));
    877 	else if (str_match(pos, WPA_EVENT_CONNECTED)) {
    878 		showTrayMessage(QSystemTrayIcon::Information, 3,
    879 				tr("Connection to network established."));
    880 		QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus()));
    881 		stopWpsRun(true);
    882 	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) {
    883 		wpsStatusText->setText(tr("WPS AP in active PBC mode found"));
    884 		if (textStatus->text() == "INACTIVE" ||
    885 		    textStatus->text() == "DISCONNECTED")
    886 			wpaguiTab->setCurrentWidget(wpsTab);
    887 		wpsInstructions->setText(tr("Press the PBC button on the "
    888 					    "screen to start registration"));
    889 	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) {
    890 		wpsStatusText->setText(tr("WPS AP with recently selected "
    891 					  "registrar"));
    892 		if (textStatus->text() == "INACTIVE" ||
    893 		    textStatus->text() == "DISCONNECTED")
    894 			wpaguiTab->setCurrentWidget(wpsTab);
    895 	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) {
    896 		showTrayMessage(QSystemTrayIcon::Information, 3,
    897 				"Wi-Fi Protected Setup (WPS) AP\n"
    898 				"indicating this client is authorized.");
    899 		wpsStatusText->setText("WPS AP indicating this client is "
    900 				       "authorized");
    901 		if (textStatus->text() == "INACTIVE" ||
    902 		    textStatus->text() == "DISCONNECTED")
    903 			wpaguiTab->setCurrentWidget(wpsTab);
    904 	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
    905 		wpsStatusText->setText(tr("WPS AP detected"));
    906 	} else if (str_match(pos, WPS_EVENT_OVERLAP)) {
    907 		wpsStatusText->setText(tr("PBC mode overlap detected"));
    908 		wpsInstructions->setText(tr("More than one AP is currently in "
    909 					    "active WPS PBC mode. Wait couple "
    910 					    "of minutes and try again"));
    911 		wpaguiTab->setCurrentWidget(wpsTab);
    912 	} else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) {
    913 		wpsStatusText->setText(tr("Network configuration received"));
    914 		wpaguiTab->setCurrentWidget(wpsTab);
    915 	} else if (str_match(pos, WPA_EVENT_EAP_METHOD)) {
    916 		if (strstr(pos, "(WSC)"))
    917 			wpsStatusText->setText(tr("Registration started"));
    918 	} else if (str_match(pos, WPS_EVENT_M2D)) {
    919 		wpsStatusText->setText(tr("Registrar does not yet know PIN"));
    920 	} else if (str_match(pos, WPS_EVENT_FAIL)) {
    921 		wpsStatusText->setText(tr("Registration failed"));
    922 	} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
    923 		wpsStatusText->setText(tr("Registration succeeded"));
    924 	}
    925 }
    926 
    927 
    928 void WpaGui::processCtrlReq(const char *req)
    929 {
    930 	if (udr) {
    931 		udr->close();
    932 		delete udr;
    933 	}
    934 	udr = new UserDataRequest();
    935 	if (udr == NULL)
    936 		return;
    937 	if (udr->setParams(this, req) < 0) {
    938 		delete udr;
    939 		udr = NULL;
    940 		return;
    941 	}
    942 	udr->show();
    943 	udr->exec();
    944 }
    945 
    946 
    947 void WpaGui::receiveMsgs()
    948 {
    949 	char buf[256];
    950 	size_t len;
    951 
    952 	while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
    953 		len = sizeof(buf) - 1;
    954 		if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
    955 			buf[len] = '\0';
    956 			processMsg(buf);
    957 		}
    958 	}
    959 }
    960 
    961 
    962 void WpaGui::connectB()
    963 {
    964 	char reply[10];
    965 	size_t reply_len = sizeof(reply);
    966 	ctrlRequest("REASSOCIATE", reply, &reply_len);
    967 }
    968 
    969 
    970 void WpaGui::selectNetwork( const QString &sel )
    971 {
    972 	QString cmd(sel);
    973 	char reply[10];
    974 	size_t reply_len = sizeof(reply);
    975 
    976 	if (cmd.contains(QRegExp("^\\d+:")))
    977 		cmd.truncate(cmd.indexOf(':'));
    978 	else
    979 		cmd = "any";
    980 	cmd.prepend("SELECT_NETWORK ");
    981 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
    982 	triggerUpdate();
    983 	stopWpsRun(false);
    984 }
    985 
    986 
    987 void WpaGui::enableNetwork(const QString &sel)
    988 {
    989 	QString cmd(sel);
    990 	char reply[10];
    991 	size_t reply_len = sizeof(reply);
    992 
    993 	if (cmd.contains(QRegExp("^\\d+:")))
    994 		cmd.truncate(cmd.indexOf(':'));
    995 	else if (!cmd.startsWith("all")) {
    996 		printf("Invalid editNetwork '%s'\n",
    997 		       cmd.toAscii().constData());
    998 		return;
    999 	}
   1000 	cmd.prepend("ENABLE_NETWORK ");
   1001 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
   1002 	triggerUpdate();
   1003 }
   1004 
   1005 
   1006 void WpaGui::disableNetwork(const QString &sel)
   1007 {
   1008 	QString cmd(sel);
   1009 	char reply[10];
   1010 	size_t reply_len = sizeof(reply);
   1011 
   1012 	if (cmd.contains(QRegExp("^\\d+:")))
   1013 		cmd.truncate(cmd.indexOf(':'));
   1014 	else if (!cmd.startsWith("all")) {
   1015 		printf("Invalid editNetwork '%s'\n",
   1016 		       cmd.toAscii().constData());
   1017 		return;
   1018 	}
   1019 	cmd.prepend("DISABLE_NETWORK ");
   1020 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
   1021 	triggerUpdate();
   1022 }
   1023 
   1024 
   1025 void WpaGui::editNetwork(const QString &sel)
   1026 {
   1027 	QString cmd(sel);
   1028 	int id = -1;
   1029 
   1030 	if (cmd.contains(QRegExp("^\\d+:"))) {
   1031 		cmd.truncate(cmd.indexOf(':'));
   1032 		id = cmd.toInt();
   1033 	}
   1034 
   1035 	NetworkConfig *nc = new NetworkConfig();
   1036 	if (nc == NULL)
   1037 		return;
   1038 	nc->setWpaGui(this);
   1039 
   1040 	if (id >= 0)
   1041 		nc->paramsFromConfig(id);
   1042 	else
   1043 		nc->newNetwork();
   1044 
   1045 	nc->show();
   1046 	nc->exec();
   1047 }
   1048 
   1049 
   1050 void WpaGui::editSelectedNetwork()
   1051 {
   1052 	if (networkSelect->count() < 1) {
   1053 		QMessageBox::information(
   1054 			this, tr("No Networks"),
   1055 			tr("There are no networks to edit.\n"));
   1056 		return;
   1057 	}
   1058 	QString sel(networkSelect->currentText());
   1059 	editNetwork(sel);
   1060 }
   1061 
   1062 
   1063 void WpaGui::editListedNetwork()
   1064 {
   1065 	if (networkList->currentRow() < 0) {
   1066 		QMessageBox::information(this, tr("Select A Network"),
   1067 					 tr("Select a network from the list to"
   1068 					    " edit it.\n"));
   1069 		return;
   1070 	}
   1071 	QString sel(networkList->currentItem()->text());
   1072 	editNetwork(sel);
   1073 }
   1074 
   1075 
   1076 void WpaGui::triggerUpdate()
   1077 {
   1078 	updateStatus();
   1079 	networkMayHaveChanged = true;
   1080 	updateNetworks();
   1081 }
   1082 
   1083 
   1084 void WpaGui::addNetwork()
   1085 {
   1086 	NetworkConfig *nc = new NetworkConfig();
   1087 	if (nc == NULL)
   1088 		return;
   1089 	nc->setWpaGui(this);
   1090 	nc->newNetwork();
   1091 	nc->show();
   1092 	nc->exec();
   1093 }
   1094 
   1095 
   1096 void WpaGui::removeNetwork(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 		printf("Invalid editNetwork '%s'\n",
   1106 		       cmd.toAscii().constData());
   1107 		return;
   1108 	}
   1109 	cmd.prepend("REMOVE_NETWORK ");
   1110 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
   1111 	triggerUpdate();
   1112 }
   1113 
   1114 
   1115 void WpaGui::removeSelectedNetwork()
   1116 {
   1117 	if (networkSelect->count() < 1) {
   1118 		QMessageBox::information(this, tr("No Networks"),
   1119 			                 tr("There are no networks to remove."
   1120 					    "\n"));
   1121 		return;
   1122 	}
   1123 	QString sel(networkSelect->currentText());
   1124 	removeNetwork(sel);
   1125 }
   1126 
   1127 
   1128 void WpaGui::removeListedNetwork()
   1129 {
   1130 	if (networkList->currentRow() < 0) {
   1131 		QMessageBox::information(this, tr("Select A Network"),
   1132 					 tr("Select a network from the list "
   1133 					    "to remove it.\n"));
   1134 		return;
   1135 	}
   1136 	QString sel(networkList->currentItem()->text());
   1137 	removeNetwork(sel);
   1138 }
   1139 
   1140 
   1141 void WpaGui::enableAllNetworks()
   1142 {
   1143 	QString sel("all");
   1144 	enableNetwork(sel);
   1145 }
   1146 
   1147 
   1148 void WpaGui::disableAllNetworks()
   1149 {
   1150 	QString sel("all");
   1151 	disableNetwork(sel);
   1152 }
   1153 
   1154 
   1155 void WpaGui::removeAllNetworks()
   1156 {
   1157 	QString sel("all");
   1158 	removeNetwork(sel);
   1159 }
   1160 
   1161 
   1162 int WpaGui::getNetworkDisabled(const QString &sel)
   1163 {
   1164 	QString cmd(sel);
   1165 	char reply[10];
   1166 	size_t reply_len = sizeof(reply) - 1;
   1167 	int pos = cmd.indexOf(':');
   1168 	if (pos < 0) {
   1169 		printf("Invalid getNetworkDisabled '%s'\n",
   1170 		       cmd.toAscii().constData());
   1171 		return -1;
   1172 	}
   1173 	cmd.truncate(pos);
   1174 	cmd.prepend("GET_NETWORK ");
   1175 	cmd.append(" disabled");
   1176 
   1177 	if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0
   1178 	    && reply_len >= 1) {
   1179 		reply[reply_len] = '\0';
   1180 		if (!str_match(reply, "FAIL"))
   1181 			return atoi(reply);
   1182 	}
   1183 
   1184 	return -1;
   1185 }
   1186 
   1187 
   1188 void WpaGui::updateNetworkDisabledStatus()
   1189 {
   1190 	if (networkList->currentRow() < 0)
   1191 		return;
   1192 
   1193 	QString sel(networkList->currentItem()->text());
   1194 
   1195 	switch (getNetworkDisabled(sel)) {
   1196 	case 0:
   1197 		if (!enableRadioButton->isChecked())
   1198 			enableRadioButton->setChecked(true);
   1199 		return;
   1200 	case 1:
   1201 		if (!disableRadioButton->isChecked())
   1202 			disableRadioButton->setChecked(true);
   1203 		return;
   1204 	}
   1205 }
   1206 
   1207 
   1208 void WpaGui::enableListedNetwork(bool enabled)
   1209 {
   1210 	if (networkList->currentRow() < 0 || !enabled)
   1211 		return;
   1212 
   1213 	QString sel(networkList->currentItem()->text());
   1214 
   1215 	if (getNetworkDisabled(sel) == 1)
   1216 		enableNetwork(sel);
   1217 }
   1218 
   1219 
   1220 void WpaGui::disableListedNetwork(bool disabled)
   1221 {
   1222 	if (networkList->currentRow() < 0 || !disabled)
   1223 		return;
   1224 
   1225 	QString sel(networkList->currentItem()->text());
   1226 
   1227 	if (getNetworkDisabled(sel) == 0)
   1228 		disableNetwork(sel);
   1229 }
   1230 
   1231 
   1232 void WpaGui::saveConfig()
   1233 {
   1234 	char buf[10];
   1235 	size_t len;
   1236 
   1237 	len = sizeof(buf) - 1;
   1238 	ctrlRequest("SAVE_CONFIG", buf, &len);
   1239 
   1240 	buf[len] = '\0';
   1241 
   1242 	if (str_match(buf, "FAIL"))
   1243 		QMessageBox::warning(
   1244 			this, tr("Failed to save configuration"),
   1245 			tr("The configuration could not be saved.\n"
   1246 			   "\n"
   1247 			   "The update_config=1 configuration option\n"
   1248 			   "must be used for configuration saving to\n"
   1249 			   "be permitted.\n"));
   1250 	else
   1251 		QMessageBox::information(
   1252 			this, tr("Saved configuration"),
   1253 			tr("The current configuration was saved."
   1254 			   "\n"));
   1255 }
   1256 
   1257 
   1258 void WpaGui::selectAdapter( const QString & sel )
   1259 {
   1260 	if (openCtrlConnection(sel.toAscii().constData()) < 0)
   1261 		printf("Failed to open control connection to "
   1262 		       "wpa_supplicant.\n");
   1263 	updateStatus();
   1264 	updateNetworks();
   1265 }
   1266 
   1267 
   1268 void WpaGui::createTrayIcon(bool trayOnly)
   1269 {
   1270 	QApplication::setQuitOnLastWindowClosed(false);
   1271 
   1272 	tray_icon = new QSystemTrayIcon(this);
   1273 	tray_icon->setToolTip(qAppName() + tr(" - wpa_supplicant user interface"));
   1274 	if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
   1275 		tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
   1276 	else
   1277 		tray_icon->setIcon(QIcon(":/icons/wpa_gui.png"));
   1278 
   1279 	connect(tray_icon,
   1280 		SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
   1281 		this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
   1282 
   1283 	ackTrayIcon = false;
   1284 
   1285 	tray_menu = new QMenu(this);
   1286 
   1287 	disconnectAction = new QAction(tr("&Disconnect"), this);
   1288 	reconnectAction = new QAction(tr("Re&connect"), this);
   1289 	connect(disconnectAction, SIGNAL(triggered()), this,
   1290 		SLOT(disconnect()));
   1291 	connect(reconnectAction, SIGNAL(triggered()), this,
   1292 		SLOT(connectB()));
   1293 	tray_menu->addAction(disconnectAction);
   1294 	tray_menu->addAction(reconnectAction);
   1295 	tray_menu->addSeparator();
   1296 
   1297 	eventAction = new QAction(tr("&Event History"), this);
   1298 	scanAction = new QAction(tr("Scan &Results"), this);
   1299 	statAction = new QAction(tr("S&tatus"), this);
   1300 	connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
   1301 	connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
   1302 	connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
   1303 	tray_menu->addAction(eventAction);
   1304 	tray_menu->addAction(scanAction);
   1305 	tray_menu->addAction(statAction);
   1306 	tray_menu->addSeparator();
   1307 
   1308 	showAction = new QAction(tr("&Show Window"), this);
   1309 	hideAction = new QAction(tr("&Hide Window"), this);
   1310 	quitAction = new QAction(tr("&Quit"), this);
   1311 	connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
   1312 	connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
   1313 	connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
   1314 	tray_menu->addAction(showAction);
   1315 	tray_menu->addAction(hideAction);
   1316 	tray_menu->addSeparator();
   1317 	tray_menu->addAction(quitAction);
   1318 
   1319 	tray_icon->setContextMenu(tray_menu);
   1320 
   1321 	tray_icon->show();
   1322 
   1323 	if (!trayOnly)
   1324 		show();
   1325 	inTray = trayOnly;
   1326 }
   1327 
   1328 
   1329 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
   1330 			     const QString & msg)
   1331 {
   1332 	if (!QSystemTrayIcon::supportsMessages())
   1333 		return;
   1334 
   1335 	if (isVisible() || !tray_icon || !tray_icon->isVisible())
   1336 		return;
   1337 
   1338 	tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
   1339 }
   1340 
   1341 
   1342 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
   1343  {
   1344 	switch (how) {
   1345 	/* use close() here instead of hide() and allow the
   1346 	 * custom closeEvent handler take care of children */
   1347 	case QSystemTrayIcon::Trigger:
   1348 		ackTrayIcon = true;
   1349 		if (isVisible()) {
   1350 			close();
   1351 			inTray = true;
   1352 		} else {
   1353 			show();
   1354 			inTray = false;
   1355 		}
   1356 		break;
   1357 	case QSystemTrayIcon::MiddleClick:
   1358 		showTrayStatus();
   1359 		break;
   1360 	default:
   1361 		break;
   1362 	}
   1363 }
   1364 
   1365 
   1366 void WpaGui::showTrayStatus()
   1367 {
   1368 	char buf[2048];
   1369 	size_t len;
   1370 
   1371 	len = sizeof(buf) - 1;
   1372 	if (ctrlRequest("STATUS", buf, &len) < 0)
   1373 		return;
   1374 	buf[len] = '\0';
   1375 
   1376 	QString msg, status(buf);
   1377 
   1378 	QStringList lines = status.split(QRegExp("\\n"));
   1379 	for (QStringList::Iterator it = lines.begin();
   1380 	     it != lines.end(); it++) {
   1381 		int pos = (*it).indexOf('=') + 1;
   1382 		if (pos < 1)
   1383 			continue;
   1384 
   1385 		if ((*it).startsWith("bssid="))
   1386 			msg.append("BSSID:\t" + (*it).mid(pos) + "\n");
   1387 		else if ((*it).startsWith("ssid="))
   1388 			msg.append("SSID: \t" + (*it).mid(pos) + "\n");
   1389 		else if ((*it).startsWith("pairwise_cipher="))
   1390 			msg.append("PAIR: \t" + (*it).mid(pos) + "\n");
   1391 		else if ((*it).startsWith("group_cipher="))
   1392 			msg.append("GROUP:\t" + (*it).mid(pos) + "\n");
   1393 		else if ((*it).startsWith("key_mgmt="))
   1394 			msg.append("AUTH: \t" + (*it).mid(pos) + "\n");
   1395 		else if ((*it).startsWith("wpa_state="))
   1396 			msg.append("STATE:\t" + (*it).mid(pos) + "\n");
   1397 		else if ((*it).startsWith("ip_address="))
   1398 			msg.append("IP:   \t" + (*it).mid(pos) + "\n");
   1399 		else if ((*it).startsWith("Supplicant PAE state="))
   1400 			msg.append("PAE:  \t" + (*it).mid(pos) + "\n");
   1401 		else if ((*it).startsWith("EAP state="))
   1402 			msg.append("EAP:  \t" + (*it).mid(pos) + "\n");
   1403 	}
   1404 
   1405 	if (!msg.isEmpty())
   1406 		showTrayMessage(QSystemTrayIcon::Information, 10, msg);
   1407 }
   1408 
   1409 
   1410 void WpaGui::closeEvent(QCloseEvent *event)
   1411 {
   1412 	if (eh) {
   1413 		eh->close();
   1414 		delete eh;
   1415 		eh = NULL;
   1416 	}
   1417 
   1418 	if (scanres) {
   1419 		scanres->close();
   1420 		delete scanres;
   1421 		scanres = NULL;
   1422 	}
   1423 
   1424 	if (peers) {
   1425 		peers->close();
   1426 		delete peers;
   1427 		peers = NULL;
   1428 	}
   1429 
   1430 	if (udr) {
   1431 		udr->close();
   1432 		delete udr;
   1433 		udr = NULL;
   1434 	}
   1435 
   1436 	if (tray_icon && !ackTrayIcon) {
   1437 		/* give user a visual hint that the tray icon exists */
   1438 		if (QSystemTrayIcon::supportsMessages()) {
   1439 			hide();
   1440 			showTrayMessage(QSystemTrayIcon::Information, 3,
   1441 					qAppName() +
   1442 					tr(" will keep running in "
   1443 					   "the system tray."));
   1444 		} else {
   1445 			QMessageBox::information(this, qAppName() +
   1446 						 tr(" systray"),
   1447 						 tr("The program will keep "
   1448 						    "running in the system "
   1449 						    "tray."));
   1450 		}
   1451 		ackTrayIcon = true;
   1452 	}
   1453 
   1454 	event->accept();
   1455 }
   1456 
   1457 
   1458 void WpaGui::wpsDialog()
   1459 {
   1460 	wpaguiTab->setCurrentWidget(wpsTab);
   1461 }
   1462 
   1463 
   1464 void WpaGui::peersDialog()
   1465 {
   1466 	if (peers) {
   1467 		peers->close();
   1468 		delete peers;
   1469 	}
   1470 
   1471 	peers = new Peers();
   1472 	if (peers == NULL)
   1473 		return;
   1474 	peers->setWpaGui(this);
   1475 	peers->show();
   1476 	peers->exec();
   1477 }
   1478 
   1479 
   1480 void WpaGui::tabChanged(int index)
   1481 {
   1482 	if (index != 2)
   1483 		return;
   1484 
   1485 	if (wpsRunning)
   1486 		return;
   1487 
   1488 	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
   1489 	if (bssFromScan.isEmpty())
   1490 		wpsApPinButton->setEnabled(false);
   1491 }
   1492 
   1493 
   1494 void WpaGui::wpsPbc()
   1495 {
   1496 	char reply[20];
   1497 	size_t reply_len = sizeof(reply);
   1498 
   1499 	if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
   1500 		return;
   1501 
   1502 	wpsPinEdit->setEnabled(false);
   1503 	if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) {
   1504 		wpsInstructions->setText(tr("Press the push button on the AP to "
   1505 					 "start the PBC mode."));
   1506 	} else {
   1507 		wpsInstructions->setText(tr("If you have not yet done so, press "
   1508 					 "the push button on the AP to start "
   1509 					 "the PBC mode."));
   1510 	}
   1511 	wpsStatusText->setText(tr("Waiting for Registrar"));
   1512 	wpsRunning = true;
   1513 }
   1514 
   1515 
   1516 void WpaGui::wpsGeneratePin()
   1517 {
   1518 	char reply[20];
   1519 	size_t reply_len = sizeof(reply) - 1;
   1520 
   1521 	if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
   1522 		return;
   1523 
   1524 	reply[reply_len] = '\0';
   1525 
   1526 	wpsPinEdit->setText(reply);
   1527 	wpsPinEdit->setEnabled(true);
   1528 	wpsInstructions->setText(tr("Enter the generated PIN into the Registrar "
   1529 				 "(either the internal one in the AP or an "
   1530 				 "external one)."));
   1531 	wpsStatusText->setText(tr("Waiting for Registrar"));
   1532 	wpsRunning = true;
   1533 }
   1534 
   1535 
   1536 void WpaGui::setBssFromScan(const QString &bssid)
   1537 {
   1538 	bssFromScan = bssid;
   1539 	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
   1540 	wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
   1541 	wpsStatusText->setText(tr("WPS AP selected from scan results"));
   1542 	wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., "
   1543 				 "from a label in the device, enter the eight "
   1544 				 "digit AP PIN and click Use AP PIN button."));
   1545 }
   1546 
   1547 
   1548 void WpaGui::wpsApPinChanged(const QString &text)
   1549 {
   1550 	wpsApPinButton->setEnabled(text.length() == 8);
   1551 }
   1552 
   1553 
   1554 void WpaGui::wpsApPin()
   1555 {
   1556 	char reply[20];
   1557 	size_t reply_len = sizeof(reply);
   1558 
   1559 	QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
   1560 	if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0)
   1561 		return;
   1562 
   1563 	wpsStatusText->setText(tr("Waiting for AP/Enrollee"));
   1564 	wpsRunning = true;
   1565 }
   1566 
   1567 
   1568 void WpaGui::stopWpsRun(bool success)
   1569 {
   1570 	if (wpsRunning)
   1571 		wpsStatusText->setText(success ? tr("Connected to the network") :
   1572 				       tr("Stopped"));
   1573 	else
   1574 		wpsStatusText->setText("");
   1575 	wpsPinEdit->setEnabled(false);
   1576 	wpsInstructions->setText("");
   1577 	wpsRunning = false;
   1578 	bssFromScan = "";
   1579 	wpsApPinEdit->setEnabled(false);
   1580 	wpsApPinButton->setEnabled(false);
   1581 }
   1582 
   1583 
   1584 #ifdef CONFIG_NATIVE_WINDOWS
   1585 
   1586 #ifndef WPASVC_NAME
   1587 #define WPASVC_NAME TEXT("wpasvc")
   1588 #endif
   1589 
   1590 class ErrorMsg : public QMessageBox {
   1591 public:
   1592 	ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
   1593 	void showMsg(QString msg);
   1594 private:
   1595 	DWORD err;
   1596 };
   1597 
   1598 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
   1599 	QMessageBox(parent), err(last_err)
   1600 {
   1601 	setWindowTitle(tr("wpa_gui error"));
   1602 	setIcon(QMessageBox::Warning);
   1603 }
   1604 
   1605 void ErrorMsg::showMsg(QString msg)
   1606 {
   1607 	LPTSTR buf;
   1608 
   1609 	setText(msg);
   1610 	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
   1611 			  FORMAT_MESSAGE_FROM_SYSTEM,
   1612 			  NULL, err, 0, (LPTSTR) (void *) &buf,
   1613 			  0, NULL) > 0) {
   1614 		QString msg = QString::fromWCharArray(buf);
   1615 		setInformativeText(QString("[%1] %2").arg(err).arg(msg));
   1616 		LocalFree(buf);
   1617 	} else {
   1618 		setInformativeText(QString("[%1]").arg(err));
   1619 	}
   1620 
   1621 	exec();
   1622 }
   1623 
   1624 
   1625 void WpaGui::startService()
   1626 {
   1627 	SC_HANDLE svc, scm;
   1628 
   1629 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
   1630 	if (!scm) {
   1631 		ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
   1632 		return;
   1633 	}
   1634 
   1635 	svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
   1636 	if (!svc) {
   1637 		ErrorMsg(this).showMsg(tr("OpenService failed"));
   1638 		CloseServiceHandle(scm);
   1639 		return;
   1640 	}
   1641 
   1642 	if (!StartService(svc, 0, NULL)) {
   1643 		ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant "
   1644 				       "service"));
   1645 	}
   1646 
   1647 	CloseServiceHandle(svc);
   1648 	CloseServiceHandle(scm);
   1649 }
   1650 
   1651 
   1652 void WpaGui::stopService()
   1653 {
   1654 	SC_HANDLE svc, scm;
   1655 	SERVICE_STATUS status;
   1656 
   1657 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
   1658 	if (!scm) {
   1659 		ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
   1660 		return;
   1661 	}
   1662 
   1663 	svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
   1664 	if (!svc) {
   1665 		ErrorMsg(this).showMsg(tr("OpenService failed"));
   1666 		CloseServiceHandle(scm);
   1667 		return;
   1668 	}
   1669 
   1670 	if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
   1671 		ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant "
   1672 				       "service"));
   1673 	}
   1674 
   1675 	CloseServiceHandle(svc);
   1676 	CloseServiceHandle(scm);
   1677 }
   1678 
   1679 
   1680 bool WpaGui::serviceRunning()
   1681 {
   1682 	SC_HANDLE svc, scm;
   1683 	SERVICE_STATUS status;
   1684 	bool running = false;
   1685 
   1686 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
   1687 	if (!scm) {
   1688 		printf("OpenSCManager failed: %d\n", (int) GetLastError());
   1689 		return false;
   1690 	}
   1691 
   1692 	svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
   1693 	if (!svc) {
   1694 		printf("OpenService failed: %d\n\n", (int) GetLastError());
   1695 		CloseServiceHandle(scm);
   1696 		return false;
   1697 	}
   1698 
   1699 	if (QueryServiceStatus(svc, &status)) {
   1700 		if (status.dwCurrentState != SERVICE_STOPPED)
   1701 			running = true;
   1702 	}
   1703 
   1704 	CloseServiceHandle(svc);
   1705 	CloseServiceHandle(scm);
   1706 
   1707 	return running;
   1708 }
   1709 
   1710 #endif /* CONFIG_NATIVE_WINDOWS */
   1711 
   1712 
   1713 void WpaGui::addInterface()
   1714 {
   1715 	if (add_iface) {
   1716 		add_iface->close();
   1717 		delete add_iface;
   1718 	}
   1719 	add_iface = new AddInterface(this, this);
   1720 	add_iface->show();
   1721 	add_iface->exec();
   1722 }
   1723 
   1724 
   1725 #ifndef QT_NO_SESSIONMANAGER
   1726 void WpaGui::saveState()
   1727 {
   1728 	QSettings settings("wpa_supplicant", "wpa_gui");
   1729 	settings.beginGroup("state");
   1730 	settings.setValue("session_id", app->sessionId());
   1731 	settings.setValue("in_tray", inTray);
   1732 	settings.endGroup();
   1733 }
   1734 #endif
   1735