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