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