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