wpa_gui: Only move to WPS tab if inactive/disconnect and AP ready
[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                 if (textStatus->text() == "INACTIVE" ||
873                     textStatus->text() == "DISCONNECTED")
874                         wpaguiTab->setCurrentWidget(wpsTab);
875                 wpsInstructions->setText("Press the PBC button on the screen "
876                                          "to start registration");
877         } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) {
878                 showTrayMessage(QSystemTrayIcon::Information, 3,
879                                 "Wi-Fi Protected Setup (WPS) AP\n"
880                                 " in active PIN mode found.");
881                 wpsStatusText->setText("WPS AP with recently selected "
882                                        "registrar");
883                 if (textStatus->text() == "INACTIVE" ||
884                     textStatus->text() == "DISCONNECTED")
885                         wpaguiTab->setCurrentWidget(wpsTab);
886         } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
887                 showTrayMessage(QSystemTrayIcon::Information, 3,
888                                 "Wi-Fi Protected Setup (WPS)\n"
889                                 "AP detected.");
890                 wpsStatusText->setText("WPS AP detected");
891         } else if (str_match(pos, WPS_EVENT_OVERLAP)) {
892                 showTrayMessage(QSystemTrayIcon::Information, 3,
893                                 "Wi-Fi Protected Setup (WPS)\n"
894                                 "PBC mode overlap detected.");
895                 wpsStatusText->setText("PBC mode overlap detected");
896                 wpsInstructions->setText("More than one AP is currently in "
897                                          "active WPS PBC mode. Wait couple of "
898                                          "minutes and try again");
899                 wpaguiTab->setCurrentWidget(wpsTab);
900         } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) {
901                 wpsStatusText->setText("Network configuration received");
902                 wpaguiTab->setCurrentWidget(wpsTab);
903         } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) {
904                 if (strstr(pos, "(WSC)"))
905                         wpsStatusText->setText("Registration started");
906         } else if (str_match(pos, WPS_EVENT_M2D)) {
907                 wpsStatusText->setText("Registrar does not yet know PIN");
908         } else if (str_match(pos, WPS_EVENT_FAIL)) {
909                 wpsStatusText->setText("Registration failed");
910         } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
911                 wpsStatusText->setText("Registration succeeded");
912         }
913 }
914
915
916 void WpaGui::processCtrlReq(const char *req)
917 {
918         if (udr) {
919                 udr->close();
920                 delete udr;
921         }
922         udr = new UserDataRequest();
923         if (udr == NULL)
924                 return;
925         if (udr->setParams(this, req) < 0) {
926                 delete udr;
927                 udr = NULL;
928                 return;
929         }
930         udr->show();
931         udr->exec();
932 }
933
934
935 void WpaGui::receiveMsgs()
936 {
937         char buf[256];
938         size_t len;
939
940         while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
941                 len = sizeof(buf) - 1;
942                 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
943                         buf[len] = '\0';
944                         processMsg(buf);
945                 }
946         }
947 }
948
949
950 void WpaGui::connectB()
951 {
952         char reply[10];
953         size_t reply_len = sizeof(reply);
954         ctrlRequest("REASSOCIATE", reply, &reply_len);
955 }
956
957
958 void WpaGui::selectNetwork( const QString &sel )
959 {
960         QString cmd(sel);
961         char reply[10];
962         size_t reply_len = sizeof(reply);
963
964         if (cmd.startsWith("Select any")) {
965                 cmd = "any";
966         } else {
967                 int pos = cmd.indexOf(':');
968                 if (pos < 0) {
969                         printf("Invalid selectNetwork '%s'\n",
970                                cmd.toAscii().constData());
971                         return;
972                 }
973                 cmd.truncate(pos);
974         }
975         cmd.prepend("SELECT_NETWORK ");
976         ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
977         triggerUpdate();
978         stopWpsRun(false);
979 }
980
981
982 void WpaGui::enableNetwork(const QString &sel)
983 {
984         QString cmd(sel);
985         char reply[10];
986         size_t reply_len = sizeof(reply);
987
988         if (!cmd.startsWith("all")) {
989                 int pos = cmd.indexOf(':');
990                 if (pos < 0) {
991                         printf("Invalid enableNetwork '%s'\n",
992                                cmd.toAscii().constData());
993                         return;
994                 }
995                 cmd.truncate(pos);
996         }
997         cmd.prepend("ENABLE_NETWORK ");
998         ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
999         triggerUpdate();
1000 }
1001
1002
1003 void WpaGui::disableNetwork(const QString &sel)
1004 {
1005         QString cmd(sel);
1006         char reply[10];
1007         size_t reply_len = sizeof(reply);
1008
1009         if (!cmd.startsWith("all")) {
1010                 int pos = cmd.indexOf(':');
1011                 if (pos < 0) {
1012                         printf("Invalid disableNetwork '%s'\n",
1013                                cmd.toAscii().constData());
1014                         return;
1015                 }
1016                 cmd.truncate(pos);
1017         }
1018         cmd.prepend("DISABLE_NETWORK ");
1019         ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1020         triggerUpdate();
1021 }
1022
1023
1024 void WpaGui::editNetwork(const QString &sel)
1025 {
1026         QString cmd(sel);
1027         int id = -1;
1028
1029         if (!cmd.startsWith("Select any")) {
1030                 int pos = sel.indexOf(':');
1031                 if (pos < 0) {
1032                         printf("Invalid editNetwork '%s'\n",
1033                                cmd.toAscii().constData());
1034                         return;
1035                 }
1036                 cmd.truncate(pos);
1037                 id = cmd.toInt();
1038         }
1039
1040         NetworkConfig *nc = new NetworkConfig();
1041         if (nc == NULL)
1042                 return;
1043         nc->setWpaGui(this);
1044
1045         if (id >= 0)
1046                 nc->paramsFromConfig(id);
1047         else
1048                 nc->newNetwork();
1049
1050         nc->show();
1051         nc->exec();
1052 }
1053
1054
1055 void WpaGui::editSelectedNetwork()
1056 {
1057         if (networkSelect->count() < 1) {
1058                 QMessageBox::information(this, "No Networks",
1059                                          "There are no networks to edit.\n");
1060                 return;
1061         }
1062         QString sel(networkSelect->currentText());
1063         editNetwork(sel);
1064 }
1065
1066
1067 void WpaGui::editListedNetwork()
1068 {
1069         if (networkList->currentRow() < 0) {
1070                 QMessageBox::information(this, "Select A Network",
1071                                          "Select a network from the list to"
1072                                          " edit it.\n");
1073                 return;
1074         }
1075         QString sel(networkList->currentItem()->text());
1076         editNetwork(sel);
1077 }
1078
1079
1080 void WpaGui::triggerUpdate()
1081 {
1082         updateStatus();
1083         networkMayHaveChanged = true;
1084         updateNetworks();
1085 }
1086
1087
1088 void WpaGui::addNetwork()
1089 {
1090         NetworkConfig *nc = new NetworkConfig();
1091         if (nc == NULL)
1092                 return;
1093         nc->setWpaGui(this);
1094         nc->newNetwork();
1095         nc->show();
1096         nc->exec();
1097 }
1098
1099
1100 void WpaGui::removeNetwork(const QString &sel)
1101 {
1102         QString cmd(sel);
1103         char reply[10];
1104         size_t reply_len = sizeof(reply);
1105
1106         if (cmd.startsWith("Select any"))
1107                 return;
1108
1109         if (!cmd.startsWith("all")) {
1110                 int pos = cmd.indexOf(':');
1111                 if (pos < 0) {
1112                         printf("Invalid removeNetwork '%s'\n",
1113                                cmd.toAscii().constData());
1114                         return;
1115                 }
1116                 cmd.truncate(pos);
1117         }
1118         cmd.prepend("REMOVE_NETWORK ");
1119         ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
1120         triggerUpdate();
1121 }
1122
1123
1124 void WpaGui::removeSelectedNetwork()
1125 {
1126         if (networkSelect->count() < 1) {
1127                 QMessageBox::information(this, "No Networks",
1128                                          "There are no networks to remove.\n");
1129                 return;
1130         }
1131         QString sel(networkSelect->currentText());
1132         removeNetwork(sel);
1133 }
1134
1135
1136 void WpaGui::removeListedNetwork()
1137 {
1138         if (networkList->currentRow() < 0) {
1139                 QMessageBox::information(this, "Select A Network",
1140                                          "Select a network from the list to"
1141                                          " remove it.\n");
1142                 return;
1143         }
1144         QString sel(networkList->currentItem()->text());
1145         removeNetwork(sel);
1146 }
1147
1148
1149 void WpaGui::enableAllNetworks()
1150 {
1151         QString sel("all");
1152         enableNetwork(sel);
1153 }
1154
1155
1156 void WpaGui::disableAllNetworks()
1157 {
1158         QString sel("all");
1159         disableNetwork(sel);
1160 }
1161
1162
1163 void WpaGui::removeAllNetworks()
1164 {
1165         QString sel("all");
1166         removeNetwork(sel);
1167 }
1168
1169
1170 int WpaGui::getNetworkDisabled(const QString &sel)
1171 {
1172         QString cmd(sel);
1173         char reply[10];
1174         size_t reply_len = sizeof(reply) - 1;
1175         int pos = cmd.indexOf(':');
1176         if (pos < 0) {
1177                 printf("Invalid getNetworkDisabled '%s'\n",
1178                        cmd.toAscii().constData());
1179                 return -1;
1180         }
1181         cmd.truncate(pos);
1182         cmd.prepend("GET_NETWORK ");
1183         cmd.append(" disabled");
1184
1185         if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0
1186             && reply_len >= 1) {
1187                 reply[reply_len] = '\0';
1188                 if (!str_match(reply, "FAIL"))
1189                         return atoi(reply);
1190         }
1191
1192         return -1;
1193 }
1194
1195
1196 void WpaGui::updateNetworkDisabledStatus()
1197 {
1198         if (networkList->currentRow() < 0)
1199                 return;
1200
1201         QString sel(networkList->currentItem()->text());
1202
1203         switch (getNetworkDisabled(sel)) {
1204         case 0:
1205                 if (!enableRadioButton->isChecked())
1206                         enableRadioButton->setChecked(true);
1207                 return;
1208         case 1:
1209                 if (!disableRadioButton->isChecked())
1210                         disableRadioButton->setChecked(true);
1211                 return;
1212         }
1213 }
1214
1215
1216 void WpaGui::enableListedNetwork(bool enabled)
1217 {
1218         if (networkList->currentRow() < 0 || !enabled)
1219                 return;
1220
1221         QString sel(networkList->currentItem()->text());
1222
1223         if (getNetworkDisabled(sel) == 1)
1224                 enableNetwork(sel);
1225 }
1226
1227
1228 void WpaGui::disableListedNetwork(bool disabled)
1229 {
1230         if (networkList->currentRow() < 0 || !disabled)
1231                 return;
1232
1233         QString sel(networkList->currentItem()->text());
1234
1235         if (getNetworkDisabled(sel) == 0)
1236                 disableNetwork(sel);
1237 }
1238
1239
1240 void WpaGui::saveConfig()
1241 {
1242         char buf[10];
1243         size_t len;
1244
1245         len = sizeof(buf) - 1;
1246         ctrlRequest("SAVE_CONFIG", buf, &len);
1247
1248         buf[len] = '\0';
1249
1250         if (str_match(buf, "FAIL"))
1251                 QMessageBox::warning(this, "Failed to save configuration",
1252                                      "The configuration could not be saved.\n"
1253                                      "\n"
1254                                      "The update_config=1 configuration option\n"
1255                                      "must be used for configuration saving to\n"
1256                                      "be permitted.\n");
1257         else
1258                 QMessageBox::information(this, "Saved configuration",
1259                                          "The current configuration was saved."
1260                                          "\n");
1261 }
1262
1263
1264 void WpaGui::selectAdapter( const QString & sel )
1265 {
1266         if (openCtrlConnection(sel.toAscii().constData()) < 0)
1267                 printf("Failed to open control connection to "
1268                        "wpa_supplicant.\n");
1269         updateStatus();
1270         updateNetworks();
1271 }
1272
1273
1274 void WpaGui::createTrayIcon(bool trayOnly)
1275 {
1276         QApplication::setQuitOnLastWindowClosed(false);
1277
1278         tray_icon = new QSystemTrayIcon(this);
1279         tray_icon->setToolTip(qAppName() + " - wpa_supplicant user interface");
1280         if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
1281                 tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
1282         else
1283                 tray_icon->setIcon(QIcon(":/icons/wpa_gui.png"));
1284
1285         connect(tray_icon,
1286                 SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
1287                 this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
1288
1289         ackTrayIcon = false;
1290
1291         tray_menu = new QMenu(this);
1292
1293         disconnectAction = new QAction("&Disconnect", this);
1294         reconnectAction = new QAction("Re&connect", this);
1295         connect(disconnectAction, SIGNAL(triggered()), this,
1296                 SLOT(disconnect()));
1297         connect(reconnectAction, SIGNAL(triggered()), this,
1298                 SLOT(connectB()));
1299         tray_menu->addAction(disconnectAction);
1300         tray_menu->addAction(reconnectAction);
1301         tray_menu->addSeparator();
1302
1303         eventAction = new QAction("&Event History", this);
1304         scanAction = new QAction("Scan &Results", this);
1305         statAction = new QAction("S&tatus", this);
1306         connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
1307         connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
1308         connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
1309         tray_menu->addAction(eventAction);
1310         tray_menu->addAction(scanAction);
1311         tray_menu->addAction(statAction);
1312         tray_menu->addSeparator();
1313
1314         showAction = new QAction("&Show Window", this);
1315         hideAction = new QAction("&Hide Window", this);
1316         quitAction = new QAction("&Quit", this);
1317         connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
1318         connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
1319         connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
1320         tray_menu->addAction(showAction);
1321         tray_menu->addAction(hideAction);
1322         tray_menu->addSeparator();
1323         tray_menu->addAction(quitAction);
1324
1325         tray_icon->setContextMenu(tray_menu);
1326
1327         tray_icon->show();
1328
1329         if (!trayOnly)
1330                 show();
1331         inTray = trayOnly;
1332 }
1333
1334
1335 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
1336                              const QString & msg)
1337 {
1338         if (!QSystemTrayIcon::supportsMessages())
1339                 return;
1340
1341         if (isVisible() || !tray_icon || !tray_icon->isVisible())
1342                 return;
1343
1344         tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
1345 }
1346
1347
1348 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
1349  {
1350         switch (how) {
1351         /* use close() here instead of hide() and allow the
1352          * custom closeEvent handler take care of children */
1353         case QSystemTrayIcon::Trigger:
1354                 ackTrayIcon = true;
1355                 if (isVisible()) {
1356                         close();
1357                         inTray = true;
1358                 } else {
1359                         show();
1360                         inTray = false;
1361                 }
1362                 break;
1363         case QSystemTrayIcon::MiddleClick:
1364                 showTrayStatus();
1365                 break;
1366         default:
1367                 break;
1368         }
1369 }
1370
1371
1372 void WpaGui::showTrayStatus()
1373 {
1374         char buf[2048];
1375         size_t len;
1376
1377         len = sizeof(buf) - 1;
1378         if (ctrlRequest("STATUS", buf, &len) < 0)
1379                 return;
1380         buf[len] = '\0';
1381
1382         QString msg, status(buf);
1383
1384         QStringList lines = status.split(QRegExp("\\n"));
1385         for (QStringList::Iterator it = lines.begin();
1386              it != lines.end(); it++) {
1387                 int pos = (*it).indexOf('=') + 1;
1388                 if (pos < 1)
1389                         continue;
1390
1391                 if ((*it).startsWith("bssid="))
1392                         msg.append("BSSID:\t" + (*it).mid(pos) + "\n");
1393                 else if ((*it).startsWith("ssid="))
1394                         msg.append("SSID: \t" + (*it).mid(pos) + "\n");
1395                 else if ((*it).startsWith("pairwise_cipher="))
1396                         msg.append("PAIR: \t" + (*it).mid(pos) + "\n");
1397                 else if ((*it).startsWith("group_cipher="))
1398                         msg.append("GROUP:\t" + (*it).mid(pos) + "\n");
1399                 else if ((*it).startsWith("key_mgmt="))
1400                         msg.append("AUTH: \t" + (*it).mid(pos) + "\n");
1401                 else if ((*it).startsWith("wpa_state="))
1402                         msg.append("STATE:\t" + (*it).mid(pos) + "\n");
1403                 else if ((*it).startsWith("ip_address="))
1404                         msg.append("IP:   \t" + (*it).mid(pos) + "\n");
1405                 else if ((*it).startsWith("Supplicant PAE state="))
1406                         msg.append("PAE:  \t" + (*it).mid(pos) + "\n");
1407                 else if ((*it).startsWith("EAP state="))
1408                         msg.append("EAP:  \t" + (*it).mid(pos) + "\n");
1409         }
1410
1411         if (!msg.isEmpty())
1412                 showTrayMessage(QSystemTrayIcon::Information, 10, msg);
1413 }
1414
1415
1416 void WpaGui::closeEvent(QCloseEvent *event)
1417 {
1418         if (eh) {
1419                 eh->close();
1420                 delete eh;
1421                 eh = NULL;
1422         }
1423
1424         if (scanres) {
1425                 scanres->close();
1426                 delete scanres;
1427                 scanres = NULL;
1428         }
1429
1430         if (peers) {
1431                 peers->close();
1432                 delete peers;
1433                 peers = NULL;
1434         }
1435
1436         if (udr) {
1437                 udr->close();
1438                 delete udr;
1439                 udr = NULL;
1440         }
1441
1442         if (tray_icon && !ackTrayIcon) {
1443                 /* give user a visual hint that the tray icon exists */
1444                 if (QSystemTrayIcon::supportsMessages()) {
1445                         hide();
1446                         showTrayMessage(QSystemTrayIcon::Information, 3,
1447                                         qAppName() + " will keep running in "
1448                                         "the system tray.");
1449                 } else {
1450                         QMessageBox::information(this, qAppName() + " systray",
1451                                                  "The program will keep "
1452                                                  "running in the system "
1453                                                  "tray.");
1454                 }
1455                 ackTrayIcon = true;
1456         }
1457
1458         event->accept();
1459 }
1460
1461
1462 void WpaGui::wpsDialog()
1463 {
1464         wpaguiTab->setCurrentWidget(wpsTab);
1465 }
1466
1467
1468 void WpaGui::peersDialog()
1469 {
1470         if (peers) {
1471                 peers->close();
1472                 delete peers;
1473         }
1474
1475         peers = new Peers();
1476         if (peers == NULL)
1477                 return;
1478         peers->setWpaGui(this);
1479         peers->show();
1480         peers->exec();
1481 }
1482
1483
1484 void WpaGui::tabChanged(int index)
1485 {
1486         if (index != 2)
1487                 return;
1488
1489         if (wpsRunning)
1490                 return;
1491
1492         wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1493         if (bssFromScan.isEmpty())
1494                 wpsApPinButton->setEnabled(false);
1495 }
1496
1497
1498 void WpaGui::wpsPbc()
1499 {
1500         char reply[20];
1501         size_t reply_len = sizeof(reply);
1502
1503         if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
1504                 return;
1505
1506         wpsPinEdit->setEnabled(false);
1507         if (wpsStatusText->text().compare("WPS AP in active PBC mode found")) {
1508                 wpsInstructions->setText("Press the push button on the AP to "
1509                                          "start the PBC mode.");
1510         } else {
1511                 wpsInstructions->setText("If you have not yet done so, press "
1512                                          "the push button on the AP to start "
1513                                          "the PBC mode.");
1514         }
1515         wpsStatusText->setText("Waiting for Registrar");
1516         wpsRunning = true;
1517 }
1518
1519
1520 void WpaGui::wpsGeneratePin()
1521 {
1522         char reply[20];
1523         size_t reply_len = sizeof(reply) - 1;
1524
1525         if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
1526                 return;
1527
1528         reply[reply_len] = '\0';
1529
1530         wpsPinEdit->setText(reply);
1531         wpsPinEdit->setEnabled(true);
1532         wpsInstructions->setText("Enter the generated PIN into the Registrar "
1533                                  "(either the internal one in the AP or an "
1534                                  "external one).");
1535         wpsStatusText->setText("Waiting for Registrar");
1536         wpsRunning = true;
1537 }
1538
1539
1540 void WpaGui::setBssFromScan(const QString &bssid)
1541 {
1542         bssFromScan = bssid;
1543         wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
1544         wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
1545         wpsStatusText->setText("WPS AP selected from scan results");
1546         wpsInstructions->setText("If you want to use an AP device PIN, e.g., "
1547                                  "from a label in the device, enter the eight "
1548                                  "digit AP PIN and click Use AP PIN button.");
1549 }
1550
1551
1552 void WpaGui::wpsApPinChanged(const QString &text)
1553 {
1554         wpsApPinButton->setEnabled(text.length() == 8);
1555 }
1556
1557
1558 void WpaGui::wpsApPin()
1559 {
1560         char reply[20];
1561         size_t reply_len = sizeof(reply);
1562
1563         QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
1564         if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0)
1565                 return;
1566
1567         wpsStatusText->setText("Waiting for AP/Enrollee");
1568         wpsRunning = true;
1569 }
1570
1571
1572 void WpaGui::stopWpsRun(bool success)
1573 {
1574         if (wpsRunning)
1575                 wpsStatusText->setText(success ? "Connected to the network" :
1576                                        "Stopped");
1577         else
1578                 wpsStatusText->setText("");
1579         wpsPinEdit->setEnabled(false);
1580         wpsInstructions->setText("");
1581         wpsRunning = false;
1582         bssFromScan = "";
1583         wpsApPinEdit->setEnabled(false);
1584         wpsApPinButton->setEnabled(false);
1585 }
1586
1587
1588 #ifdef CONFIG_NATIVE_WINDOWS
1589
1590 #ifndef WPASVC_NAME
1591 #define WPASVC_NAME TEXT("wpasvc")
1592 #endif
1593
1594 class ErrorMsg : public QMessageBox {
1595 public:
1596         ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
1597         void showMsg(QString msg);
1598 private:
1599         DWORD err;
1600 };
1601
1602 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
1603         QMessageBox(parent), err(last_err)
1604 {
1605         setWindowTitle("wpa_gui error");
1606         setIcon(QMessageBox::Warning);
1607 }
1608
1609 void ErrorMsg::showMsg(QString msg)
1610 {
1611         LPTSTR buf;
1612
1613         setText(msg);
1614         if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1615                           FORMAT_MESSAGE_FROM_SYSTEM,
1616                           NULL, err, 0, (LPTSTR) (void *) &buf,
1617                           0, NULL) > 0) {
1618                 QString msg = QString::fromWCharArray(buf);
1619                 setInformativeText(QString("[%1] %2").arg(err).arg(msg));
1620                 LocalFree(buf);
1621         } else {
1622                 setInformativeText(QString("[%1]").arg(err));
1623         }
1624
1625         exec();
1626 }
1627
1628
1629 void WpaGui::startService()
1630 {
1631         SC_HANDLE svc, scm;
1632
1633         scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1634         if (!scm) {
1635                 ErrorMsg(this).showMsg("OpenSCManager failed");
1636                 return;
1637         }
1638
1639         svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
1640         if (!svc) {
1641                 ErrorMsg(this).showMsg("OpenService failed");
1642                 CloseServiceHandle(scm);
1643                 return;
1644         }
1645
1646         if (!StartService(svc, 0, NULL)) {
1647                 ErrorMsg(this).showMsg("Failed to start wpa_supplicant "
1648                                        "service");
1649         }
1650
1651         CloseServiceHandle(svc);
1652         CloseServiceHandle(scm);
1653 }
1654
1655
1656 void WpaGui::stopService()
1657 {
1658         SC_HANDLE svc, scm;
1659         SERVICE_STATUS status;
1660
1661         scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1662         if (!scm) {
1663                 ErrorMsg(this).showMsg("OpenSCManager failed");
1664                 return;
1665         }
1666
1667         svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
1668         if (!svc) {
1669                 ErrorMsg(this).showMsg("OpenService failed");
1670                 CloseServiceHandle(scm);
1671                 return;
1672         }
1673
1674         if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
1675                 ErrorMsg(this).showMsg("Failed to stop wpa_supplicant "
1676                                        "service");
1677         }
1678
1679         CloseServiceHandle(svc);
1680         CloseServiceHandle(scm);
1681 }
1682
1683
1684 bool WpaGui::serviceRunning()
1685 {
1686         SC_HANDLE svc, scm;
1687         SERVICE_STATUS status;
1688         bool running = false;
1689
1690         scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
1691         if (!scm) {
1692                 printf("OpenSCManager failed: %d\n", (int) GetLastError());
1693                 return false;
1694         }
1695
1696         svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
1697         if (!svc) {
1698                 printf("OpenService failed: %d\n\n", (int) GetLastError());
1699                 CloseServiceHandle(scm);
1700                 return false;
1701         }
1702
1703         if (QueryServiceStatus(svc, &status)) {
1704                 if (status.dwCurrentState != SERVICE_STOPPED)
1705                         running = true;
1706         }
1707
1708         CloseServiceHandle(svc);
1709         CloseServiceHandle(scm);
1710
1711         return running;
1712 }
1713
1714 #endif /* CONFIG_NATIVE_WINDOWS */
1715
1716
1717 void WpaGui::addInterface()
1718 {
1719         if (add_iface) {
1720                 add_iface->close();
1721                 delete add_iface;
1722         }
1723         add_iface = new AddInterface(this, this);
1724         add_iface->show();
1725         add_iface->exec();
1726 }
1727
1728
1729 #ifndef QT_NO_SESSIONMANAGER
1730 void WpaGui::saveState()
1731 {
1732         QSettings settings("wpa_supplicant", "wpa_gui");
1733         settings.beginGroup("state");
1734         settings.setValue("session_id", app->sessionId());
1735         settings.setValue("in_tray", inTray);
1736         settings.endGroup();
1737 }
1738 #endif