xref: /netbsd-src/external/bsd/wpa/dist/wpa_supplicant/wpa_gui-qt4/wpagui.cpp (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*
2  * wpa_gui - WpaGui class
3  * Copyright (c) 2005-2010, 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-2010,\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.contains(QRegExp("^\\d+:")))
975 		cmd.truncate(cmd.indexOf(':'));
976 	else
977 		cmd = "any";
978 	cmd.prepend("SELECT_NETWORK ");
979 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
980 	triggerUpdate();
981 	stopWpsRun(false);
982 }
983 
984 
985 void WpaGui::enableNetwork(const QString &sel)
986 {
987 	QString cmd(sel);
988 	char reply[10];
989 	size_t reply_len = sizeof(reply);
990 
991 	if (cmd.contains(QRegExp("^\\d+:")))
992 		cmd.truncate(cmd.indexOf(':'));
993 	else if (!cmd.startsWith("all")) {
994 		printf("Invalid editNetwork '%s'\n",
995 		       cmd.toAscii().constData());
996 		return;
997 	}
998 	cmd.prepend("ENABLE_NETWORK ");
999 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1000 	triggerUpdate();
1001 }
1002 
1003 
1004 void WpaGui::disableNetwork(const QString &sel)
1005 {
1006 	QString cmd(sel);
1007 	char reply[10];
1008 	size_t reply_len = sizeof(reply);
1009 
1010 	if (cmd.contains(QRegExp("^\\d+:")))
1011 		cmd.truncate(cmd.indexOf(':'));
1012 	else if (!cmd.startsWith("all")) {
1013 		printf("Invalid editNetwork '%s'\n",
1014 		       cmd.toAscii().constData());
1015 		return;
1016 	}
1017 	cmd.prepend("DISABLE_NETWORK ");
1018 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1019 	triggerUpdate();
1020 }
1021 
1022 
1023 void WpaGui::editNetwork(const QString &sel)
1024 {
1025 	QString cmd(sel);
1026 	int id = -1;
1027 
1028 	if (cmd.contains(QRegExp("^\\d+:"))) {
1029 		cmd.truncate(cmd.indexOf(':'));
1030 		id = cmd.toInt();
1031 	}
1032 
1033 	NetworkConfig *nc = new NetworkConfig();
1034 	if (nc == NULL)
1035 		return;
1036 	nc->setWpaGui(this);
1037 
1038 	if (id >= 0)
1039 		nc->paramsFromConfig(id);
1040 	else
1041 		nc->newNetwork();
1042 
1043 	nc->show();
1044 	nc->exec();
1045 }
1046 
1047 
1048 void WpaGui::editSelectedNetwork()
1049 {
1050 	if (networkSelect->count() < 1) {
1051 		QMessageBox::information(
1052 			this, tr("No Networks"),
1053 			tr("There are no networks to edit.\n"));
1054 		return;
1055 	}
1056 	QString sel(networkSelect->currentText());
1057 	editNetwork(sel);
1058 }
1059 
1060 
1061 void WpaGui::editListedNetwork()
1062 {
1063 	if (networkList->currentRow() < 0) {
1064 		QMessageBox::information(this, tr("Select A Network"),
1065 					 tr("Select a network from the list to"
1066 					    " edit it.\n"));
1067 		return;
1068 	}
1069 	QString sel(networkList->currentItem()->text());
1070 	editNetwork(sel);
1071 }
1072 
1073 
1074 void WpaGui::triggerUpdate()
1075 {
1076 	updateStatus();
1077 	networkMayHaveChanged = true;
1078 	updateNetworks();
1079 }
1080 
1081 
1082 void WpaGui::addNetwork()
1083 {
1084 	NetworkConfig *nc = new NetworkConfig();
1085 	if (nc == NULL)
1086 		return;
1087 	nc->setWpaGui(this);
1088 	nc->newNetwork();
1089 	nc->show();
1090 	nc->exec();
1091 }
1092 
1093 
1094 void WpaGui::removeNetwork(const QString &sel)
1095 {
1096 	QString cmd(sel);
1097 	char reply[10];
1098 	size_t reply_len = sizeof(reply);
1099 
1100 	if (cmd.contains(QRegExp("^\\d+:")))
1101 		cmd.truncate(cmd.indexOf(':'));
1102 	else if (!cmd.startsWith("all")) {
1103 		printf("Invalid editNetwork '%s'\n",
1104 		       cmd.toAscii().constData());
1105 		return;
1106 	}
1107 	cmd.prepend("REMOVE_NETWORK ");
1108 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1109 	triggerUpdate();
1110 }
1111 
1112 
1113 void WpaGui::removeSelectedNetwork()
1114 {
1115 	if (networkSelect->count() < 1) {
1116 		QMessageBox::information(this, tr("No Networks"),
1117 			                 tr("There are no networks to remove."
1118 					    "\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, tr("Select A Network"),
1130 					 tr("Select a network from the list "
1131 					    "to 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(
1242 			this, tr("Failed to save configuration"),
1243 			tr("The configuration could not be saved.\n"
1244 			   "\n"
1245 			   "The update_config=1 configuration option\n"
1246 			   "must be used for configuration saving to\n"
1247 			   "be permitted.\n"));
1248 	else
1249 		QMessageBox::information(
1250 			this, tr("Saved configuration"),
1251 			tr("The current configuration was saved."
1252 			   "\n"));
1253 }
1254 
1255 
1256 void WpaGui::selectAdapter( const QString & sel )
1257 {
1258 	if (openCtrlConnection(sel.toAscii().constData()) < 0)
1259 		printf("Failed to open control connection to "
1260 		       "wpa_supplicant.\n");
1261 	updateStatus();
1262 	updateNetworks();
1263 }
1264 
1265 
1266 void WpaGui::createTrayIcon(bool trayOnly)
1267 {
1268 	QApplication::setQuitOnLastWindowClosed(false);
1269 
1270 	tray_icon = new QSystemTrayIcon(this);
1271 	tray_icon->setToolTip(qAppName() + tr(" - wpa_supplicant user interface"));
1272 	if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
1273 		tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
1274 	else
1275 		tray_icon->setIcon(QIcon(":/icons/wpa_gui.png"));
1276 
1277 	connect(tray_icon,
1278 		SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
1279 		this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
1280 
1281 	ackTrayIcon = false;
1282 
1283 	tray_menu = new QMenu(this);
1284 
1285 	disconnectAction = new QAction(tr("&Disconnect"), this);
1286 	reconnectAction = new QAction(tr("Re&connect"), this);
1287 	connect(disconnectAction, SIGNAL(triggered()), this,
1288 		SLOT(disconnect()));
1289 	connect(reconnectAction, SIGNAL(triggered()), this,
1290 		SLOT(connectB()));
1291 	tray_menu->addAction(disconnectAction);
1292 	tray_menu->addAction(reconnectAction);
1293 	tray_menu->addSeparator();
1294 
1295 	eventAction = new QAction(tr("&Event History"), this);
1296 	scanAction = new QAction(tr("Scan &Results"), this);
1297 	statAction = new QAction(tr("S&tatus"), this);
1298 	connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
1299 	connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
1300 	connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
1301 	tray_menu->addAction(eventAction);
1302 	tray_menu->addAction(scanAction);
1303 	tray_menu->addAction(statAction);
1304 	tray_menu->addSeparator();
1305 
1306 	showAction = new QAction(tr("&Show Window"), this);
1307 	hideAction = new QAction(tr("&Hide Window"), this);
1308 	quitAction = new QAction(tr("&Quit"), this);
1309 	connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
1310 	connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
1311 	connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1312 	tray_menu->addAction(showAction);
1313 	tray_menu->addAction(hideAction);
1314 	tray_menu->addSeparator();
1315 	tray_menu->addAction(quitAction);
1316 
1317 	tray_icon->setContextMenu(tray_menu);
1318 
1319 	tray_icon->show();
1320 
1321 	if (!trayOnly)
1322 		show();
1323 	inTray = trayOnly;
1324 }
1325 
1326 
1327 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
1328 			     const QString & msg)
1329 {
1330 	if (!QSystemTrayIcon::supportsMessages())
1331 		return;
1332 
1333 	if (isVisible() || !tray_icon || !tray_icon->isVisible())
1334 		return;
1335 
1336 	tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
1337 }
1338 
1339 
1340 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
1341  {
1342 	switch (how) {
1343 	/* use close() here instead of hide() and allow the
1344 	 * custom closeEvent handler take care of children */
1345 	case QSystemTrayIcon::Trigger:
1346 		ackTrayIcon = true;
1347 		if (isVisible()) {
1348 			close();
1349 			inTray = true;
1350 		} else {
1351 			show();
1352 			inTray = false;
1353 		}
1354 		break;
1355 	case QSystemTrayIcon::MiddleClick:
1356 		showTrayStatus();
1357 		break;
1358 	default:
1359 		break;
1360 	}
1361 }
1362 
1363 
1364 void WpaGui::showTrayStatus()
1365 {
1366 	char buf[2048];
1367 	size_t len;
1368 
1369 	len = sizeof(buf) - 1;
1370 	if (ctrlRequest("STATUS", buf, &len) < 0)
1371 		return;
1372 	buf[len] = '\0';
1373 
1374 	QString msg, status(buf);
1375 
1376 	QStringList lines = status.split(QRegExp("\\n"));
1377 	for (QStringList::Iterator it = lines.begin();
1378 	     it != lines.end(); it++) {
1379 		int pos = (*it).indexOf('=') + 1;
1380 		if (pos < 1)
1381 			continue;
1382 
1383 		if ((*it).startsWith("bssid="))
1384 			msg.append("BSSID:\t" + (*it).mid(pos) + "\n");
1385 		else if ((*it).startsWith("ssid="))
1386 			msg.append("SSID: \t" + (*it).mid(pos) + "\n");
1387 		else if ((*it).startsWith("pairwise_cipher="))
1388 			msg.append("PAIR: \t" + (*it).mid(pos) + "\n");
1389 		else if ((*it).startsWith("group_cipher="))
1390 			msg.append("GROUP:\t" + (*it).mid(pos) + "\n");
1391 		else if ((*it).startsWith("key_mgmt="))
1392 			msg.append("AUTH: \t" + (*it).mid(pos) + "\n");
1393 		else if ((*it).startsWith("wpa_state="))
1394 			msg.append("STATE:\t" + (*it).mid(pos) + "\n");
1395 		else if ((*it).startsWith("ip_address="))
1396 			msg.append("IP:   \t" + (*it).mid(pos) + "\n");
1397 		else if ((*it).startsWith("Supplicant PAE state="))
1398 			msg.append("PAE:  \t" + (*it).mid(pos) + "\n");
1399 		else if ((*it).startsWith("EAP state="))
1400 			msg.append("EAP:  \t" + (*it).mid(pos) + "\n");
1401 	}
1402 
1403 	if (!msg.isEmpty())
1404 		showTrayMessage(QSystemTrayIcon::Information, 10, msg);
1405 }
1406 
1407 
1408 void WpaGui::closeEvent(QCloseEvent *event)
1409 {
1410 	if (eh) {
1411 		eh->close();
1412 		delete eh;
1413 		eh = NULL;
1414 	}
1415 
1416 	if (scanres) {
1417 		scanres->close();
1418 		delete scanres;
1419 		scanres = NULL;
1420 	}
1421 
1422 	if (peers) {
1423 		peers->close();
1424 		delete peers;
1425 		peers = NULL;
1426 	}
1427 
1428 	if (udr) {
1429 		udr->close();
1430 		delete udr;
1431 		udr = NULL;
1432 	}
1433 
1434 	if (tray_icon && !ackTrayIcon) {
1435 		/* give user a visual hint that the tray icon exists */
1436 		if (QSystemTrayIcon::supportsMessages()) {
1437 			hide();
1438 			showTrayMessage(QSystemTrayIcon::Information, 3,
1439 					qAppName() +
1440 					tr(" will keep running in "
1441 					   "the system tray."));
1442 		} else {
1443 			QMessageBox::information(this, qAppName() +
1444 						 tr(" systray"),
1445 						 tr("The program will keep "
1446 						    "running in the system "
1447 						    "tray."));
1448 		}
1449 		ackTrayIcon = true;
1450 	}
1451 
1452 	event->accept();
1453 }
1454 
1455 
1456 void WpaGui::wpsDialog()
1457 {
1458 	wpaguiTab->setCurrentWidget(wpsTab);
1459 }
1460 
1461 
1462 void WpaGui::peersDialog()
1463 {
1464 	if (peers) {
1465 		peers->close();
1466 		delete peers;
1467 	}
1468 
1469 	peers = new Peers();
1470 	if (peers == NULL)
1471 		return;
1472 	peers->setWpaGui(this);
1473 	peers->show();
1474 	peers->exec();
1475 }
1476 
1477 
1478 void WpaGui::tabChanged(int index)
1479 {
1480 	if (index != 2)
1481 		return;
1482 
1483 	if (wpsRunning)
1484 		return;
1485 
1486 	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1487 	if (bssFromScan.isEmpty())
1488 		wpsApPinButton->setEnabled(false);
1489 }
1490 
1491 
1492 void WpaGui::wpsPbc()
1493 {
1494 	char reply[20];
1495 	size_t reply_len = sizeof(reply);
1496 
1497 	if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
1498 		return;
1499 
1500 	wpsPinEdit->setEnabled(false);
1501 	if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) {
1502 		wpsInstructions->setText(tr("Press the push button on the AP to "
1503 					 "start the PBC mode."));
1504 	} else {
1505 		wpsInstructions->setText(tr("If you have not yet done so, press "
1506 					 "the push button on the AP to start "
1507 					 "the PBC mode."));
1508 	}
1509 	wpsStatusText->setText(tr("Waiting for Registrar"));
1510 	wpsRunning = true;
1511 }
1512 
1513 
1514 void WpaGui::wpsGeneratePin()
1515 {
1516 	char reply[20];
1517 	size_t reply_len = sizeof(reply) - 1;
1518 
1519 	if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
1520 		return;
1521 
1522 	reply[reply_len] = '\0';
1523 
1524 	wpsPinEdit->setText(reply);
1525 	wpsPinEdit->setEnabled(true);
1526 	wpsInstructions->setText(tr("Enter the generated PIN into the Registrar "
1527 				 "(either the internal one in the AP or an "
1528 				 "external one)."));
1529 	wpsStatusText->setText(tr("Waiting for Registrar"));
1530 	wpsRunning = true;
1531 }
1532 
1533 
1534 void WpaGui::setBssFromScan(const QString &bssid)
1535 {
1536 	bssFromScan = bssid;
1537 	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1538 	wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
1539 	wpsStatusText->setText(tr("WPS AP selected from scan results"));
1540 	wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., "
1541 				 "from a label in the device, enter the eight "
1542 				 "digit AP PIN and click Use AP PIN button."));
1543 }
1544 
1545 
1546 void WpaGui::wpsApPinChanged(const QString &text)
1547 {
1548 	wpsApPinButton->setEnabled(text.length() == 8);
1549 }
1550 
1551 
1552 void WpaGui::wpsApPin()
1553 {
1554 	char reply[20];
1555 	size_t reply_len = sizeof(reply);
1556 
1557 	QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
1558 	if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0)
1559 		return;
1560 
1561 	wpsStatusText->setText(tr("Waiting for AP/Enrollee"));
1562 	wpsRunning = true;
1563 }
1564 
1565 
1566 void WpaGui::stopWpsRun(bool success)
1567 {
1568 	if (wpsRunning)
1569 		wpsStatusText->setText(success ? tr("Connected to the network") :
1570 				       tr("Stopped"));
1571 	else
1572 		wpsStatusText->setText("");
1573 	wpsPinEdit->setEnabled(false);
1574 	wpsInstructions->setText("");
1575 	wpsRunning = false;
1576 	bssFromScan = "";
1577 	wpsApPinEdit->setEnabled(false);
1578 	wpsApPinButton->setEnabled(false);
1579 }
1580 
1581 
1582 #ifdef CONFIG_NATIVE_WINDOWS
1583 
1584 #ifndef WPASVC_NAME
1585 #define WPASVC_NAME TEXT("wpasvc")
1586 #endif
1587 
1588 class ErrorMsg : public QMessageBox {
1589 public:
1590 	ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
1591 	void showMsg(QString msg);
1592 private:
1593 	DWORD err;
1594 };
1595 
1596 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
1597 	QMessageBox(parent), err(last_err)
1598 {
1599 	setWindowTitle(tr("wpa_gui error"));
1600 	setIcon(QMessageBox::Warning);
1601 }
1602 
1603 void ErrorMsg::showMsg(QString msg)
1604 {
1605 	LPTSTR buf;
1606 
1607 	setText(msg);
1608 	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1609 			  FORMAT_MESSAGE_FROM_SYSTEM,
1610 			  NULL, err, 0, (LPTSTR) (void *) &buf,
1611 			  0, NULL) > 0) {
1612 		QString msg = QString::fromWCharArray(buf);
1613 		setInformativeText(QString("[%1] %2").arg(err).arg(msg));
1614 		LocalFree(buf);
1615 	} else {
1616 		setInformativeText(QString("[%1]").arg(err));
1617 	}
1618 
1619 	exec();
1620 }
1621 
1622 
1623 void WpaGui::startService()
1624 {
1625 	SC_HANDLE svc, scm;
1626 
1627 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1628 	if (!scm) {
1629 		ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
1630 		return;
1631 	}
1632 
1633 	svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
1634 	if (!svc) {
1635 		ErrorMsg(this).showMsg(tr("OpenService failed"));
1636 		CloseServiceHandle(scm);
1637 		return;
1638 	}
1639 
1640 	if (!StartService(svc, 0, NULL)) {
1641 		ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant "
1642 				       "service"));
1643 	}
1644 
1645 	CloseServiceHandle(svc);
1646 	CloseServiceHandle(scm);
1647 }
1648 
1649 
1650 void WpaGui::stopService()
1651 {
1652 	SC_HANDLE svc, scm;
1653 	SERVICE_STATUS status;
1654 
1655 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1656 	if (!scm) {
1657 		ErrorMsg(this).showMsg(tr("OpenSCManager failed"));
1658 		return;
1659 	}
1660 
1661 	svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
1662 	if (!svc) {
1663 		ErrorMsg(this).showMsg(tr("OpenService failed"));
1664 		CloseServiceHandle(scm);
1665 		return;
1666 	}
1667 
1668 	if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
1669 		ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant "
1670 				       "service"));
1671 	}
1672 
1673 	CloseServiceHandle(svc);
1674 	CloseServiceHandle(scm);
1675 }
1676 
1677 
1678 bool WpaGui::serviceRunning()
1679 {
1680 	SC_HANDLE svc, scm;
1681 	SERVICE_STATUS status;
1682 	bool running = false;
1683 
1684 	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1685 	if (!scm) {
1686 		printf("OpenSCManager failed: %d\n", (int) GetLastError());
1687 		return false;
1688 	}
1689 
1690 	svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
1691 	if (!svc) {
1692 		printf("OpenService failed: %d\n\n", (int) GetLastError());
1693 		CloseServiceHandle(scm);
1694 		return false;
1695 	}
1696 
1697 	if (QueryServiceStatus(svc, &status)) {
1698 		if (status.dwCurrentState != SERVICE_STOPPED)
1699 			running = true;
1700 	}
1701 
1702 	CloseServiceHandle(svc);
1703 	CloseServiceHandle(scm);
1704 
1705 	return running;
1706 }
1707 
1708 #endif /* CONFIG_NATIVE_WINDOWS */
1709 
1710 
1711 void WpaGui::addInterface()
1712 {
1713 	if (add_iface) {
1714 		add_iface->close();
1715 		delete add_iface;
1716 	}
1717 	add_iface = new AddInterface(this, this);
1718 	add_iface->show();
1719 	add_iface->exec();
1720 }
1721 
1722 
1723 #ifndef QT_NO_SESSIONMANAGER
1724 void WpaGui::saveState()
1725 {
1726 	QSettings settings("wpa_supplicant", "wpa_gui");
1727 	settings.beginGroup("state");
1728 	settings.setValue("session_id", app->sessionId());
1729 	settings.setValue("in_tray", inTray);
1730 	settings.endGroup();
1731 }
1732 #endif
1733