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