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