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