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