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