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