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