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