Home | History | Annotate | Download | only in wpa_gui-qt4
      1 /*
      2  * wpa_gui - WpaGui class
      3  * Copyright (c) 2005-2008, Jouni Malinen <j (at) 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 <cstdio>
     21 #include <QMessageBox>
     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(helpIndexAction, SIGNAL(activated()), this, SLOT(helpIndex()));
     37 	connect(helpContentsAction, SIGNAL(activated()), this,
     38 		SLOT(helpContents()));
     39 	connect(helpAboutAction, SIGNAL(activated()), this, SLOT(helpAbout()));
     40 	connect(fileExitAction, SIGNAL(activated()), this, SLOT(close()));
     41 	connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
     42 	connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
     43 	connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
     44 	connect(fileEventHistoryAction, SIGNAL(activated()), this,
     45 		SLOT(eventHistory()));
     46 	connect(networkSelect, SIGNAL(activated(const QString&)), this,
     47 		SLOT(selectNetwork(const QString&)));
     48 	connect(fileEdit_networkAction, SIGNAL(activated()), this,
     49 		SLOT(editNetwork()));
     50 	connect(fileAdd_NetworkAction, SIGNAL(activated()), this,
     51 		SLOT(addNetwork()));
     52 	connect(adapterSelect, SIGNAL(activated(const QString&)), this,
     53 		SLOT(selectAdapter(const QString&)));
     54 
     55 	eh = NULL;
     56 	scanres = NULL;
     57 	udr = NULL;
     58 	ctrl_iface = NULL;
     59 	ctrl_conn = NULL;
     60 	monitor_conn = NULL;
     61 	msgNotifier = NULL;
     62 	ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
     63 
     64 	parse_argv();
     65 
     66 	textStatus->setText("connecting to wpa_supplicant");
     67 	timer = new QTimer(this);
     68 	connect(timer, SIGNAL(timeout()), SLOT(ping()));
     69 	timer->start(1000, FALSE);
     70 
     71 	if (openCtrlConnection(ctrl_iface) < 0) {
     72 		printf("Failed to open control connection to "
     73 		       "wpa_supplicant.\n");
     74 	}
     75 
     76 	updateStatus();
     77 	networkMayHaveChanged = true;
     78 	updateNetworks();
     79 }
     80 
     81 
     82 WpaGui::~WpaGui()
     83 {
     84 	delete msgNotifier;
     85 
     86 	if (monitor_conn) {
     87 		wpa_ctrl_detach(monitor_conn);
     88 		wpa_ctrl_close(monitor_conn);
     89 		monitor_conn = NULL;
     90 	}
     91 	if (ctrl_conn) {
     92 		wpa_ctrl_close(ctrl_conn);
     93 		ctrl_conn = NULL;
     94 	}
     95 
     96 	if (eh) {
     97 		eh->close();
     98 		delete eh;
     99 		eh = NULL;
    100 	}
    101 
    102 	if (scanres) {
    103 		scanres->close();
    104 		delete scanres;
    105 		scanres = NULL;
    106 	}
    107 
    108 	if (udr) {
    109 		udr->close();
    110 		delete udr;
    111 		udr = NULL;
    112 	}
    113 
    114 	free(ctrl_iface);
    115 	ctrl_iface = NULL;
    116 
    117 	free(ctrl_iface_dir);
    118 	ctrl_iface_dir = NULL;
    119 }
    120 
    121 
    122 void WpaGui::languageChange()
    123 {
    124 	retranslateUi(this);
    125 }
    126 
    127 
    128 void WpaGui::parse_argv()
    129 {
    130 	int c;
    131 	for (;;) {
    132 		c = getopt(qApp->argc(), qApp->argv(), "i:p:");
    133 		if (c < 0)
    134 			break;
    135 		switch (c) {
    136 		case 'i':
    137 			free(ctrl_iface);
    138 			ctrl_iface = strdup(optarg);
    139 			break;
    140 		case 'p':
    141 			free(ctrl_iface_dir);
    142 			ctrl_iface_dir = strdup(optarg);
    143 			break;
    144 		}
    145 	}
    146 }
    147 
    148 
    149 int WpaGui::openCtrlConnection(const char *ifname)
    150 {
    151 	char *cfile;
    152 	int flen;
    153 	char buf[2048], *pos, *pos2;
    154 	size_t len;
    155 
    156 	if (ifname) {
    157 		if (ifname != ctrl_iface) {
    158 			free(ctrl_iface);
    159 			ctrl_iface = strdup(ifname);
    160 		}
    161 	} else {
    162 #ifdef CONFIG_CTRL_IFACE_UDP
    163 		free(ctrl_iface);
    164 		ctrl_iface = strdup("udp");
    165 #endif /* CONFIG_CTRL_IFACE_UDP */
    166 #ifdef CONFIG_CTRL_IFACE_UNIX
    167 		struct dirent *dent;
    168 		DIR *dir = opendir(ctrl_iface_dir);
    169 		free(ctrl_iface);
    170 		ctrl_iface = NULL;
    171 		if (dir) {
    172 			while ((dent = readdir(dir))) {
    173 #ifdef _DIRENT_HAVE_D_TYPE
    174 				/* Skip the file if it is not a socket.
    175 				 * Also accept DT_UNKNOWN (0) in case
    176 				 * the C library or underlying file
    177 				 * system does not support d_type. */
    178 				if (dent->d_type != DT_SOCK &&
    179 				    dent->d_type != DT_UNKNOWN)
    180 					continue;
    181 #endif /* _DIRENT_HAVE_D_TYPE */
    182 
    183 				if (strcmp(dent->d_name, ".") == 0 ||
    184 				    strcmp(dent->d_name, "..") == 0)
    185 					continue;
    186 				printf("Selected interface '%s'\n",
    187 				       dent->d_name);
    188 				ctrl_iface = strdup(dent->d_name);
    189 				break;
    190 			}
    191 			closedir(dir);
    192 		}
    193 #endif /* CONFIG_CTRL_IFACE_UNIX */
    194 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    195 		struct wpa_ctrl *ctrl;
    196 		int ret;
    197 
    198 		free(ctrl_iface);
    199 		ctrl_iface = NULL;
    200 
    201 		ctrl = wpa_ctrl_open(NULL);
    202 		if (ctrl) {
    203 			len = sizeof(buf) - 1;
    204 			ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
    205 					       &len, NULL);
    206 			if (ret >= 0) {
    207 				buf[len] = '\0';
    208 				pos = strchr(buf, '\n');
    209 				if (pos)
    210 					*pos = '\0';
    211 				ctrl_iface = strdup(buf);
    212 			}
    213 			wpa_ctrl_close(ctrl);
    214 		}
    215 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    216 	}
    217 
    218 	if (ctrl_iface == NULL)
    219 		return -1;
    220 
    221 #ifdef CONFIG_CTRL_IFACE_UNIX
    222 	flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
    223 	cfile = (char *) malloc(flen);
    224 	if (cfile == NULL)
    225 		return -1;
    226 	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
    227 #else /* CONFIG_CTRL_IFACE_UNIX */
    228 	flen = strlen(ctrl_iface) + 1;
    229 	cfile = (char *) malloc(flen);
    230 	if (cfile == NULL)
    231 		return -1;
    232 	snprintf(cfile, flen, "%s", ctrl_iface);
    233 #endif /* CONFIG_CTRL_IFACE_UNIX */
    234 
    235 	if (ctrl_conn) {
    236 		wpa_ctrl_close(ctrl_conn);
    237 		ctrl_conn = NULL;
    238 	}
    239 
    240 	if (monitor_conn) {
    241 		delete msgNotifier;
    242 		msgNotifier = NULL;
    243 		wpa_ctrl_detach(monitor_conn);
    244 		wpa_ctrl_close(monitor_conn);
    245 		monitor_conn = NULL;
    246 	}
    247 
    248 	printf("Trying to connect to '%s'\n", cfile);
    249 	ctrl_conn = wpa_ctrl_open(cfile);
    250 	if (ctrl_conn == NULL) {
    251 		free(cfile);
    252 		return -1;
    253 	}
    254 	monitor_conn = wpa_ctrl_open(cfile);
    255 	free(cfile);
    256 	if (monitor_conn == NULL) {
    257 		wpa_ctrl_close(ctrl_conn);
    258 		return -1;
    259 	}
    260 	if (wpa_ctrl_attach(monitor_conn)) {
    261 		printf("Failed to attach to wpa_supplicant\n");
    262 		wpa_ctrl_close(monitor_conn);
    263 		monitor_conn = NULL;
    264 		wpa_ctrl_close(ctrl_conn);
    265 		ctrl_conn = NULL;
    266 		return -1;
    267 	}
    268 
    269 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
    270 	msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
    271 					  QSocketNotifier::Read, this);
    272 	connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
    273 #endif
    274 
    275 	adapterSelect->clear();
    276 	adapterSelect->insertItem(ctrl_iface);
    277 	adapterSelect->setCurrentItem(0);
    278 
    279 	len = sizeof(buf) - 1;
    280 	if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
    281 	    0) {
    282 		buf[len] = '\0';
    283 		pos = buf;
    284 		while (*pos) {
    285 			pos2 = strchr(pos, '\n');
    286 			if (pos2)
    287 				*pos2 = '\0';
    288 			if (strcmp(pos, ctrl_iface) != 0)
    289 				adapterSelect->insertItem(pos);
    290 			if (pos2)
    291 				pos = pos2 + 1;
    292 			else
    293 				break;
    294 		}
    295 	}
    296 
    297 	return 0;
    298 }
    299 
    300 
    301 static void wpa_gui_msg_cb(char *msg, size_t)
    302 {
    303 	/* This should not happen anymore since two control connections are
    304 	 * used. */
    305 	printf("missed message: %s\n", msg);
    306 }
    307 
    308 
    309 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
    310 {
    311 	int ret;
    312 
    313 	if (ctrl_conn == NULL)
    314 		return -3;
    315 	ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
    316 			       wpa_gui_msg_cb);
    317 	if (ret == -2)
    318 		printf("'%s' command timed out.\n", cmd);
    319 	else if (ret < 0)
    320 		printf("'%s' command failed.\n", cmd);
    321 
    322 	return ret;
    323 }
    324 
    325 
    326 void WpaGui::updateStatus()
    327 {
    328 	char buf[2048], *start, *end, *pos;
    329 	size_t len;
    330 
    331 	pingsToStatusUpdate = 10;
    332 
    333 	len = sizeof(buf) - 1;
    334 	if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
    335 		textStatus->setText("Could not get status from "
    336 				    "wpa_supplicant");
    337 		textAuthentication->clear();
    338 		textEncryption->clear();
    339 		textSsid->clear();
    340 		textBssid->clear();
    341 		textIpAddress->clear();
    342 		return;
    343 	}
    344 
    345 	buf[len] = '\0';
    346 
    347 	bool auth_updated = false, ssid_updated = false;
    348 	bool bssid_updated = false, ipaddr_updated = false;
    349 	bool status_updated = false;
    350 	char *pairwise_cipher = NULL, *group_cipher = NULL;
    351 
    352 	start = buf;
    353 	while (*start) {
    354 		bool last = false;
    355 		end = strchr(start, '\n');
    356 		if (end == NULL) {
    357 			last = true;
    358 			end = start;
    359 			while (end[0] && end[1])
    360 				end++;
    361 		}
    362 		*end = '\0';
    363 
    364 		pos = strchr(start, '=');
    365 		if (pos) {
    366 			*pos++ = '\0';
    367 			if (strcmp(start, "bssid") == 0) {
    368 				bssid_updated = true;
    369 				textBssid->setText(pos);
    370 			} else if (strcmp(start, "ssid") == 0) {
    371 				ssid_updated = true;
    372 				textSsid->setText(pos);
    373 			} else if (strcmp(start, "ip_address") == 0) {
    374 				ipaddr_updated = true;
    375 				textIpAddress->setText(pos);
    376 			} else if (strcmp(start, "wpa_state") == 0) {
    377 				status_updated = true;
    378 				textStatus->setText(pos);
    379 			} else if (strcmp(start, "key_mgmt") == 0) {
    380 				auth_updated = true;
    381 				textAuthentication->setText(pos);
    382 				/* TODO: could add EAP status to this */
    383 			} else if (strcmp(start, "pairwise_cipher") == 0) {
    384 				pairwise_cipher = pos;
    385 			} else if (strcmp(start, "group_cipher") == 0) {
    386 				group_cipher = pos;
    387 			}
    388 		}
    389 
    390 		if (last)
    391 			break;
    392 		start = end + 1;
    393 	}
    394 
    395 	if (pairwise_cipher || group_cipher) {
    396 		QString encr;
    397 		if (pairwise_cipher && group_cipher &&
    398 		    strcmp(pairwise_cipher, group_cipher) != 0) {
    399 			encr.append(pairwise_cipher);
    400 			encr.append(" + ");
    401 			encr.append(group_cipher);
    402 		} else if (pairwise_cipher) {
    403 			encr.append(pairwise_cipher);
    404 		} else if (group_cipher) {
    405 			encr.append(group_cipher);
    406 			encr.append(" [group key only]");
    407 		} else {
    408 			encr.append("?");
    409 		}
    410 		textEncryption->setText(encr);
    411 	} else
    412 		textEncryption->clear();
    413 
    414 	if (!status_updated)
    415 		textStatus->clear();
    416 	if (!auth_updated)
    417 		textAuthentication->clear();
    418 	if (!ssid_updated)
    419 		textSsid->clear();
    420 	if (!bssid_updated)
    421 		textBssid->clear();
    422 	if (!ipaddr_updated)
    423 		textIpAddress->clear();
    424 }
    425 
    426 
    427 void WpaGui::updateNetworks()
    428 {
    429 	char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
    430 	size_t len;
    431 	int first_active = -1;
    432 	bool selected = false;
    433 
    434 	if (!networkMayHaveChanged)
    435 		return;
    436 
    437 	networkSelect->clear();
    438 
    439 	if (ctrl_conn == NULL)
    440 		return;
    441 
    442 	len = sizeof(buf) - 1;
    443 	if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
    444 		return;
    445 
    446 	buf[len] = '\0';
    447 	start = strchr(buf, '\n');
    448 	if (start == NULL)
    449 		return;
    450 	start++;
    451 
    452 	while (*start) {
    453 		bool last = false;
    454 		end = strchr(start, '\n');
    455 		if (end == NULL) {
    456 			last = true;
    457 			end = start;
    458 			while (end[0] && end[1])
    459 				end++;
    460 		}
    461 		*end = '\0';
    462 
    463 		id = start;
    464 		ssid = strchr(id, '\t');
    465 		if (ssid == NULL)
    466 			break;
    467 		*ssid++ = '\0';
    468 		bssid = strchr(ssid, '\t');
    469 		if (bssid == NULL)
    470 			break;
    471 		*bssid++ = '\0';
    472 		flags = strchr(bssid, '\t');
    473 		if (flags == NULL)
    474 			break;
    475 		*flags++ = '\0';
    476 
    477 		QString network(id);
    478 		network.append(": ");
    479 		network.append(ssid);
    480 		networkSelect->insertItem(network);
    481 
    482 		if (strstr(flags, "[CURRENT]")) {
    483 			networkSelect->setCurrentItem(networkSelect->count() -
    484 						      1);
    485 			selected = true;
    486 		} else if (first_active < 0 &&
    487 			   strstr(flags, "[DISABLED]") == NULL)
    488 			first_active = networkSelect->count() - 1;
    489 
    490 		if (last)
    491 			break;
    492 		start = end + 1;
    493 	}
    494 
    495 	if (!selected && first_active >= 0)
    496 		networkSelect->setCurrentItem(first_active);
    497 
    498 	networkMayHaveChanged = false;
    499 }
    500 
    501 
    502 void WpaGui::helpIndex()
    503 {
    504 	printf("helpIndex\n");
    505 }
    506 
    507 
    508 void WpaGui::helpContents()
    509 {
    510 	printf("helpContents\n");
    511 }
    512 
    513 
    514 void WpaGui::helpAbout()
    515 {
    516 	QMessageBox::about(this, "wpa_gui for wpa_supplicant",
    517 			   "Copyright (c) 2003-2008,\n"
    518 			   "Jouni Malinen <j (at) w1.fi>\n"
    519 			   "and contributors.\n"
    520 			   "\n"
    521 			   "This program is free software. You can\n"
    522 			   "distribute it and/or modify it under the terms "
    523 			   "of\n"
    524 			   "the GNU General Public License version 2.\n"
    525 			   "\n"
    526 			   "Alternatively, this software may be distributed\n"
    527 			   "under the terms of the BSD license.\n"
    528 			   "\n"
    529 			   "This product includes software developed\n"
    530 			   "by the OpenSSL Project for use in the\n"
    531 			   "OpenSSL Toolkit (http://www.openssl.org/)\n");
    532 }
    533 
    534 
    535 void WpaGui::disconnect()
    536 {
    537 	char reply[10];
    538 	size_t reply_len = sizeof(reply);
    539 	ctrlRequest("DISCONNECT", reply, &reply_len);
    540 }
    541 
    542 
    543 void WpaGui::scan()
    544 {
    545 	if (scanres) {
    546 		scanres->close();
    547 		delete scanres;
    548 	}
    549 
    550 	scanres = new ScanResults();
    551 	if (scanres == NULL)
    552 		return;
    553 	scanres->setWpaGui(this);
    554 	scanres->show();
    555 	scanres->exec();
    556 }
    557 
    558 
    559 void WpaGui::eventHistory()
    560 {
    561 	if (eh) {
    562 		eh->close();
    563 		delete eh;
    564 	}
    565 
    566 	eh = new EventHistory();
    567 	if (eh == NULL)
    568 		return;
    569 	eh->addEvents(msgs);
    570 	eh->show();
    571 	eh->exec();
    572 }
    573 
    574 
    575 void WpaGui::ping()
    576 {
    577 	char buf[10];
    578 	size_t len;
    579 
    580 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    581 	/*
    582 	 * QSocketNotifier cannot be used with Windows named pipes, so use a
    583 	 * timer to check for received messages for now. This could be
    584 	 * optimized be doing something specific to named pipes or Windows
    585 	 * events, but it is not clear what would be the best way of doing that
    586 	 * in Qt.
    587 	 */
    588 	receiveMsgs();
    589 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    590 
    591 	if (scanres && !scanres->isVisible()) {
    592 		delete scanres;
    593 		scanres = NULL;
    594 	}
    595 
    596 	if (eh && !eh->isVisible()) {
    597 		delete eh;
    598 		eh = NULL;
    599 	}
    600 
    601 	if (udr && !udr->isVisible()) {
    602 		delete udr;
    603 		udr = NULL;
    604 	}
    605 
    606 	len = sizeof(buf) - 1;
    607 	if (ctrlRequest("PING", buf, &len) < 0) {
    608 		printf("PING failed - trying to reconnect\n");
    609 		if (openCtrlConnection(ctrl_iface) >= 0) {
    610 			printf("Reconnected successfully\n");
    611 			pingsToStatusUpdate = 0;
    612 		}
    613 	}
    614 
    615 	pingsToStatusUpdate--;
    616 	if (pingsToStatusUpdate <= 0) {
    617 		updateStatus();
    618 		updateNetworks();
    619 	}
    620 }
    621 
    622 
    623 static int str_match(const char *a, const char *b)
    624 {
    625 	return strncmp(a, b, strlen(b)) == 0;
    626 }
    627 
    628 
    629 void WpaGui::processMsg(char *msg)
    630 {
    631 	char *pos = msg, *pos2;
    632 	int priority = 2;
    633 
    634 	if (*pos == '<') {
    635 		/* skip priority */
    636 		pos++;
    637 		priority = atoi(pos);
    638 		pos = strchr(pos, '>');
    639 		if (pos)
    640 			pos++;
    641 		else
    642 			pos = msg;
    643 	}
    644 
    645 	WpaMsg wm(pos, priority);
    646 	if (eh)
    647 		eh->addEvent(wm);
    648 	msgs.append(wm);
    649 	while (msgs.count() > 100)
    650 		msgs.pop_front();
    651 
    652 	/* Update last message with truncated version of the event */
    653 	if (strncmp(pos, "CTRL-", 5) == 0) {
    654 		pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
    655 		if (pos2)
    656 			pos2++;
    657 		else
    658 			pos2 = pos;
    659 	} else
    660 		pos2 = pos;
    661 	QString lastmsg = pos2;
    662 	lastmsg.truncate(40);
    663 	textLastMessage->setText(lastmsg);
    664 
    665 	pingsToStatusUpdate = 0;
    666 	networkMayHaveChanged = true;
    667 
    668 	if (str_match(pos, WPA_CTRL_REQ))
    669 		processCtrlReq(pos + strlen(WPA_CTRL_REQ));
    670 }
    671 
    672 
    673 void WpaGui::processCtrlReq(const char *req)
    674 {
    675 	if (udr) {
    676 		udr->close();
    677 		delete udr;
    678 	}
    679 	udr = new UserDataRequest();
    680 	if (udr == NULL)
    681 		return;
    682 	if (udr->setParams(this, req) < 0) {
    683 		delete udr;
    684 		udr = NULL;
    685 		return;
    686 	}
    687 	udr->show();
    688 	udr->exec();
    689 }
    690 
    691 
    692 void WpaGui::receiveMsgs()
    693 {
    694 	char buf[256];
    695 	size_t len;
    696 
    697 	while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
    698 		len = sizeof(buf) - 1;
    699 		if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
    700 			buf[len] = '\0';
    701 			processMsg(buf);
    702 		}
    703 	}
    704 }
    705 
    706 
    707 void WpaGui::connectB()
    708 {
    709 	char reply[10];
    710 	size_t reply_len = sizeof(reply);
    711 	ctrlRequest("REASSOCIATE", reply, &reply_len);
    712 }
    713 
    714 
    715 void WpaGui::selectNetwork( const QString &sel )
    716 {
    717 	QString cmd(sel);
    718 	char reply[10];
    719 	size_t reply_len = sizeof(reply);
    720 
    721 	int pos = cmd.find(':');
    722 	if (pos < 0) {
    723 		printf("Invalid selectNetwork '%s'\n", cmd.ascii());
    724 		return;
    725 	}
    726 	cmd.truncate(pos);
    727 	cmd.prepend("SELECT_NETWORK ");
    728 	ctrlRequest(cmd.ascii(), reply, &reply_len);
    729 }
    730 
    731 
    732 void WpaGui::editNetwork()
    733 {
    734 	QString sel(networkSelect->currentText());
    735 	int pos = sel.find(':');
    736 	if (pos < 0) {
    737 		printf("Invalid selectNetwork '%s'\n", sel.ascii());
    738 		return;
    739 	}
    740 	sel.truncate(pos);
    741 
    742 	NetworkConfig *nc = new NetworkConfig();
    743 	if (nc == NULL)
    744 		return;
    745 	nc->setWpaGui(this);
    746 
    747 	nc->paramsFromConfig(sel.toInt());
    748 	nc->show();
    749 	nc->exec();
    750 }
    751 
    752 
    753 void WpaGui::triggerUpdate()
    754 {
    755 	updateStatus();
    756 	networkMayHaveChanged = true;
    757 	updateNetworks();
    758 }
    759 
    760 
    761 void WpaGui::addNetwork()
    762 {
    763 	NetworkConfig *nc = new NetworkConfig();
    764 	if (nc == NULL)
    765 		return;
    766 	nc->setWpaGui(this);
    767 	nc->newNetwork();
    768 	nc->show();
    769 	nc->exec();
    770 }
    771 
    772 
    773 void WpaGui::selectAdapter( const QString & sel )
    774 {
    775 	if (openCtrlConnection(sel.ascii()) < 0)
    776 		printf("Failed to open control connection to "
    777 		       "wpa_supplicant.\n");
    778 	updateStatus();
    779 	updateNetworks();
    780 }
    781