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