Re-initialize hostapd/wpa_supplicant git repository based on 0.6.3 release
[wpasupplicant] / 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 #include <QMessageBox>
21 #include <QCloseEvent>
22
23 #include "wpagui.h"
24 #include "dirent.h"
25 #include "wpa_ctrl.h"
26 #include "userdatarequest.h"
27 #include "networkconfig.h"
28
29 WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
30         : QMainWindow(parent)
31 {
32         setupUi(this);
33
34         (void) statusBar();
35
36         connect(fileEventHistoryAction, SIGNAL(triggered()), this,
37                 SLOT(eventHistory()));
38         connect(fileSaveConfigAction, SIGNAL(triggered()), this,
39                 SLOT(saveConfig()));
40         connect(fileExitAction, SIGNAL(triggered()), this, SLOT(close()));
41         connect(networkAddAction, SIGNAL(triggered()), this,
42                 SLOT(addNetwork()));
43         connect(networkEditAction, SIGNAL(triggered()), this,
44                 SLOT(editSelectedNetwork()));
45         connect(networkRemoveAction, SIGNAL(triggered()), this,
46                 SLOT(removeSelectedNetwork()));
47         connect(networkEnableAllAction, SIGNAL(triggered()), this,
48                 SLOT(enableAllNetworks()));
49         connect(networkDisableAllAction, SIGNAL(triggered()), this,
50                 SLOT(disableAllNetworks()));
51         connect(networkRemoveAllAction, SIGNAL(triggered()), this,
52                 SLOT(removeAllNetworks()));
53         connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex()));
54         connect(helpContentsAction, SIGNAL(triggered()), this,
55                 SLOT(helpContents()));
56         connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout()));
57         connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
58         connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
59         connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
60         connect(adapterSelect, SIGNAL(activated(const QString&)), this,
61                 SLOT(selectAdapter(const QString&)));
62         connect(networkSelect, SIGNAL(activated(const QString&)), this,
63                 SLOT(selectNetwork(const QString&)));
64         connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
65         connect(editNetworkButton, SIGNAL(clicked()), this,
66                 SLOT(editListedNetwork()));
67         connect(removeNetworkButton, SIGNAL(clicked()), this,
68                 SLOT(removeListedNetwork()));
69         connect(networkList, SIGNAL(itemSelectionChanged()), this,
70                 SLOT(updateNetworkDisabledStatus()));
71         connect(enableRadioButton, SIGNAL(toggled(bool)), this,
72                 SLOT(enableListedNetwork(bool)));
73         connect(disableRadioButton, SIGNAL(toggled(bool)), this,
74                 SLOT(disableListedNetwork(bool)));
75         connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan()));
76         connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
77                 this, SLOT(editListedNetwork()));
78
79         eh = NULL;
80         scanres = NULL;
81         udr = NULL;
82         ctrl_iface = NULL;
83         ctrl_conn = NULL;
84         monitor_conn = NULL;
85         msgNotifier = NULL;
86         ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
87
88         parse_argv();
89
90         textStatus->setText("connecting to wpa_supplicant");
91         timer = new QTimer(this);
92         connect(timer, SIGNAL(timeout()), SLOT(ping()));
93         timer->setSingleShot(FALSE);
94         timer->start(1000);
95
96         if (openCtrlConnection(ctrl_iface) < 0) {
97                 printf("Failed to open control connection to "
98                        "wpa_supplicant.\n");
99         }
100
101         updateStatus();
102         networkMayHaveChanged = true;
103         updateNetworks();
104 }
105
106
107 WpaGui::~WpaGui()
108 {
109         delete msgNotifier;
110
111         if (monitor_conn) {
112                 wpa_ctrl_detach(monitor_conn);
113                 wpa_ctrl_close(monitor_conn);
114                 monitor_conn = NULL;
115         }
116         if (ctrl_conn) {
117                 wpa_ctrl_close(ctrl_conn);
118                 ctrl_conn = NULL;
119         }
120
121         if (eh) {
122                 eh->close();
123                 delete eh;
124                 eh = NULL;
125         }
126
127         if (scanres) {
128                 scanres->close();
129                 delete scanres;
130                 scanres = NULL;
131         }
132
133         if (udr) {
134                 udr->close();
135                 delete udr;
136                 udr = NULL;
137         }
138
139         free(ctrl_iface);
140         ctrl_iface = NULL;
141
142         free(ctrl_iface_dir);
143         ctrl_iface_dir = NULL;
144 }
145
146
147 void WpaGui::languageChange()
148 {
149         retranslateUi(this);
150 }
151
152
153 void WpaGui::parse_argv()
154 {
155         int c;
156         for (;;) {
157                 c = getopt(qApp->argc(), qApp->argv(), "i:p:");
158                 if (c < 0)
159                         break;
160                 switch (c) {
161                 case 'i':
162                         free(ctrl_iface);
163                         ctrl_iface = strdup(optarg);
164                         break;
165                 case 'p':
166                         free(ctrl_iface_dir);
167                         ctrl_iface_dir = strdup(optarg);
168                         break;
169                 }
170         }
171 }
172
173
174 int WpaGui::openCtrlConnection(const char *ifname)
175 {
176         char *cfile;
177         int flen;
178         char buf[2048], *pos, *pos2;
179         size_t len;
180
181         if (ifname) {
182                 if (ifname != ctrl_iface) {
183                         free(ctrl_iface);
184                         ctrl_iface = strdup(ifname);
185                 }
186         } else {
187 #ifdef CONFIG_CTRL_IFACE_UDP
188                 free(ctrl_iface);
189                 ctrl_iface = strdup("udp");
190 #endif /* CONFIG_CTRL_IFACE_UDP */
191 #ifdef CONFIG_CTRL_IFACE_UNIX
192                 struct dirent *dent;
193                 DIR *dir = opendir(ctrl_iface_dir);
194                 free(ctrl_iface);
195                 ctrl_iface = NULL;
196                 if (dir) {
197                         while ((dent = readdir(dir))) {
198 #ifdef _DIRENT_HAVE_D_TYPE
199                                 /* Skip the file if it is not a socket.
200                                  * Also accept DT_UNKNOWN (0) in case
201                                  * the C library or underlying file
202                                  * system does not support d_type. */
203                                 if (dent->d_type != DT_SOCK &&
204                                     dent->d_type != DT_UNKNOWN)
205                                         continue;
206 #endif /* _DIRENT_HAVE_D_TYPE */
207
208                                 if (strcmp(dent->d_name, ".") == 0 ||
209                                     strcmp(dent->d_name, "..") == 0)
210                                         continue;
211                                 printf("Selected interface '%s'\n",
212                                        dent->d_name);
213                                 ctrl_iface = strdup(dent->d_name);
214                                 break;
215                         }
216                         closedir(dir);
217                 }
218 #endif /* CONFIG_CTRL_IFACE_UNIX */
219 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
220                 struct wpa_ctrl *ctrl;
221                 int ret;
222
223                 free(ctrl_iface);
224                 ctrl_iface = NULL;
225
226                 ctrl = wpa_ctrl_open(NULL);
227                 if (ctrl) {
228                         len = sizeof(buf) - 1;
229                         ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
230                                                &len, NULL);
231                         if (ret >= 0) {
232                                 buf[len] = '\0';
233                                 pos = strchr(buf, '\n');
234                                 if (pos)
235                                         *pos = '\0';
236                                 ctrl_iface = strdup(buf);
237                         }
238                         wpa_ctrl_close(ctrl);
239                 }
240 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
241         }
242
243         if (ctrl_iface == NULL)
244                 return -1;
245
246 #ifdef CONFIG_CTRL_IFACE_UNIX
247         flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
248         cfile = (char *) malloc(flen);
249         if (cfile == NULL)
250                 return -1;
251         snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
252 #else /* CONFIG_CTRL_IFACE_UNIX */
253         flen = strlen(ctrl_iface) + 1;
254         cfile = (char *) malloc(flen);
255         if (cfile == NULL)
256                 return -1;
257         snprintf(cfile, flen, "%s", ctrl_iface);
258 #endif /* CONFIG_CTRL_IFACE_UNIX */
259
260         if (ctrl_conn) {
261                 wpa_ctrl_close(ctrl_conn);
262                 ctrl_conn = NULL;
263         }
264
265         if (monitor_conn) {
266                 delete msgNotifier;
267                 msgNotifier = NULL;
268                 wpa_ctrl_detach(monitor_conn);
269                 wpa_ctrl_close(monitor_conn);
270                 monitor_conn = NULL;
271         }
272
273         printf("Trying to connect to '%s'\n", cfile);
274         ctrl_conn = wpa_ctrl_open(cfile);
275         if (ctrl_conn == NULL) {
276                 free(cfile);
277                 return -1;
278         }
279         monitor_conn = wpa_ctrl_open(cfile);
280         free(cfile);
281         if (monitor_conn == NULL) {
282                 wpa_ctrl_close(ctrl_conn);
283                 return -1;
284         }
285         if (wpa_ctrl_attach(monitor_conn)) {
286                 printf("Failed to attach to wpa_supplicant\n");
287                 wpa_ctrl_close(monitor_conn);
288                 monitor_conn = NULL;
289                 wpa_ctrl_close(ctrl_conn);
290                 ctrl_conn = NULL;
291                 return -1;
292         }
293
294 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
295         msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
296                                           QSocketNotifier::Read, this);
297         connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
298 #endif
299
300         adapterSelect->clear();
301         adapterSelect->addItem(ctrl_iface);
302         adapterSelect->setCurrentIndex(0);
303
304         len = sizeof(buf) - 1;
305         if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
306             0) {
307                 buf[len] = '\0';
308                 pos = buf;
309                 while (*pos) {
310                         pos2 = strchr(pos, '\n');
311                         if (pos2)
312                                 *pos2 = '\0';
313                         if (strcmp(pos, ctrl_iface) != 0)
314                                 adapterSelect->addItem(pos);
315                         if (pos2)
316                                 pos = pos2 + 1;
317                         else
318                                 break;
319                 }
320         }
321
322         return 0;
323 }
324
325
326 static void wpa_gui_msg_cb(char *msg, size_t)
327 {
328         /* This should not happen anymore since two control connections are
329          * used. */
330         printf("missed message: %s\n", msg);
331 }
332
333
334 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
335 {
336         int ret;
337
338         if (ctrl_conn == NULL)
339                 return -3;
340         ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
341                                wpa_gui_msg_cb);
342         if (ret == -2)
343                 printf("'%s' command timed out.\n", cmd);
344         else if (ret < 0)
345                 printf("'%s' command failed.\n", cmd);
346
347         return ret;
348 }
349
350
351 void WpaGui::updateStatus()
352 {
353         char buf[2048], *start, *end, *pos;
354         size_t len;
355
356         pingsToStatusUpdate = 10;
357
358         len = sizeof(buf) - 1;
359         if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
360                 textStatus->setText("Could not get status from "
361                                     "wpa_supplicant");
362                 textAuthentication->clear();
363                 textEncryption->clear();
364                 textSsid->clear();
365                 textBssid->clear();
366                 textIpAddress->clear();
367                 return;
368         }
369
370         buf[len] = '\0';
371
372         bool auth_updated = false, ssid_updated = false;
373         bool bssid_updated = false, ipaddr_updated = false;
374         bool status_updated = false;
375         char *pairwise_cipher = NULL, *group_cipher = NULL;
376
377         start = buf;
378         while (*start) {
379                 bool last = false;
380                 end = strchr(start, '\n');
381                 if (end == NULL) {
382                         last = true;
383                         end = start;
384                         while (end[0] && end[1])
385                                 end++;
386                 }
387                 *end = '\0';
388
389                 pos = strchr(start, '=');
390                 if (pos) {
391                         *pos++ = '\0';
392                         if (strcmp(start, "bssid") == 0) {
393                                 bssid_updated = true;
394                                 textBssid->setText(pos);
395                         } else if (strcmp(start, "ssid") == 0) {
396                                 ssid_updated = true;
397                                 textSsid->setText(pos);
398                         } else if (strcmp(start, "ip_address") == 0) {
399                                 ipaddr_updated = true;
400                                 textIpAddress->setText(pos);
401                         } else if (strcmp(start, "wpa_state") == 0) {
402                                 status_updated = true;
403                                 textStatus->setText(pos);
404                         } else if (strcmp(start, "key_mgmt") == 0) {
405                                 auth_updated = true;
406                                 textAuthentication->setText(pos);
407                                 /* TODO: could add EAP status to this */
408                         } else if (strcmp(start, "pairwise_cipher") == 0) {
409                                 pairwise_cipher = pos;
410                         } else if (strcmp(start, "group_cipher") == 0) {
411                                 group_cipher = pos;
412                         }
413                 }
414
415                 if (last)
416                         break;
417                 start = end + 1;
418         }
419
420         if (pairwise_cipher || group_cipher) {
421                 QString encr;
422                 if (pairwise_cipher && group_cipher &&
423                     strcmp(pairwise_cipher, group_cipher) != 0) {
424                         encr.append(pairwise_cipher);
425                         encr.append(" + ");
426                         encr.append(group_cipher);
427                 } else if (pairwise_cipher) {
428                         encr.append(pairwise_cipher);
429                 } else {
430                         encr.append(group_cipher);
431                         encr.append(" [group key only]");
432                 }
433                 textEncryption->setText(encr);
434         } else
435                 textEncryption->clear();
436
437         if (!status_updated)
438                 textStatus->clear();
439         if (!auth_updated)
440                 textAuthentication->clear();
441         if (!ssid_updated)
442                 textSsid->clear();
443         if (!bssid_updated)
444                 textBssid->clear();
445         if (!ipaddr_updated)
446                 textIpAddress->clear();
447 }
448
449
450 void WpaGui::updateNetworks()
451 {
452         char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
453         size_t len;
454         int first_active = -1;
455         int was_selected = -1;
456         bool current = false;
457
458         if (!networkMayHaveChanged)
459                 return;
460
461         if (networkList->currentRow() >= 0)
462                 was_selected = networkList->currentRow();
463
464         networkSelect->clear();
465         networkList->clear();
466
467         if (ctrl_conn == NULL)
468                 return;
469
470         len = sizeof(buf) - 1;
471         if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
472                 return;
473
474         buf[len] = '\0';
475         start = strchr(buf, '\n');
476         if (start == NULL)
477                 return;
478         start++;
479
480         while (*start) {
481                 bool last = false;
482                 end = strchr(start, '\n');
483                 if (end == NULL) {
484                         last = true;
485                         end = start;
486                         while (end[0] && end[1])
487                                 end++;
488                 }
489                 *end = '\0';
490
491                 id = start;
492                 ssid = strchr(id, '\t');
493                 if (ssid == NULL)
494                         break;
495                 *ssid++ = '\0';
496                 bssid = strchr(ssid, '\t');
497                 if (bssid == NULL)
498                         break;
499                 *bssid++ = '\0';
500                 flags = strchr(bssid, '\t');
501                 if (flags == NULL)
502                         break;
503                 *flags++ = '\0';
504
505                 QString network(id);
506                 network.append(": ");
507                 network.append(ssid);
508                 networkSelect->addItem(network);
509                 networkList->addItem(network);
510
511                 if (strstr(flags, "[CURRENT]")) {
512                         networkSelect->setCurrentIndex(networkSelect->count() -
513                                                       1);
514                         current = true;
515                 } else if (first_active < 0 &&
516                            strstr(flags, "[DISABLED]") == NULL)
517                         first_active = networkSelect->count() - 1;
518
519                 if (last)
520                         break;
521                 start = end + 1;
522         }
523
524         if (networkSelect->count() > 1)
525                 networkSelect->addItem("Select any network");
526
527         if (!current && first_active >= 0)
528                 networkSelect->setCurrentIndex(first_active);
529
530         if (was_selected >= 0 && networkList->count() > 0) {
531                 if (was_selected < networkList->count())
532                         networkList->setCurrentRow(was_selected);
533                 else
534                         networkList->setCurrentRow(networkList->count() - 1);
535         }
536         else
537                 networkList->setCurrentRow(networkSelect->currentIndex());
538
539         networkMayHaveChanged = false;
540 }
541
542
543 void WpaGui::helpIndex()
544 {
545         printf("helpIndex\n");
546 }
547
548
549 void WpaGui::helpContents()
550 {
551         printf("helpContents\n");
552 }
553
554
555 void WpaGui::helpAbout()
556 {
557         QMessageBox::about(this, "wpa_gui for wpa_supplicant",
558                            "Copyright (c) 2003-2008,\n"
559                            "Jouni Malinen <j@w1.fi>\n"
560                            "and contributors.\n"
561                            "\n"
562                            "This program is free software. You can\n"
563                            "distribute it and/or modify it under the terms "
564                            "of\n"
565                            "the GNU General Public License version 2.\n"
566                            "\n"
567                            "Alternatively, this software may be distributed\n"
568                            "under the terms of the BSD license.\n"
569                            "\n"
570                            "This product includes software developed\n"
571                            "by the OpenSSL Project for use in the\n"
572                            "OpenSSL Toolkit (http://www.openssl.org/)\n");
573 }
574
575
576 void WpaGui::disconnect()
577 {
578         char reply[10];
579         size_t reply_len = sizeof(reply);
580         ctrlRequest("DISCONNECT", reply, &reply_len);
581 }
582
583
584 void WpaGui::scan()
585 {
586         if (scanres) {
587                 scanres->close();
588                 delete scanres;
589         }
590
591         scanres = new ScanResults();
592         if (scanres == NULL)
593                 return;
594         scanres->setWpaGui(this);
595         scanres->show();
596         scanres->exec();
597 }
598
599
600 void WpaGui::eventHistory()
601 {
602         if (eh) {
603                 eh->close();
604                 delete eh;
605         }
606
607         eh = new EventHistory();
608         if (eh == NULL)
609                 return;
610         eh->addEvents(msgs);
611         eh->show();
612         eh->exec();
613 }
614
615
616 void WpaGui::ping()
617 {
618         char buf[10];
619         size_t len;
620
621 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
622         /*
623          * QSocketNotifier cannot be used with Windows named pipes, so use a
624          * timer to check for received messages for now. This could be
625          * optimized be doing something specific to named pipes or Windows
626          * events, but it is not clear what would be the best way of doing that
627          * in Qt.
628          */
629         receiveMsgs();
630 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
631
632         if (scanres && !scanres->isVisible()) {
633                 delete scanres;
634                 scanres = NULL;
635         }
636
637         if (eh && !eh->isVisible()) {
638                 delete eh;
639                 eh = NULL;
640         }
641
642         if (udr && !udr->isVisible()) {
643                 delete udr;
644                 udr = NULL;
645         }
646
647         len = sizeof(buf) - 1;
648         if (ctrlRequest("PING", buf, &len) < 0) {
649                 printf("PING failed - trying to reconnect\n");
650                 if (openCtrlConnection(ctrl_iface) >= 0) {
651                         printf("Reconnected successfully\n");
652                         pingsToStatusUpdate = 0;
653                 }
654         }
655
656         pingsToStatusUpdate--;
657         if (pingsToStatusUpdate <= 0) {
658                 updateStatus();
659                 updateNetworks();
660         }
661 }
662
663
664 static int str_match(const char *a, const char *b)
665 {
666         return strncmp(a, b, strlen(b)) == 0;
667 }
668
669
670 void WpaGui::processMsg(char *msg)
671 {
672         char *pos = msg, *pos2;
673         int priority = 2;
674
675         if (*pos == '<') {
676                 /* skip priority */
677                 pos++;
678                 priority = atoi(pos);
679                 pos = strchr(pos, '>');
680                 if (pos)
681                         pos++;
682                 else
683                         pos = msg;
684         }
685
686         WpaMsg wm(pos, priority);
687         if (eh)
688                 eh->addEvent(wm);
689         msgs.append(wm);
690         while (msgs.count() > 100)
691                 msgs.pop_front();
692
693         /* Update last message with truncated version of the event */
694         if (strncmp(pos, "CTRL-", 5) == 0) {
695                 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
696                 if (pos2)
697                         pos2++;
698                 else
699                         pos2 = pos;
700         } else
701                 pos2 = pos;
702         QString lastmsg = pos2;
703         lastmsg.truncate(40);
704         textLastMessage->setText(lastmsg);
705
706         pingsToStatusUpdate = 0;
707         networkMayHaveChanged = true;
708
709         if (str_match(pos, WPA_CTRL_REQ))
710                 processCtrlReq(pos + strlen(WPA_CTRL_REQ));
711         else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres)
712                 scanres->updateResults();
713 }
714
715
716 void WpaGui::processCtrlReq(const char *req)
717 {
718         if (udr) {
719                 udr->close();
720                 delete udr;
721         }
722         udr = new UserDataRequest();
723         if (udr == NULL)
724                 return;
725         if (udr->setParams(this, req) < 0) {
726                 delete udr;
727                 udr = NULL;
728                 return;
729         }
730         udr->show();
731         udr->exec();
732 }
733
734
735 void WpaGui::receiveMsgs()
736 {
737         char buf[256];
738         size_t len;
739
740         while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
741                 len = sizeof(buf) - 1;
742                 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
743                         buf[len] = '\0';
744                         processMsg(buf);
745                 }
746         }
747 }
748
749
750 void WpaGui::connectB()
751 {
752         char reply[10];
753         size_t reply_len = sizeof(reply);
754         ctrlRequest("REASSOCIATE", reply, &reply_len);
755 }
756
757
758 void WpaGui::selectNetwork( const QString &sel )
759 {
760         QString cmd(sel);
761         char reply[10];
762         size_t reply_len = sizeof(reply);
763
764         if (cmd.startsWith("Select any")) {
765                 cmd = "any";
766         } else {
767                 int pos = cmd.indexOf(':');
768                 if (pos < 0) {
769                         printf("Invalid selectNetwork '%s'\n",
770                                cmd.toAscii().constData());
771                         return;
772                 }
773                 cmd.truncate(pos);
774         }
775         cmd.prepend("SELECT_NETWORK ");
776         ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
777         triggerUpdate();
778 }
779
780
781 void WpaGui::enableNetwork(const QString &sel)
782 {
783         QString cmd(sel);
784         char reply[10];
785         size_t reply_len = sizeof(reply);
786
787         if (!cmd.startsWith("all")) {
788                 int pos = cmd.indexOf(':');
789                 if (pos < 0) {
790                         printf("Invalid enableNetwork '%s'\n",
791                                cmd.toAscii().constData());
792                         return;
793                 }
794                 cmd.truncate(pos);
795         }
796         cmd.prepend("ENABLE_NETWORK ");
797         ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
798         triggerUpdate();
799 }
800
801
802 void WpaGui::disableNetwork(const QString &sel)
803 {
804         QString cmd(sel);
805         char reply[10];
806         size_t reply_len = sizeof(reply);
807
808         if (!cmd.startsWith("all")) {
809                 int pos = cmd.indexOf(':');
810                 if (pos < 0) {
811                         printf("Invalid disableNetwork '%s'\n",
812                                cmd.toAscii().constData());
813                         return;
814                 }
815                 cmd.truncate(pos);
816         }
817         cmd.prepend("DISABLE_NETWORK ");
818         ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
819         triggerUpdate();
820 }
821
822
823 void WpaGui::editNetwork(const QString &sel)
824 {
825         QString cmd(sel);
826         int id = -1;
827
828         if (!cmd.startsWith("Select any")) {
829                 int pos = sel.indexOf(':');
830                 if (pos < 0) {
831                         printf("Invalid editNetwork '%s'\n",
832                                cmd.toAscii().constData());
833                         return;
834                 }
835                 cmd.truncate(pos);
836                 id = cmd.toInt();
837         }
838
839         NetworkConfig *nc = new NetworkConfig();
840         if (nc == NULL)
841                 return;
842         nc->setWpaGui(this);
843
844         if (id >= 0)
845                 nc->paramsFromConfig(id);
846         else
847                 nc->newNetwork();
848
849         nc->show();
850         nc->exec();
851 }
852
853
854 void WpaGui::editSelectedNetwork()
855 {
856         if (networkSelect->count() < 1) {
857                 QMessageBox::information(this, "No Networks",
858                                          "There are no networks to edit.\n");
859                 return;
860         }
861         QString sel(networkSelect->currentText());
862         editNetwork(sel);
863 }
864
865
866 void WpaGui::editListedNetwork()
867 {
868         if (networkList->currentRow() < 0) {
869                 QMessageBox::information(this, "Select A Network",
870                                          "Select a network from the list to"
871                                          " edit it.\n");
872                 return;
873         }
874         QString sel(networkList->currentItem()->text());
875         editNetwork(sel);
876 }
877
878
879 void WpaGui::triggerUpdate()
880 {
881         updateStatus();
882         networkMayHaveChanged = true;
883         updateNetworks();
884 }
885
886
887 void WpaGui::addNetwork()
888 {
889         NetworkConfig *nc = new NetworkConfig();
890         if (nc == NULL)
891                 return;
892         nc->setWpaGui(this);
893         nc->newNetwork();
894         nc->show();
895         nc->exec();
896 }
897
898
899 void WpaGui::removeNetwork(const QString &sel)
900 {
901         QString cmd(sel);
902         char reply[10];
903         size_t reply_len = sizeof(reply);
904
905         if (cmd.startsWith("Select any"))
906                 return;
907
908         if (!cmd.startsWith("all")) {
909                 int pos = cmd.indexOf(':');
910                 if (pos < 0) {
911                         printf("Invalid removeNetwork '%s'\n",
912                                cmd.toAscii().constData());
913                         return;
914                 }
915                 cmd.truncate(pos);
916         }
917         cmd.prepend("REMOVE_NETWORK ");
918         ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
919         triggerUpdate();
920 }
921
922
923 void WpaGui::removeSelectedNetwork()
924 {
925         if (networkSelect->count() < 1) {
926                 QMessageBox::information(this, "No Networks",
927                                          "There are no networks to remove.\n");
928                 return;
929         }
930         QString sel(networkSelect->currentText());
931         removeNetwork(sel);
932 }
933
934
935 void WpaGui::removeListedNetwork()
936 {
937         if (networkList->currentRow() < 0) {
938                 QMessageBox::information(this, "Select A Network",
939                                          "Select a network from the list to"
940                                          " remove it.\n");
941                 return;
942         }
943         QString sel(networkList->currentItem()->text());
944         removeNetwork(sel);
945 }
946
947
948 void WpaGui::enableAllNetworks()
949 {
950         QString sel("all");
951         enableNetwork(sel);
952 }
953
954
955 void WpaGui::disableAllNetworks()
956 {
957         QString sel("all");
958         disableNetwork(sel);
959 }
960
961
962 void WpaGui::removeAllNetworks()
963 {
964         QString sel("all");
965         removeNetwork(sel);
966 }
967
968
969 int WpaGui::getNetworkDisabled(const QString &sel)
970 {
971         QString cmd(sel);
972         char reply[10];
973         size_t reply_len = sizeof(reply) - 1;
974         int pos = cmd.indexOf(':');
975         if (pos < 0) {
976                 printf("Invalid getNetworkDisabled '%s'\n",
977                        cmd.toAscii().constData());
978                 return -1;
979         }
980         cmd.truncate(pos);
981         cmd.prepend("GET_NETWORK ");
982         cmd.append(" disabled");
983
984         if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0
985             && reply_len >= 1) {
986                 reply[reply_len] = '\0';
987                 if (!str_match(reply, "FAIL"))
988                         return atoi(reply);
989         }
990
991         return -1;
992 }
993
994
995 void WpaGui::updateNetworkDisabledStatus()
996 {
997         if (networkList->currentRow() < 0)
998                 return;
999
1000         QString sel(networkList->currentItem()->text());
1001
1002         switch (getNetworkDisabled(sel)) {
1003         case 0:
1004                 if (!enableRadioButton->isChecked())
1005                         enableRadioButton->setChecked(true);
1006                 return;
1007         case 1:
1008                 if (!disableRadioButton->isChecked())
1009                         disableRadioButton->setChecked(true);
1010                 return;
1011         }
1012 }
1013
1014
1015 void WpaGui::enableListedNetwork(bool enabled)
1016 {
1017         if (networkList->currentRow() < 0 || !enabled)
1018                 return;
1019
1020         QString sel(networkList->currentItem()->text());
1021
1022         if (getNetworkDisabled(sel) == 1)
1023                 enableNetwork(sel);
1024 }
1025
1026
1027 void WpaGui::disableListedNetwork(bool disabled)
1028 {
1029         if (networkList->currentRow() < 0 || !disabled)
1030                 return;
1031
1032         QString sel(networkList->currentItem()->text());
1033
1034         if (getNetworkDisabled(sel) == 0)
1035                 disableNetwork(sel);
1036 }
1037
1038
1039 void WpaGui::saveConfig()
1040 {
1041         char buf[10];
1042         size_t len;
1043
1044         len = sizeof(buf) - 1;
1045         ctrlRequest("SAVE_CONFIG", buf, &len);
1046
1047         buf[len] = '\0';
1048
1049         if (str_match(buf, "FAIL"))
1050                 QMessageBox::warning(this, "Failed to save configuration",
1051                                      "The configuration could not be saved.\n"
1052                                      "\n"
1053                                      "The update_config=1 configuration option\n"
1054                                      "must be used for configuration saving to\n"
1055                                      "be permitted.\n");
1056         else
1057                 QMessageBox::information(this, "Saved configuration",
1058                                          "The current configuration was saved."
1059                                          "\n");
1060 }
1061
1062
1063 void WpaGui::selectAdapter( const QString & sel )
1064 {
1065         if (openCtrlConnection(sel.toAscii().constData()) < 0)
1066                 printf("Failed to open control connection to "
1067                        "wpa_supplicant.\n");
1068         updateStatus();
1069         updateNetworks();
1070 }
1071
1072
1073 void WpaGui::closeEvent(QCloseEvent *event)
1074 {
1075         if (eh) {
1076                 eh->close();
1077                 delete eh;
1078                 eh = NULL;
1079         }
1080
1081         if (scanres) {
1082                 scanres->close();
1083                 delete scanres;
1084                 scanres = NULL;
1085         }
1086
1087         if (udr) {
1088                 udr->close();
1089                 delete udr;
1090                 udr = NULL;
1091         }
1092
1093         event->accept();
1094 }