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