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