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