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