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