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