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