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[2048], *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