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