xref: /netbsd-src/external/bsd/wpa/dist/wpa_supplicant/wpa_gui-qt4/wpagui.cpp (revision 7a6a7ae08ac6c612f0fbb0d4425825c6be2a9050)
1 /*
2  * wpa_gui - WpaGui class
3  * Copyright (c) 2005-2008, Jouni Malinen <j@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 		QString network(id);
663 		network.append(": ");
664 		network.append(ssid);
665 		networkSelect->addItem(network);
666 		networkList->addItem(network);
667 
668 		if (strstr(flags, "[CURRENT]")) {
669 			networkSelect->setCurrentIndex(networkSelect->count() -
670 						      1);
671 			current = true;
672 		} else if (first_active < 0 &&
673 			   strstr(flags, "[DISABLED]") == NULL)
674 			first_active = networkSelect->count() - 1;
675 
676 		if (last)
677 			break;
678 		start = end + 1;
679 	}
680 
681 	if (networkSelect->count() > 1)
682 		networkSelect->addItem(tr("Select any network"));
683 
684 	if (!current && first_active >= 0)
685 		networkSelect->setCurrentIndex(first_active);
686 
687 	if (was_selected >= 0 && networkList->count() > 0) {
688 		if (was_selected < networkList->count())
689 			networkList->setCurrentRow(was_selected);
690 		else
691 			networkList->setCurrentRow(networkList->count() - 1);
692 	}
693 	else
694 		networkList->setCurrentRow(networkSelect->currentIndex());
695 
696 	networkMayHaveChanged = false;
697 }
698 
699 
700 void WpaGui::helpIndex()
701 {
702 	printf("helpIndex\n");
703 }
704 
705 
706 void WpaGui::helpContents()
707 {
708 	printf("helpContents\n");
709 }
710 
711 
712 void WpaGui::helpAbout()
713 {
714 	QMessageBox::about(this, "wpa_gui for wpa_supplicant",
715 			   "Copyright (c) 2003-2008,\n"
716 			   "Jouni Malinen <j@w1.fi>\n"
717 			   "and contributors.\n"
718 			   "\n"
719 			   "This program is free software. You can\n"
720 			   "distribute it and/or modify it under the terms "
721 			   "of\n"
722 			   "the GNU General Public License version 2.\n"
723 			   "\n"
724 			   "Alternatively, this software may be distributed\n"
725 			   "under the terms of the BSD license.\n"
726 			   "\n"
727 			   "This product includes software developed\n"
728 			   "by the OpenSSL Project for use in the\n"
729 			   "OpenSSL Toolkit (http://www.openssl.org/)\n");
730 }
731 
732 
733 void WpaGui::disconnect()
734 {
735 	char reply[10];
736 	size_t reply_len = sizeof(reply);
737 	ctrlRequest("DISCONNECT", reply, &reply_len);
738 	stopWpsRun(false);
739 }
740 
741 
742 void WpaGui::scan()
743 {
744 	if (scanres) {
745 		scanres->close();
746 		delete scanres;
747 	}
748 
749 	scanres = new ScanResults();
750 	if (scanres == NULL)
751 		return;
752 	scanres->setWpaGui(this);
753 	scanres->show();
754 	scanres->exec();
755 }
756 
757 
758 void WpaGui::eventHistory()
759 {
760 	if (eh) {
761 		eh->close();
762 		delete eh;
763 	}
764 
765 	eh = new EventHistory();
766 	if (eh == NULL)
767 		return;
768 	eh->addEvents(msgs);
769 	eh->show();
770 	eh->exec();
771 }
772 
773 
774 void WpaGui::ping()
775 {
776 	char buf[10];
777 	size_t len;
778 
779 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
780 	/*
781 	 * QSocketNotifier cannot be used with Windows named pipes, so use a
782 	 * timer to check for received messages for now. This could be
783 	 * optimized be doing something specific to named pipes or Windows
784 	 * events, but it is not clear what would be the best way of doing that
785 	 * in Qt.
786 	 */
787 	receiveMsgs();
788 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
789 
790 	if (scanres && !scanres->isVisible()) {
791 		delete scanres;
792 		scanres = NULL;
793 	}
794 
795 	if (eh && !eh->isVisible()) {
796 		delete eh;
797 		eh = NULL;
798 	}
799 
800 	if (udr && !udr->isVisible()) {
801 		delete udr;
802 		udr = NULL;
803 	}
804 
805 	len = sizeof(buf) - 1;
806 	if (ctrlRequest("PING", buf, &len) < 0) {
807 		printf("PING failed - trying to reconnect\n");
808 		if (openCtrlConnection(ctrl_iface) >= 0) {
809 			printf("Reconnected successfully\n");
810 			pingsToStatusUpdate = 0;
811 		}
812 	}
813 
814 	pingsToStatusUpdate--;
815 	if (pingsToStatusUpdate <= 0) {
816 		updateStatus();
817 		updateNetworks();
818 	}
819 
820 #ifndef CONFIG_CTRL_IFACE_NAMED_PIPE
821 	/* Use less frequent pings and status updates when the main window is
822 	 * hidden (running in taskbar). */
823 	int interval = isHidden() ? 5000 : 1000;
824 	if (timer->interval() != interval)
825 		timer->setInterval(interval);
826 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
827 }
828 
829 
830 static int str_match(const char *a, const char *b)
831 {
832 	return strncmp(a, b, strlen(b)) == 0;
833 }
834 
835 
836 void WpaGui::processMsg(char *msg)
837 {
838 	char *pos = msg, *pos2;
839 	int priority = 2;
840 
841 	if (*pos == '<') {
842 		/* skip priority */
843 		pos++;
844 		priority = atoi(pos);
845 		pos = strchr(pos, '>');
846 		if (pos)
847 			pos++;
848 		else
849 			pos = msg;
850 	}
851 
852 	WpaMsg wm(pos, priority);
853 	if (eh)
854 		eh->addEvent(wm);
855 	if (peers)
856 		peers->event_notify(wm);
857 	msgs.append(wm);
858 	while (msgs.count() > 100)
859 		msgs.pop_front();
860 
861 	/* Update last message with truncated version of the event */
862 	if (strncmp(pos, "CTRL-", 5) == 0) {
863 		pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
864 		if (pos2)
865 			pos2++;
866 		else
867 			pos2 = pos;
868 	} else
869 		pos2 = pos;
870 	QString lastmsg = pos2;
871 	lastmsg.truncate(40);
872 	textLastMessage->setText(lastmsg);
873 
874 	pingsToStatusUpdate = 0;
875 	networkMayHaveChanged = true;
876 
877 	if (str_match(pos, WPA_CTRL_REQ))
878 		processCtrlReq(pos + strlen(WPA_CTRL_REQ));
879 	else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres)
880 		scanres->updateResults();
881 	else if (str_match(pos, WPA_EVENT_DISCONNECTED))
882 		showTrayMessage(QSystemTrayIcon::Information, 3,
883 				tr("Disconnected from network."));
884 	else if (str_match(pos, WPA_EVENT_CONNECTED)) {
885 		showTrayMessage(QSystemTrayIcon::Information, 3,
886 				tr("Connection to network established."));
887 		QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus()));
888 		stopWpsRun(true);
889 	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) {
890 		wpsStatusText->setText(tr("WPS AP in active PBC mode found"));
891 		if (textStatus->text() == "INACTIVE" ||
892 		    textStatus->text() == "DISCONNECTED")
893 			wpaguiTab->setCurrentWidget(wpsTab);
894 		wpsInstructions->setText(tr("Press the PBC button on the "
895 					    "screen to start registration"));
896 	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) {
897 		wpsStatusText->setText(tr("WPS AP with recently selected "
898 					  "registrar"));
899 		if (textStatus->text() == "INACTIVE" ||
900 		    textStatus->text() == "DISCONNECTED")
901 			wpaguiTab->setCurrentWidget(wpsTab);
902 	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
903 		wpsStatusText->setText(tr("WPS AP detected"));
904 	} else if (str_match(pos, WPS_EVENT_OVERLAP)) {
905 		wpsStatusText->setText(tr("PBC mode overlap detected"));
906 		wpsInstructions->setText(tr("More than one AP is currently in "
907 					    "active WPS PBC mode. Wait couple "
908 					    "of minutes and try again"));
909 		wpaguiTab->setCurrentWidget(wpsTab);
910 	} else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) {
911 		wpsStatusText->setText(tr("Network configuration received"));
912 		wpaguiTab->setCurrentWidget(wpsTab);
913 	} else if (str_match(pos, WPA_EVENT_EAP_METHOD)) {
914 		if (strstr(pos, "(WSC)"))
915 			wpsStatusText->setText(tr("Registration started"));
916 	} else if (str_match(pos, WPS_EVENT_M2D)) {
917 		wpsStatusText->setText(tr("Registrar does not yet know PIN"));
918 	} else if (str_match(pos, WPS_EVENT_FAIL)) {
919 		wpsStatusText->setText(tr("Registration failed"));
920 	} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
921 		wpsStatusText->setText(tr("Registration succeeded"));
922 	}
923 }
924 
925 
926 void WpaGui::processCtrlReq(const char *req)
927 {
928 	if (udr) {
929 		udr->close();
930 		delete udr;
931 	}
932 	udr = new UserDataRequest();
933 	if (udr == NULL)
934 		return;
935 	if (udr->setParams(this, req) < 0) {
936 		delete udr;
937 		udr = NULL;
938 		return;
939 	}
940 	udr->show();
941 	udr->exec();
942 }
943 
944 
945 void WpaGui::receiveMsgs()
946 {
947 	char buf[256];
948 	size_t len;
949 
950 	while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
951 		len = sizeof(buf) - 1;
952 		if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
953 			buf[len] = '\0';
954 			processMsg(buf);
955 		}
956 	}
957 }
958 
959 
960 void WpaGui::connectB()
961 {
962 	char reply[10];
963 	size_t reply_len = sizeof(reply);
964 	ctrlRequest("REASSOCIATE", reply, &reply_len);
965 }
966 
967 
968 void WpaGui::selectNetwork( const QString &sel )
969 {
970 	QString cmd(sel);
971 	char reply[10];
972 	size_t reply_len = sizeof(reply);
973 
974 	if (cmd.compare(tr("Select any network"))) {
975 		cmd = "any";
976 	} else {
977 		int pos = cmd.indexOf(':');
978 		if (pos < 0) {
979 			printf("Invalid selectNetwork '%s'\n",
980 			       cmd.toAscii().constData());
981 			return;
982 		}
983 		cmd.truncate(pos);
984 	}
985 	cmd.prepend("SELECT_NETWORK ");
986 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
987 	triggerUpdate();
988 	stopWpsRun(false);
989 }
990 
991 
992 void WpaGui::enableNetwork(const QString &sel)
993 {
994 	QString cmd(sel);
995 	char reply[10];
996 	size_t reply_len = sizeof(reply);
997 
998 	if (!cmd.startsWith("all")) {
999 		int pos = cmd.indexOf(':');
1000 		if (pos < 0) {
1001 			printf("Invalid enableNetwork '%s'\n",
1002 			       cmd.toAscii().constData());
1003 			return;
1004 		}
1005 		cmd.truncate(pos);
1006 	}
1007 	cmd.prepend("ENABLE_NETWORK ");
1008 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1009 	triggerUpdate();
1010 }
1011 
1012 
1013 void WpaGui::disableNetwork(const QString &sel)
1014 {
1015 	QString cmd(sel);
1016 	char reply[10];
1017 	size_t reply_len = sizeof(reply);
1018 
1019 	if (!cmd.startsWith("all")) {
1020 		int pos = cmd.indexOf(':');
1021 		if (pos < 0) {
1022 			printf("Invalid disableNetwork '%s'\n",
1023 			       cmd.toAscii().constData());
1024 			return;
1025 		}
1026 		cmd.truncate(pos);
1027 	}
1028 	cmd.prepend("DISABLE_NETWORK ");
1029 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1030 	triggerUpdate();
1031 }
1032 
1033 
1034 void WpaGui::editNetwork(const QString &sel)
1035 {
1036 	QString cmd(sel);
1037 	int id = -1;
1038 
1039 	if (!cmd.compare(tr("Select any network"))) {
1040 		int pos = sel.indexOf(':');
1041 		if (pos < 0) {
1042 			printf("Invalid editNetwork '%s'\n",
1043 			       cmd.toAscii().constData());
1044 			return;
1045 		}
1046 		cmd.truncate(pos);
1047 		id = cmd.toInt();
1048 	}
1049 
1050 	NetworkConfig *nc = new NetworkConfig();
1051 	if (nc == NULL)
1052 		return;
1053 	nc->setWpaGui(this);
1054 
1055 	if (id >= 0)
1056 		nc->paramsFromConfig(id);
1057 	else
1058 		nc->newNetwork();
1059 
1060 	nc->show();
1061 	nc->exec();
1062 }
1063 
1064 
1065 void WpaGui::editSelectedNetwork()
1066 {
1067 	if (networkSelect->count() < 1) {
1068 		QMessageBox::information(
1069 			this, tr("No Networks"),
1070 			tr("There are no networks to edit.\n"));
1071 		return;
1072 	}
1073 	QString sel(networkSelect->currentText());
1074 	editNetwork(sel);
1075 }
1076 
1077 
1078 void WpaGui::editListedNetwork()
1079 {
1080 	if (networkList->currentRow() < 0) {
1081 		QMessageBox::information(this, tr("Select A Network"),
1082 					 tr("Select a network from the list to"
1083 					    " edit it.\n"));
1084 		return;
1085 	}
1086 	QString sel(networkList->currentItem()->text());
1087 	editNetwork(sel);
1088 }
1089 
1090 
1091 void WpaGui::triggerUpdate()
1092 {
1093 	updateStatus();
1094 	networkMayHaveChanged = true;
1095 	updateNetworks();
1096 }
1097 
1098 
1099 void WpaGui::addNetwork()
1100 {
1101 	NetworkConfig *nc = new NetworkConfig();
1102 	if (nc == NULL)
1103 		return;
1104 	nc->setWpaGui(this);
1105 	nc->newNetwork();
1106 	nc->show();
1107 	nc->exec();
1108 }
1109 
1110 
1111 void WpaGui::removeNetwork(const QString &sel)
1112 {
1113 	QString cmd(sel);
1114 	char reply[10];
1115 	size_t reply_len = sizeof(reply);
1116 
1117 	if (cmd.compare(tr("Select any network")))
1118 		return;
1119 
1120 	if (!cmd.startsWith("all")) {
1121 		int pos = cmd.indexOf(':');
1122 		if (pos < 0) {
1123 			printf("Invalid removeNetwork '%s'\n",
1124 			       cmd.toAscii().constData());
1125 			return;
1126 		}
1127 		cmd.truncate(pos);
1128 	}
1129 	cmd.prepend("REMOVE_NETWORK ");
1130 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1131 	triggerUpdate();
1132 }
1133 
1134 
1135 void WpaGui::removeSelectedNetwork()
1136 {
1137 	if (networkSelect->count() < 1) {
1138 		QMessageBox::information(this, tr("No Networks"),
1139 			                 tr("There are no networks to remove."
1140 					    "\n"));
1141 		return;
1142 	}
1143 	QString sel(networkSelect->currentText());
1144 	removeNetwork(sel);
1145 }
1146 
1147 
1148 void WpaGui::removeListedNetwork()
1149 {
1150 	if (networkList->currentRow() < 0) {
1151 		QMessageBox::information(this, tr("Select A Network"),
1152 					 tr("Select a network from the list "
1153 					    "to remove it.\n"));
1154 		return;
1155 	}
1156 	QString sel(networkList->currentItem()->text());
1157 	removeNetwork(sel);
1158 }
1159 
1160 
1161 void WpaGui::enableAllNetworks()
1162 {
1163 	QString sel("all");
1164 	enableNetwork(sel);
1165 }
1166 
1167 
1168 void WpaGui::disableAllNetworks()
1169 {
1170 	QString sel("all");
1171 	disableNetwork(sel);
1172 }
1173 
1174 
1175 void WpaGui::removeAllNetworks()
1176 {
1177 	QString sel("all");
1178 	removeNetwork(sel);
1179 }
1180 
1181 
1182 int WpaGui::getNetworkDisabled(const QString &sel)
1183 {
1184 	QString cmd(sel);
1185 	char reply[10];
1186 	size_t reply_len = sizeof(reply) - 1;
1187 	int pos = cmd.indexOf(':');
1188 	if (pos < 0) {
1189 		printf("Invalid getNetworkDisabled '%s'\n",
1190 		       cmd.toAscii().constData());
1191 		return -1;
1192 	}
1193 	cmd.truncate(pos);
1194 	cmd.prepend("GET_NETWORK ");
1195 	cmd.append(" disabled");
1196 
1197 	if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0
1198 	    && reply_len >= 1) {
1199 		reply[reply_len] = '\0';
1200 		if (!str_match(reply, "FAIL"))
1201 			return atoi(reply);
1202 	}
1203 
1204 	return -1;
1205 }
1206 
1207 
1208 void WpaGui::updateNetworkDisabledStatus()
1209 {
1210 	if (networkList->currentRow() < 0)
1211 		return;
1212 
1213 	QString sel(networkList->currentItem()->text());
1214 
1215 	switch (getNetworkDisabled(sel)) {
1216 	case 0:
1217 		if (!enableRadioButton->isChecked())
1218 			enableRadioButton->setChecked(true);
1219 		return;
1220 	case 1:
1221 		if (!disableRadioButton->isChecked())
1222 			disableRadioButton->setChecked(true);
1223 		return;
1224 	}
1225 }
1226 
1227 
1228 void WpaGui::enableListedNetwork(bool enabled)
1229 {
1230 	if (networkList->currentRow() < 0 || !enabled)
1231 		return;
1232 
1233 	QString sel(networkList->currentItem()->text());
1234 
1235 	if (getNetworkDisabled(sel) == 1)
1236 		enableNetwork(sel);
1237 }
1238 
1239 
1240 void WpaGui::disableListedNetwork(bool disabled)
1241 {
1242 	if (networkList->currentRow() < 0 || !disabled)
1243 		return;
1244 
1245 	QString sel(networkList->currentItem()->text());
1246 
1247 	if (getNetworkDisabled(sel) == 0)
1248 		disableNetwork(sel);
1249 }
1250 
1251 
1252 void WpaGui::saveConfig()
1253 {
1254 	char buf[10];
1255 	size_t len;
1256 
1257 	len = sizeof(buf) - 1;
1258 	ctrlRequest("SAVE_CONFIG", buf, &len);
1259 
1260 	buf[len] = '\0';
1261 
1262 	if (str_match(buf, "FAIL"))
1263 		QMessageBox::warning(
1264 			this, tr("Failed to save configuration"),
1265 			tr("The configuration could not be saved.\n"
1266 			   "\n"
1267 			   "The update_config=1 configuration option\n"
1268 			   "must be used for configuration saving to\n"
1269 			   "be permitted.\n"));
1270 	else
1271 		QMessageBox::information(
1272 			this, tr("Saved configuration"),
1273 			tr("The current configuration was saved."
1274 			   "\n"));
1275 }
1276 
1277 
1278 void WpaGui::selectAdapter( const QString & sel )
1279 {
1280 	if (openCtrlConnection(sel.toAscii().constData()) < 0)
1281 		printf("Failed to open control connection to "
1282 		       "wpa_supplicant.\n");
1283 	updateStatus();
1284 	updateNetworks();
1285 }
1286 
1287 
1288 void WpaGui::createTrayIcon(bool trayOnly)
1289 {
1290 	QApplication::setQuitOnLastWindowClosed(false);
1291 
1292 	tray_icon = new QSystemTrayIcon(this);
1293 	tray_icon->setToolTip(qAppName() + tr(" - wpa_supplicant user interface"));
1294 	if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
1295 		tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
1296 	else
1297 		tray_icon->setIcon(QIcon(":/icons/wpa_gui.png"));
1298 
1299 	connect(tray_icon,
1300 		SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
1301 		this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
1302 
1303 	ackTrayIcon = false;
1304 
1305 	tray_menu = new QMenu(this);
1306 
1307 	disconnectAction = new QAction(tr("&Disconnect"), this);
1308 	reconnectAction = new QAction(tr("Re&connect"), this);
1309 	connect(disconnectAction, SIGNAL(triggered()), this,
1310 		SLOT(disconnect()));
1311 	connect(reconnectAction, SIGNAL(triggered()), this,
1312 		SLOT(connectB()));
1313 	tray_menu->addAction(disconnectAction);
1314 	tray_menu->addAction(reconnectAction);
1315 	tray_menu->addSeparator();
1316 
1317 	eventAction = new QAction(tr("&Event History"), this);
1318 	scanAction = new QAction(tr("Scan &Results"), this);
1319 	statAction = new QAction(tr("S&tatus"), this);
1320 	connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
1321 	connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
1322 	connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
1323 	tray_menu->addAction(eventAction);
1324 	tray_menu->addAction(scanAction);
1325 	tray_menu->addAction(statAction);
1326 	tray_menu->addSeparator();
1327 
1328 	showAction = new QAction(tr("&Show Window"), this);
1329 	hideAction = new QAction(tr("&Hide Window"), this);
1330 	quitAction = new QAction(tr("&Quit"), this);
1331 	connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
1332 	connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
1333 	connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1334 	tray_menu->addAction(showAction);
1335 	tray_menu->addAction(hideAction);
1336 	tray_menu->addSeparator();
1337 	tray_menu->addAction(quitAction);
1338 
1339 	tray_icon->setContextMenu(tray_menu);
1340 
1341 	tray_icon->show();
1342 
1343 	if (!trayOnly)
1344 		show();
1345 	inTray = trayOnly;
1346 }
1347 
1348 
1349 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
1350 			     const QString & msg)
1351 {
1352 	if (!QSystemTrayIcon::supportsMessages())
1353 		return;
1354 
1355 	if (isVisible() || !tray_icon || !tray_icon->isVisible())
1356 		return;
1357 
1358 	tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
1359 }
1360 
1361 
1362 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
1363  {
1364 	switch (how) {
1365 	/* use close() here instead of hide() and allow the
1366 	 * custom closeEvent handler take care of children */
1367 	case QSystemTrayIcon::Trigger:
1368 		ackTrayIcon = true;
1369 		if (isVisible()) {
1370 			close();
1371 			inTray = true;
1372 		} else {
1373 			show();
1374 			inTray = false;
1375 		}
1376 		break;
1377 	case QSystemTrayIcon::MiddleClick:
1378 		showTrayStatus();
1379 		break;
1380 	default:
1381 		break;
1382 	}
1383 }
1384 
1385 
1386 void WpaGui::showTrayStatus()
1387 {
1388 	char buf[2048];
1389 	size_t len;
1390 
1391 	len = sizeof(buf) - 1;
1392 	if (ctrlRequest("STATUS", buf, &len) < 0)
1393 		return;
1394 	buf[len] = '\0';
1395 
1396 	QString msg, status(buf);
1397 
1398 	QStringList lines = status.split(QRegExp("\\n"));
1399 	for (QStringList::Iterator it = lines.begin();
1400 	     it != lines.end(); it++) {
1401 		int pos = (*it).indexOf('=') + 1;
1402 		if (pos < 1)
1403 			continue;
1404 
1405 		if ((*it).startsWith("bssid="))
1406 			msg.append("BSSID:\t" + (*it).mid(pos) + "\n");
1407 		else if ((*it).startsWith("ssid="))
1408 			msg.append("SSID: \t" + (*it).mid(pos) + "\n");
1409 		else if ((*it).startsWith("pairwise_cipher="))
1410 			msg.append("PAIR: \t" + (*it).mid(pos) + "\n");
1411 		else if ((*it).startsWith("group_cipher="))
1412 			msg.append("GROUP:\t" + (*it).mid(pos) + "\n");
1413 		else if ((*it).startsWith("key_mgmt="))
1414 			msg.append("AUTH: \t" + (*it).mid(pos) + "\n");
1415 		else if ((*it).startsWith("wpa_state="))
1416 			msg.append("STATE:\t" + (*it).mid(pos) + "\n");
1417 		else if ((*it).startsWith("ip_address="))
1418 			msg.append("IP:   \t" + (*it).mid(pos) + "\n");
1419 		else if ((*it).startsWith("Supplicant PAE state="))
1420 			msg.append("PAE:  \t" + (*it).mid(pos) + "\n");
1421 		else if ((*it).startsWith("EAP state="))
1422 			msg.append("EAP:  \t" + (*it).mid(pos) + "\n");
1423 	}
1424 
1425 	if (!msg.isEmpty())
1426 		showTrayMessage(QSystemTrayIcon::Information, 10, msg);
1427 }
1428 
1429 
1430 void WpaGui::closeEvent(QCloseEvent *event)
1431 {
1432 	if (eh) {
1433 		eh->close();
1434 		delete eh;
1435 		eh = NULL;
1436 	}
1437 
1438 	if (scanres) {
1439 		scanres->close();
1440 		delete scanres;
1441 		scanres = NULL;
1442 	}
1443 
1444 	if (peers) {
1445 		peers->close();
1446 		delete peers;
1447 		peers = NULL;
1448 	}
1449 
1450 	if (udr) {
1451 		udr->close();
1452 		delete udr;
1453 		udr = NULL;
1454 	}
1455 
1456 	if (tray_icon && !ackTrayIcon) {
1457 		/* give user a visual hint that the tray icon exists */
1458 		if (QSystemTrayIcon::supportsMessages()) {
1459 			hide();
1460 			showTrayMessage(QSystemTrayIcon::Information, 3,
1461 					qAppName() +
1462 					tr(" will keep running in "
1463 					   "the system tray."));
1464 		} else {
1465 			QMessageBox::information(this, qAppName() +
1466 						 tr(" systray"),
1467 						 tr("The program will keep "
1468 						    "running in the system "
1469 						    "tray."));
1470 		}
1471 		ackTrayIcon = true;
1472 	}
1473 
1474 	event->accept();
1475 }
1476 
1477 
1478 void WpaGui::wpsDialog()
1479 {
1480 	wpaguiTab->setCurrentWidget(wpsTab);
1481 }
1482 
1483 
1484 void WpaGui::peersDialog()
1485 {
1486 	if (peers) {
1487 		peers->close();
1488 		delete peers;
1489 	}
1490 
1491 	peers = new Peers();
1492 	if (peers == NULL)
1493 		return;
1494 	peers->setWpaGui(this);
1495 	peers->show();
1496 	peers->exec();
1497 }
1498 
1499 
1500 void WpaGui::tabChanged(int index)
1501 {
1502 	if (index != 2)
1503 		return;
1504 
1505 	if (wpsRunning)
1506 		return;
1507 
1508 	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1509 	if (bssFromScan.isEmpty())
1510 		wpsApPinButton->setEnabled(false);
1511 }
1512 
1513 
1514 void WpaGui::wpsPbc()
1515 {
1516 	char reply[20];
1517 	size_t reply_len = sizeof(reply);
1518 
1519 	if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
1520 		return;
1521 
1522 	wpsPinEdit->setEnabled(false);
1523 	if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) {
1524 		wpsInstructions->setText(tr("Press the push button on the AP to "
1525 					 "start the PBC mode."));
1526 	} else {
1527 		wpsInstructions->setText(tr("If you have not yet done so, press "
1528 					 "the push button on the AP to start "
1529 					 "the PBC mode."));
1530 	}
1531 	wpsStatusText->setText(tr("Waiting for Registrar"));
1532 	wpsRunning = true;
1533 }
1534 
1535 
1536 void WpaGui::wpsGeneratePin()
1537 {
1538 	char reply[20];
1539 	size_t reply_len = sizeof(reply) - 1;
1540 
1541 	if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
1542 		return;
1543 
1544 	reply[reply_len] = '\0';
1545 
1546 	wpsPinEdit->setText(reply);
1547 	wpsPinEdit->setEnabled(true);
1548 	wpsInstructions->setText(tr("Enter the generated PIN into the Registrar "
1549 				 "(either the internal one in the AP or an "
1550 				 "external one)."));
1551 	wpsStatusText->setText(tr("Waiting for Registrar"));
1552 	wpsRunning = true;
1553 }
1554 
1555 
1556 void WpaGui::setBssFromScan(const QString &bssid)
1557 {
1558 	bssFromScan = bssid;
1559 	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1560 	wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
1561 	wpsStatusText->setText(tr("WPS AP selected from scan results"));
1562 	wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., "
1563 				 "from a label in the device, enter the eight "
1564 				 "digit AP PIN and click Use AP PIN button."));
1565 }
1566 
1567 
1568 void WpaGui::wpsApPinChanged(const QString &text)
1569 {
1570 	wpsApPinButton->setEnabled(text.length() == 8);
1571 }
1572 
1573 
1574 void WpaGui::wpsApPin()
1575 {
1576 	char reply[20];
1577 	size_t reply_len = sizeof(reply);
1578 
1579 	QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
1580 	if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0)
1581 		return;
1582 
1583 	wpsStatusText->setText(tr("Waiting for AP/Enrollee"));
1584 	wpsRunning = true;
1585 }
1586 
1587 
1588 void WpaGui::stopWpsRun(bool success)
1589 {
1590 	if (wpsRunning)
1591 		wpsStatusText->setText(success ? tr("Connected to the network") :
1592 				       tr("Stopped"));
1593 	else
1594 		wpsStatusText->setText("");
1595 	wpsPinEdit->setEnabled(false);
1596 	wpsInstructions->setText("");
1597 	wpsRunning = false;
1598 	bssFromScan = "";
1599 	wpsApPinEdit->setEnabled(false);
1600 	wpsApPinButton->setEnabled(false);
1601 }
1602 
1603 
1604 #ifdef CONFIG_NATIVE_WINDOWS
1605 
1606 #ifndef WPASVC_NAME
1607 #define WPASVC_NAME TEXT("wpasvc")
1608 #endif
1609 
1610 class ErrorMsg : public QMessageBox {
1611 public:
1612 	ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
1613 	void showMsg(QString msg);
1614 private:
1615 	DWORD err;
1616 };
1617 
1618 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
1619 	QMessageBox(parent), err(last_err)
1620 {
1621 	setWindowTitle(tr("wpa_gui error"));
1622 	setIcon(QMessageBox::Warning);
1623 }
1624 
1625 void ErrorMsg::showMsg(QString msg)
1626 {
1627 	LPTSTR buf;
1628 
1629 	setText(msg);
1630 	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1631 			  FORMAT_MESSAGE_FROM_SYSTEM,
1632 			  NULL, err, 0, (LPTSTR) (void *) &buf,
1633 			  0, NULL) > 0) {
1634 		QString msg = QString::fromWCharArray(buf);
1635 		setInformativeText(QString("[%1] %2").arg(err).arg(msg));
1636 		LocalFree(buf);
1637 	} else {
1638 		setInformativeText(QString("[%1]").arg(err));
1639 	}
1640 
1641 	exec();
1642 }
1643 
1644 
1645 void WpaGui::startService()
1646 {
1647 	SC_HANDLE svc, scm;
1648 
1649 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1650 	if (!scm) {
1651 		ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
1652 		return;
1653 	}
1654 
1655 	svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
1656 	if (!svc) {
1657 		ErrorMsg(this).showMsg(tr("OpenService failed"));
1658 		CloseServiceHandle(scm);
1659 		return;
1660 	}
1661 
1662 	if (!StartService(svc, 0, NULL)) {
1663 		ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant "
1664 				       "service"));
1665 	}
1666 
1667 	CloseServiceHandle(svc);
1668 	CloseServiceHandle(scm);
1669 }
1670 
1671 
1672 void WpaGui::stopService()
1673 {
1674 	SC_HANDLE svc, scm;
1675 	SERVICE_STATUS status;
1676 
1677 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1678 	if (!scm) {
1679 		ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
1680 		return;
1681 	}
1682 
1683 	svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
1684 	if (!svc) {
1685 		ErrorMsg(this).showMsg(tr("OpenService failed"));
1686 		CloseServiceHandle(scm);
1687 		return;
1688 	}
1689 
1690 	if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
1691 		ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant "
1692 				       "service"));
1693 	}
1694 
1695 	CloseServiceHandle(svc);
1696 	CloseServiceHandle(scm);
1697 }
1698 
1699 
1700 bool WpaGui::serviceRunning()
1701 {
1702 	SC_HANDLE svc, scm;
1703 	SERVICE_STATUS status;
1704 	bool running = false;
1705 
1706 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1707 	if (!scm) {
1708 		printf("OpenSCManager failed: %d\n", (int) GetLastError());
1709 		return false;
1710 	}
1711 
1712 	svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
1713 	if (!svc) {
1714 		printf("OpenService failed: %d\n\n", (int) GetLastError());
1715 		CloseServiceHandle(scm);
1716 		return false;
1717 	}
1718 
1719 	if (QueryServiceStatus(svc, &status)) {
1720 		if (status.dwCurrentState != SERVICE_STOPPED)
1721 			running = true;
1722 	}
1723 
1724 	CloseServiceHandle(svc);
1725 	CloseServiceHandle(scm);
1726 
1727 	return running;
1728 }
1729 
1730 #endif /* CONFIG_NATIVE_WINDOWS */
1731 
1732 
1733 void WpaGui::addInterface()
1734 {
1735 	if (add_iface) {
1736 		add_iface->close();
1737 		delete add_iface;
1738 	}
1739 	add_iface = new AddInterface(this, this);
1740 	add_iface->show();
1741 	add_iface->exec();
1742 }
1743 
1744 
1745 #ifndef QT_NO_SESSIONMANAGER
1746 void WpaGui::saveState()
1747 {
1748 	QSettings settings("wpa_supplicant", "wpa_gui");
1749 	settings.beginGroup("state");
1750 	settings.setValue("session_id", app->sessionId());
1751 	settings.setValue("in_tray", inTray);
1752 	settings.endGroup();
1753 }
1754 #endif
1755