Home | History | Annotate | Download | only in wpa_gui-qt4
      1 /*
      2  * wpa_gui - Peers class
      3  * Copyright (c) 2009-2010, Atheros Communications
      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 #include <cstdio>
     16 #include <QImageReader>
     17 #include <QMessageBox>
     18 
     19 #include "common/wpa_ctrl.h"
     20 #include "wpagui.h"
     21 #include "stringquery.h"
     22 #include "peers.h"
     23 
     24 
     25 enum {
     26 	peer_role_address = Qt::UserRole + 1,
     27 	peer_role_type,
     28 	peer_role_uuid,
     29 	peer_role_details,
     30 	peer_role_ifname,
     31 	peer_role_pri_dev_type,
     32 	peer_role_ssid,
     33 	peer_role_config_methods,
     34 	peer_role_dev_passwd_id,
     35 	peer_role_bss_id,
     36 	peer_role_selected_method,
     37 	peer_role_selected_pin,
     38 	peer_role_requested_method,
     39 	peer_role_network_id
     40 };
     41 
     42 enum selected_method {
     43 	SEL_METHOD_NONE,
     44 	SEL_METHOD_PIN_PEER_DISPLAY,
     45 	SEL_METHOD_PIN_LOCAL_DISPLAY
     46 };
     47 
     48 /*
     49  * TODO:
     50  * - add current AP info (e.g., from WPS) in station mode
     51  */
     52 
     53 enum peer_type {
     54 	PEER_TYPE_ASSOCIATED_STATION,
     55 	PEER_TYPE_AP,
     56 	PEER_TYPE_AP_WPS,
     57 	PEER_TYPE_WPS_PIN_NEEDED,
     58 	PEER_TYPE_P2P,
     59 	PEER_TYPE_P2P_CLIENT,
     60 	PEER_TYPE_P2P_GROUP,
     61 	PEER_TYPE_P2P_PERSISTENT_GROUP_GO,
     62 	PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT,
     63 	PEER_TYPE_P2P_INVITATION,
     64 	PEER_TYPE_WPS_ER_AP,
     65 	PEER_TYPE_WPS_ER_AP_UNCONFIGURED,
     66 	PEER_TYPE_WPS_ER_ENROLLEE,
     67 	PEER_TYPE_WPS_ENROLLEE
     68 };
     69 
     70 
     71 Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags)
     72 	: QDialog(parent)
     73 {
     74 	setupUi(this);
     75 
     76 	if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
     77 	{
     78 		default_icon = new QIcon(":/icons/wpa_gui.svg");
     79 		ap_icon = new QIcon(":/icons/ap.svg");
     80 		laptop_icon = new QIcon(":/icons/laptop.svg");
     81 		group_icon = new QIcon(":/icons/group.svg");
     82 		invitation_icon = new QIcon(":/icons/invitation.svg");
     83 	} else {
     84 		default_icon = new QIcon(":/icons/wpa_gui.png");
     85 		ap_icon = new QIcon(":/icons/ap.png");
     86 		laptop_icon = new QIcon(":/icons/laptop.png");
     87 		group_icon = new QIcon(":/icons/group.png");
     88 		invitation_icon = new QIcon(":/icons/invitation.png");
     89 	}
     90 
     91 	peers->setModel(&model);
     92 	peers->setResizeMode(QListView::Adjust);
     93 	peers->setDragEnabled(false);
     94 	peers->setSelectionMode(QAbstractItemView::NoSelection);
     95 
     96 	peers->setContextMenuPolicy(Qt::CustomContextMenu);
     97 	connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)),
     98 		this, SLOT(context_menu(const QPoint &)));
     99 
    100 	wpagui = NULL;
    101 	hide_ap = false;
    102 }
    103 
    104 
    105 void Peers::setWpaGui(WpaGui *_wpagui)
    106 {
    107 	wpagui = _wpagui;
    108 	update_peers();
    109 }
    110 
    111 
    112 Peers::~Peers()
    113 {
    114 	delete default_icon;
    115 	delete ap_icon;
    116 	delete laptop_icon;
    117 	delete group_icon;
    118 	delete invitation_icon;
    119 }
    120 
    121 
    122 void Peers::languageChange()
    123 {
    124 	retranslateUi(this);
    125 }
    126 
    127 
    128 QString Peers::ItemType(int type)
    129 {
    130 	QString title;
    131 	switch (type) {
    132 	case PEER_TYPE_ASSOCIATED_STATION:
    133 		title = tr("Associated station");
    134 		break;
    135 	case PEER_TYPE_AP:
    136 		title = tr("AP");
    137 		break;
    138 	case PEER_TYPE_AP_WPS:
    139 		title = tr("WPS AP");
    140 		break;
    141 	case PEER_TYPE_WPS_PIN_NEEDED:
    142 		title = tr("WPS PIN needed");
    143 		break;
    144 	case PEER_TYPE_P2P:
    145 		title = tr("P2P Device");
    146 		break;
    147 	case PEER_TYPE_P2P_CLIENT:
    148 		title = tr("P2P Device (group client)");
    149 		break;
    150 	case PEER_TYPE_P2P_GROUP:
    151 		title = tr("P2P Group");
    152 		break;
    153 	case PEER_TYPE_P2P_PERSISTENT_GROUP_GO:
    154 		title = tr("P2P Persistent Group (GO)");
    155 		break;
    156 	case PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT:
    157 		title = tr("P2P Persistent Group (client)");
    158 		break;
    159 	case PEER_TYPE_P2P_INVITATION:
    160 		title = tr("P2P Invitation");
    161 		break;
    162 	case PEER_TYPE_WPS_ER_AP:
    163 		title = tr("ER: WPS AP");
    164 		break;
    165 	case PEER_TYPE_WPS_ER_AP_UNCONFIGURED:
    166 		title = tr("ER: WPS AP (Unconfigured)");
    167 		break;
    168 	case PEER_TYPE_WPS_ER_ENROLLEE:
    169 		title = tr("ER: WPS Enrollee");
    170 		break;
    171 	case PEER_TYPE_WPS_ENROLLEE:
    172 		title = tr("WPS Enrollee");
    173 		break;
    174 	}
    175 	return title;
    176 }
    177 
    178 
    179 void Peers::context_menu(const QPoint &pos)
    180 {
    181 	QMenu *menu = new QMenu;
    182 	if (menu == NULL)
    183 		return;
    184 
    185 	QModelIndex idx = peers->indexAt(pos);
    186 	if (idx.isValid()) {
    187 		ctx_item = model.itemFromIndex(idx);
    188 		int type = ctx_item->data(peer_role_type).toInt();
    189 		menu->addAction(Peers::ItemType(type))->setEnabled(false);
    190 		menu->addSeparator();
    191 
    192 		int config_methods = -1;
    193 		QVariant var = ctx_item->data(peer_role_config_methods);
    194 		if (var.isValid())
    195 			config_methods = var.toInt();
    196 
    197 		enum selected_method method = SEL_METHOD_NONE;
    198 		var = ctx_item->data(peer_role_selected_method);
    199 		if (var.isValid())
    200 			method = (enum selected_method) var.toInt();
    201 
    202 		if ((type == PEER_TYPE_ASSOCIATED_STATION ||
    203 		     type == PEER_TYPE_AP_WPS ||
    204 		     type == PEER_TYPE_WPS_PIN_NEEDED ||
    205 		     type == PEER_TYPE_WPS_ER_ENROLLEE ||
    206 		     type == PEER_TYPE_WPS_ENROLLEE) &&
    207 		    (config_methods == -1 || (config_methods & 0x010c))) {
    208 			menu->addAction(tr("Enter WPS PIN"), this,
    209 					SLOT(enter_pin()));
    210 		}
    211 
    212 		if (type == PEER_TYPE_P2P || type == PEER_TYPE_P2P_CLIENT) {
    213 			menu->addAction(tr("P2P Connect"), this,
    214 					SLOT(ctx_p2p_connect()));
    215 			if (method == SEL_METHOD_NONE &&
    216 			    config_methods > -1 &&
    217 			    config_methods & 0x0080 /* PBC */ &&
    218 			    config_methods != 0x0080)
    219 				menu->addAction(tr("P2P Connect (PBC)"), this,
    220 						SLOT(connect_pbc()));
    221 			if (method == SEL_METHOD_NONE) {
    222 				menu->addAction(tr("P2P Request PIN"), this,
    223 						SLOT(ctx_p2p_req_pin()));
    224 				menu->addAction(tr("P2P Show PIN"), this,
    225 						SLOT(ctx_p2p_show_pin()));
    226 			}
    227 
    228 			if (config_methods > -1 && (config_methods & 0x0100)) {
    229 				/* Peer has Keypad */
    230 				menu->addAction(tr("P2P Display PIN"), this,
    231 						SLOT(ctx_p2p_display_pin()));
    232 			}
    233 
    234 			if (config_methods > -1 && (config_methods & 0x000c)) {
    235 				/* Peer has Label or Display */
    236 				menu->addAction(tr("P2P Enter PIN"), this,
    237 						SLOT(ctx_p2p_enter_pin()));
    238 			}
    239 		}
    240 
    241 		if (type == PEER_TYPE_P2P_GROUP) {
    242 			menu->addAction(tr("Show passphrase"), this,
    243 					SLOT(ctx_p2p_show_passphrase()));
    244 			menu->addAction(tr("Remove P2P Group"), this,
    245 					SLOT(ctx_p2p_remove_group()));
    246 		}
    247 
    248 		if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
    249 		    type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT ||
    250 		    type == PEER_TYPE_P2P_INVITATION) {
    251 			menu->addAction(tr("Start group"), this,
    252 					SLOT(ctx_p2p_start_persistent()));
    253 		}
    254 
    255 		if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
    256 		    type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) {
    257 			menu->addAction(tr("Invite"), this,
    258 					SLOT(ctx_p2p_invite()));
    259 		}
    260 
    261 		if (type == PEER_TYPE_P2P_INVITATION) {
    262 			menu->addAction(tr("Ignore"), this,
    263 					SLOT(ctx_p2p_delete()));
    264 		}
    265 
    266 		if (type == PEER_TYPE_AP_WPS) {
    267 			menu->addAction(tr("Connect (PBC)"), this,
    268 					SLOT(connect_pbc()));
    269 		}
    270 
    271 		if ((type == PEER_TYPE_ASSOCIATED_STATION ||
    272 		     type == PEER_TYPE_WPS_ER_ENROLLEE ||
    273 		     type == PEER_TYPE_WPS_ENROLLEE) &&
    274 		    config_methods >= 0 && (config_methods & 0x0080)) {
    275 			menu->addAction(tr("Enroll (PBC)"), this,
    276 					SLOT(connect_pbc()));
    277 		}
    278 
    279 		if (type == PEER_TYPE_WPS_ER_AP) {
    280 			menu->addAction(tr("Learn Configuration"), this,
    281 					SLOT(learn_ap_config()));
    282 		}
    283 
    284 		menu->addAction(tr("Properties"), this, SLOT(properties()));
    285 	} else {
    286 		ctx_item = NULL;
    287 		menu->addAction(QString(tr("Refresh")), this,
    288 				SLOT(ctx_refresh()));
    289 		menu->addAction(tr("Start P2P discovery"), this,
    290 				SLOT(ctx_p2p_start()));
    291 		menu->addAction(tr("Stop P2P discovery"), this,
    292 				SLOT(ctx_p2p_stop()));
    293 		menu->addAction(tr("P2P listen only"), this,
    294 				SLOT(ctx_p2p_listen()));
    295 		menu->addAction(tr("Start P2P group"), this,
    296 				SLOT(ctx_p2p_start_group()));
    297 		if (hide_ap)
    298 			menu->addAction(tr("Show AP entries"), this,
    299 					SLOT(ctx_show_ap()));
    300 		else
    301 			menu->addAction(tr("Hide AP entries"), this,
    302 					SLOT(ctx_hide_ap()));
    303 	}
    304 
    305 	menu->exec(peers->mapToGlobal(pos));
    306 }
    307 
    308 
    309 void Peers::enter_pin()
    310 {
    311 	if (ctx_item == NULL)
    312 		return;
    313 
    314 	int peer_type = ctx_item->data(peer_role_type).toInt();
    315 	QString uuid;
    316 	QString addr;
    317 	addr = ctx_item->data(peer_role_address).toString();
    318 	if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE)
    319 		uuid = ctx_item->data(peer_role_uuid).toString();
    320 
    321 	StringQuery input(tr("PIN:"));
    322 	input.setWindowTitle(tr("PIN for ") + ctx_item->text());
    323 	if (input.exec() != QDialog::Accepted)
    324 		return;
    325 
    326 	char cmd[100];
    327 	char reply[100];
    328 	size_t reply_len;
    329 
    330 	if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
    331 		snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
    332 			 uuid.toAscii().constData(),
    333 			 input.get_string().toAscii().constData(),
    334 			 addr.toAscii().constData());
    335 	} else {
    336 		snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
    337 			 addr.toAscii().constData(),
    338 			 input.get_string().toAscii().constData());
    339 	}
    340 	reply_len = sizeof(reply) - 1;
    341 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
    342 		QMessageBox msg;
    343 		msg.setIcon(QMessageBox::Warning);
    344 		msg.setText(tr("Failed to set the WPS PIN."));
    345 		msg.exec();
    346 	}
    347 }
    348 
    349 
    350 void Peers::ctx_refresh()
    351 {
    352 	update_peers();
    353 }
    354 
    355 
    356 void Peers::ctx_p2p_start()
    357 {
    358 	char reply[20];
    359 	size_t reply_len;
    360 	reply_len = sizeof(reply) - 1;
    361 	if (wpagui->ctrlRequest("P2P_FIND", reply, &reply_len) < 0 ||
    362 	    memcmp(reply, "FAIL", 4) == 0) {
    363 		QMessageBox msg;
    364 		msg.setIcon(QMessageBox::Warning);
    365 		msg.setText("Failed to start P2P discovery.");
    366 		msg.exec();
    367 	}
    368 }
    369 
    370 
    371 void Peers::ctx_p2p_stop()
    372 {
    373 	char reply[20];
    374 	size_t reply_len;
    375 	reply_len = sizeof(reply) - 1;
    376 	wpagui->ctrlRequest("P2P_STOP_FIND", reply, &reply_len);
    377 }
    378 
    379 
    380 void Peers::ctx_p2p_listen()
    381 {
    382 	char reply[20];
    383 	size_t reply_len;
    384 	reply_len = sizeof(reply) - 1;
    385 	if (wpagui->ctrlRequest("P2P_LISTEN 3600", reply, &reply_len) < 0 ||
    386 	    memcmp(reply, "FAIL", 4) == 0) {
    387 		QMessageBox msg;
    388 		msg.setIcon(QMessageBox::Warning);
    389 		msg.setText("Failed to start P2P listen.");
    390 		msg.exec();
    391 	}
    392 }
    393 
    394 
    395 void Peers::ctx_p2p_start_group()
    396 {
    397 	char reply[20];
    398 	size_t reply_len;
    399 	reply_len = sizeof(reply) - 1;
    400 	if (wpagui->ctrlRequest("P2P_GROUP_ADD", reply, &reply_len) < 0 ||
    401 	    memcmp(reply, "FAIL", 4) == 0) {
    402 		QMessageBox msg;
    403 		msg.setIcon(QMessageBox::Warning);
    404 		msg.setText("Failed to start P2P group.");
    405 		msg.exec();
    406 	}
    407 }
    408 
    409 
    410 void Peers::add_station(QString info)
    411 {
    412 	QStringList lines = info.split(QRegExp("\\n"));
    413 	QString name;
    414 
    415 	for (QStringList::Iterator it = lines.begin();
    416 	     it != lines.end(); it++) {
    417 		int pos = (*it).indexOf('=') + 1;
    418 		if (pos < 1)
    419 			continue;
    420 
    421 		if ((*it).startsWith("wpsDeviceName="))
    422 			name = (*it).mid(pos);
    423 		else if ((*it).startsWith("p2p_device_name="))
    424 			name = (*it).mid(pos);
    425 	}
    426 
    427 	if (name.isEmpty())
    428 		name = lines[0];
    429 
    430 	QStandardItem *item = new QStandardItem(*laptop_icon, name);
    431 	if (item) {
    432 		/* Remove WPS enrollee entry if one is still pending */
    433 		if (model.rowCount() > 0) {
    434 			QModelIndexList lst = model.match(model.index(0, 0),
    435 							  peer_role_address,
    436 							  lines[0]);
    437 			for (int i = 0; i < lst.size(); i++) {
    438 				QStandardItem *item;
    439 				item = model.itemFromIndex(lst[i]);
    440 				if (item == NULL)
    441 					continue;
    442 				int type = item->data(peer_role_type).toInt();
    443 				if (type == PEER_TYPE_WPS_ENROLLEE) {
    444 					model.removeRow(lst[i].row());
    445 					break;
    446 				}
    447 			}
    448 		}
    449 
    450 		item->setData(lines[0], peer_role_address);
    451 		item->setData(PEER_TYPE_ASSOCIATED_STATION,
    452 			      peer_role_type);
    453 		item->setData(info, peer_role_details);
    454 		item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION));
    455 		model.appendRow(item);
    456 	}
    457 }
    458 
    459 
    460 void Peers::add_stations()
    461 {
    462 	char reply[2048];
    463 	size_t reply_len;
    464 	char cmd[30];
    465 	int res;
    466 
    467 	reply_len = sizeof(reply) - 1;
    468 	if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0)
    469 		return;
    470 
    471 	do {
    472 		reply[reply_len] = '\0';
    473 		QString info(reply);
    474 		char *txt = reply;
    475 		while (*txt != '\0' && *txt != '\n')
    476 			txt++;
    477 		*txt++ = '\0';
    478 		if (strncmp(reply, "FAIL", 4) == 0 ||
    479 		    strncmp(reply, "UNKNOWN", 7) == 0)
    480 			break;
    481 
    482 		add_station(info);
    483 
    484 		reply_len = sizeof(reply) - 1;
    485 		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
    486 		res = wpagui->ctrlRequest(cmd, reply, &reply_len);
    487 	} while (res >= 0);
    488 }
    489 
    490 
    491 void Peers::add_single_station(const char *addr)
    492 {
    493 	char reply[2048];
    494 	size_t reply_len;
    495 	char cmd[30];
    496 
    497 	reply_len = sizeof(reply) - 1;
    498 	snprintf(cmd, sizeof(cmd), "STA %s", addr);
    499 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
    500 		return;
    501 
    502 	reply[reply_len] = '\0';
    503 	QString info(reply);
    504 	char *txt = reply;
    505 	while (*txt != '\0' && *txt != '\n')
    506 		txt++;
    507 	*txt++ = '\0';
    508 	if (strncmp(reply, "FAIL", 4) == 0 ||
    509 	    strncmp(reply, "UNKNOWN", 7) == 0)
    510 		return;
    511 
    512 	add_station(info);
    513 }
    514 
    515 
    516 void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params)
    517 {
    518 	/*
    519 	 * dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0
    520 	 * dev_type=1-0050f204-1 dev_name='Wireless Client'
    521 	 * config_methods=0x8c
    522 	 */
    523 
    524 	QStringList items =
    525 		params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
    526 	QString addr = "";
    527 	QString name = "";
    528 	int config_methods = 0;
    529 	QString dev_type;
    530 
    531 	for (int i = 0; i < items.size(); i++) {
    532 		QString str = items.at(i);
    533 		int pos = str.indexOf('=') + 1;
    534 		if (str.startsWith("dev_name='"))
    535 			name = str.section('\'', 1, -2);
    536 		else if (str.startsWith("config_methods="))
    537 			config_methods =
    538 				str.section('=', 1).toInt(0, 0);
    539 		else if (str.startsWith("dev="))
    540 			addr = str.mid(pos);
    541 		else if (str.startsWith("dev_type=") && dev_type.isEmpty())
    542 			dev_type = str.mid(pos);
    543 	}
    544 
    545 	QStandardItem *item = find_addr(addr);
    546 	if (item)
    547 		return;
    548 
    549 	item = new QStandardItem(*default_icon, name);
    550 	if (item) {
    551 		/* TODO: indicate somehow the relationship to the group owner
    552 		 * (parent) */
    553 		item->setData(addr, peer_role_address);
    554 		item->setData(config_methods, peer_role_config_methods);
    555 		item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type);
    556 		if (!dev_type.isEmpty())
    557 			item->setData(dev_type, peer_role_pri_dev_type);
    558 		item->setData(items.join(QString("\n")), peer_role_details);
    559 		item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT));
    560 		model.appendRow(item);
    561 	}
    562 }
    563 
    564 
    565 void Peers::remove_bss(int id)
    566 {
    567 	if (model.rowCount() == 0)
    568 		return;
    569 
    570 	QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id,
    571 					  id);
    572 	if (lst.size() == 0)
    573 		return;
    574 	model.removeRow(lst[0].row());
    575 }
    576 
    577 
    578 bool Peers::add_bss(const char *cmd)
    579 {
    580 	char reply[2048];
    581 	size_t reply_len;
    582 
    583 	if (hide_ap)
    584 		return false;
    585 
    586 	reply_len = sizeof(reply) - 1;
    587 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
    588 		return false;
    589 	reply[reply_len] = '\0';
    590 
    591 	QString bss(reply);
    592 	if (bss.isEmpty() || bss.startsWith("FAIL"))
    593 		return false;
    594 
    595 	QString ssid, bssid, flags, wps_name, pri_dev_type;
    596 	int id = -1;
    597 
    598 	QStringList lines = bss.split(QRegExp("\\n"));
    599 	for (QStringList::Iterator it = lines.begin();
    600 	     it != lines.end(); it++) {
    601 		int pos = (*it).indexOf('=') + 1;
    602 		if (pos < 1)
    603 			continue;
    604 
    605 		if ((*it).startsWith("bssid="))
    606 			bssid = (*it).mid(pos);
    607 		else if ((*it).startsWith("id="))
    608 			id = (*it).mid(pos).toInt();
    609 		else if ((*it).startsWith("flags="))
    610 			flags = (*it).mid(pos);
    611 		else if ((*it).startsWith("ssid="))
    612 			ssid = (*it).mid(pos);
    613 		else if ((*it).startsWith("wps_device_name="))
    614 			wps_name = (*it).mid(pos);
    615 		else if ((*it).startsWith("wps_primary_device_type="))
    616 			pri_dev_type = (*it).mid(pos);
    617 	}
    618 
    619 	QString name = wps_name;
    620 	if (name.isEmpty())
    621 		name = ssid + "\n" + bssid;
    622 
    623 	QStandardItem *item = new QStandardItem(*ap_icon, name);
    624 	if (item) {
    625 		item->setData(bssid, peer_role_address);
    626 		if (id >= 0)
    627 			item->setData(id, peer_role_bss_id);
    628 		int type;
    629 		if (flags.contains("[WPS"))
    630 			type = PEER_TYPE_AP_WPS;
    631 		else
    632 			type = PEER_TYPE_AP;
    633 		item->setData(type, peer_role_type);
    634 
    635 		for (int i = 0; i < lines.size(); i++) {
    636 			if (lines[i].length() > 60) {
    637 				lines[i].remove(60, lines[i].length());
    638 				lines[i] += "..";
    639 			}
    640 		}
    641 		item->setToolTip(ItemType(type));
    642 		item->setData(lines.join("\n"), peer_role_details);
    643 		if (!pri_dev_type.isEmpty())
    644 			item->setData(pri_dev_type,
    645 				      peer_role_pri_dev_type);
    646 		if (!ssid.isEmpty())
    647 			item->setData(ssid, peer_role_ssid);
    648 		model.appendRow(item);
    649 
    650 		lines = bss.split(QRegExp("\\n"));
    651 		for (QStringList::Iterator it = lines.begin();
    652 		     it != lines.end(); it++) {
    653 			if ((*it).startsWith("p2p_group_client:"))
    654 				add_p2p_group_client(item,
    655 						     (*it).mid(18));
    656 		}
    657 	}
    658 
    659 	return true;
    660 }
    661 
    662 
    663 void Peers::add_scan_results()
    664 {
    665 	int index;
    666 	char cmd[20];
    667 
    668 	index = 0;
    669 	while (wpagui) {
    670 		snprintf(cmd, sizeof(cmd), "BSS %d", index++);
    671 		if (index > 1000)
    672 			break;
    673 
    674 		if (!add_bss(cmd))
    675 			break;
    676 	}
    677 }
    678 
    679 
    680 void Peers::add_persistent(int id, const char *ssid, const char *bssid)
    681 {
    682 	char cmd[100];
    683 	char reply[100];
    684 	size_t reply_len;
    685 	int mode;
    686 
    687 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id);
    688 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
    689 		return;
    690 	reply[reply_len] = '\0';
    691 	mode = atoi(reply);
    692 
    693 	QString name = ssid;
    694 	name = '[' + name + ']';
    695 
    696 	QStandardItem *item = new QStandardItem(*group_icon, name);
    697 	if (!item)
    698 		return;
    699 
    700 	int type;
    701 	if (mode == 3)
    702 		type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO;
    703 	else
    704 		type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT;
    705 	item->setData(type, peer_role_type);
    706 	item->setToolTip(ItemType(type));
    707 	item->setData(ssid, peer_role_ssid);
    708 	if (bssid && strcmp(bssid, "any") == 0)
    709 		bssid = NULL;
    710 	if (bssid)
    711 		item->setData(bssid, peer_role_address);
    712 	item->setData(id, peer_role_network_id);
    713 	item->setBackground(Qt::BDiagPattern);
    714 
    715 	model.appendRow(item);
    716 }
    717 
    718 
    719 void Peers::add_persistent_groups()
    720 {
    721 	char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
    722 	size_t len;
    723 
    724 	len = sizeof(buf) - 1;
    725 	if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
    726 		return;
    727 
    728 	buf[len] = '\0';
    729 	start = strchr(buf, '\n');
    730 	if (start == NULL)
    731 		return;
    732 	start++;
    733 
    734 	while (*start) {
    735 		bool last = false;
    736 		end = strchr(start, '\n');
    737 		if (end == NULL) {
    738 			last = true;
    739 			end = start;
    740 			while (end[0] && end[1])
    741 				end++;
    742 		}
    743 		*end = '\0';
    744 
    745 		id = start;
    746 		ssid = strchr(id, '\t');
    747 		if (ssid == NULL)
    748 			break;
    749 		*ssid++ = '\0';
    750 		bssid = strchr(ssid, '\t');
    751 		if (bssid == NULL)
    752 			break;
    753 		*bssid++ = '\0';
    754 		flags = strchr(bssid, '\t');
    755 		if (flags == NULL)
    756 			break;
    757 		*flags++ = '\0';
    758 
    759 		if (strstr(flags, "[DISABLED][P2P-PERSISTENT]"))
    760 			add_persistent(atoi(id), ssid, bssid);
    761 
    762 		if (last)
    763 			break;
    764 		start = end + 1;
    765 	}
    766 }
    767 
    768 
    769 void Peers::update_peers()
    770 {
    771 	model.clear();
    772 	if (wpagui == NULL)
    773 		return;
    774 
    775 	char reply[20];
    776 	size_t replylen = sizeof(reply) - 1;
    777 	wpagui->ctrlRequest("WPS_ER_START", reply, &replylen);
    778 
    779 	add_stations();
    780 	add_scan_results();
    781 	add_persistent_groups();
    782 }
    783 
    784 
    785 QStandardItem * Peers::find_addr(QString addr)
    786 {
    787 	if (model.rowCount() == 0)
    788 		return NULL;
    789 
    790 	QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
    791 					  addr);
    792 	if (lst.size() == 0)
    793 		return NULL;
    794 	return model.itemFromIndex(lst[0]);
    795 }
    796 
    797 
    798 QStandardItem * Peers::find_addr_type(QString addr, int type)
    799 {
    800 	if (model.rowCount() == 0)
    801 		return NULL;
    802 
    803 	QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
    804 					  addr);
    805 	for (int i = 0; i < lst.size(); i++) {
    806 		QStandardItem *item = model.itemFromIndex(lst[i]);
    807 		if (item->data(peer_role_type).toInt() == type)
    808 			return item;
    809 	}
    810 	return NULL;
    811 }
    812 
    813 
    814 QStandardItem * Peers::find_uuid(QString uuid)
    815 {
    816 	if (model.rowCount() == 0)
    817 		return NULL;
    818 
    819 	QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid,
    820 					  uuid);
    821 	if (lst.size() == 0)
    822 		return NULL;
    823 	return model.itemFromIndex(lst[0]);
    824 }
    825 
    826 
    827 void Peers::event_notify(WpaMsg msg)
    828 {
    829 	QString text = msg.getMsg();
    830 
    831 	if (text.startsWith(WPS_EVENT_PIN_NEEDED)) {
    832 		/*
    833 		 * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7
    834 		 * 02:2a:c4:18:5b:f3
    835 		 * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
    836 		 */
    837 		QStringList items = text.split(' ');
    838 		QString uuid = items[1];
    839 		QString addr = items[2];
    840 		QString name = "";
    841 
    842 		QStandardItem *item = find_addr(addr);
    843 		if (item)
    844 			return;
    845 
    846 		int pos = text.indexOf('[');
    847 		if (pos >= 0) {
    848 			int pos2 = text.lastIndexOf(']');
    849 			if (pos2 >= pos) {
    850 				items = text.mid(pos + 1, pos2 - pos - 1).
    851 					split('|');
    852 				name = items[0];
    853 				items.append(addr);
    854 			}
    855 		}
    856 
    857 		item = new QStandardItem(*laptop_icon, name);
    858 		if (item) {
    859 			item->setData(addr, peer_role_address);
    860 			item->setData(PEER_TYPE_WPS_PIN_NEEDED,
    861 				      peer_role_type);
    862 			item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED));
    863 			item->setData(items.join("\n"), peer_role_details);
    864 			item->setData(items[5], peer_role_pri_dev_type);
    865 			model.appendRow(item);
    866 		}
    867 		return;
    868 	}
    869 
    870 	if (text.startsWith(AP_STA_CONNECTED)) {
    871 		/* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */
    872 		QStringList items = text.split(' ');
    873 		QString addr = items[1];
    874 		QStandardItem *item = find_addr(addr);
    875 		if (item == NULL || item->data(peer_role_type).toInt() !=
    876 		    PEER_TYPE_ASSOCIATED_STATION)
    877 			add_single_station(addr.toAscii().constData());
    878 		return;
    879 	}
    880 
    881 	if (text.startsWith(AP_STA_DISCONNECTED)) {
    882 		/* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */
    883 		QStringList items = text.split(' ');
    884 		QString addr = items[1];
    885 
    886 		if (model.rowCount() == 0)
    887 			return;
    888 
    889 		QModelIndexList lst = model.match(model.index(0, 0),
    890 						  peer_role_address, addr, -1);
    891 		for (int i = 0; i < lst.size(); i++) {
    892 			QStandardItem *item = model.itemFromIndex(lst[i]);
    893 			if (item && item->data(peer_role_type).toInt() ==
    894 			    PEER_TYPE_ASSOCIATED_STATION) {
    895 				model.removeRow(lst[i].row());
    896 				break;
    897 			}
    898 		}
    899 		return;
    900 	}
    901 
    902 	if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) {
    903 		/*
    904 		 * P2P-DEVICE-FOUND 02:b5:64:63:30:63
    905 		 * p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1
    906 		 * name='Wireless Client' config_methods=0x84 dev_capab=0x21
    907 		 * group_capab=0x0
    908 		 */
    909 		QStringList items =
    910 			text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
    911 		QString addr = items[1];
    912 		QString name = "";
    913 		QString pri_dev_type;
    914 		int config_methods = 0;
    915 		for (int i = 0; i < items.size(); i++) {
    916 			QString str = items.at(i);
    917 			if (str.startsWith("name='"))
    918 				name = str.section('\'', 1, -2);
    919 			else if (str.startsWith("config_methods="))
    920 				config_methods =
    921 					str.section('=', 1).toInt(0, 0);
    922 			else if (str.startsWith("pri_dev_type="))
    923 				pri_dev_type = str.section('=', 1);
    924 		}
    925 
    926 		QStandardItem *item = find_addr(addr);
    927 		if (item) {
    928 			int type = item->data(peer_role_type).toInt();
    929 			if (type == PEER_TYPE_P2P)
    930 				return;
    931 		}
    932 
    933 		item = new QStandardItem(*default_icon, name);
    934 		if (item) {
    935 			item->setData(addr, peer_role_address);
    936 			item->setData(config_methods,
    937 				      peer_role_config_methods);
    938 			item->setData(PEER_TYPE_P2P, peer_role_type);
    939 			if (!pri_dev_type.isEmpty())
    940 				item->setData(pri_dev_type,
    941 					      peer_role_pri_dev_type);
    942 			item->setData(items.join(QString("\n")),
    943 				      peer_role_details);
    944 			item->setToolTip(ItemType(PEER_TYPE_P2P));
    945 			model.appendRow(item);
    946 		}
    947 
    948 		item = find_addr_type(addr,
    949 				      PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT);
    950 		if (item)
    951 			item->setBackground(Qt::NoBrush);
    952 	}
    953 
    954 	if (text.startsWith(P2P_EVENT_GROUP_STARTED)) {
    955 		/* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F"
    956 		 * passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7
    957 		 * [PERSISTENT] */
    958 		QStringList items = text.split(' ');
    959 		if (items.size() < 4)
    960 			return;
    961 
    962 		int pos = text.indexOf(" ssid=\"");
    963 		if (pos < 0)
    964 			return;
    965 		QString ssid = text.mid(pos + 7);
    966 		pos = ssid.indexOf(" passphrase=\"");
    967 		if (pos < 0)
    968 			pos = ssid.indexOf(" psk=");
    969 		if (pos >= 0)
    970 			ssid.truncate(pos);
    971 		pos = ssid.lastIndexOf('"');
    972 		if (pos >= 0)
    973 			ssid.truncate(pos);
    974 
    975 		QStandardItem *item = new QStandardItem(*group_icon, ssid);
    976 		if (item) {
    977 			item->setData(PEER_TYPE_P2P_GROUP, peer_role_type);
    978 			item->setData(items[1], peer_role_ifname);
    979 			QString details;
    980 			if (items[2] == "GO") {
    981 				details = tr("P2P GO for interface ") +
    982 					items[1];
    983 			} else {
    984 				details = tr("P2P client for interface ") +
    985 					items[1];
    986 			}
    987 			if (text.contains(" [PERSISTENT]"))
    988 				details += "\nPersistent group";
    989 			item->setData(details, peer_role_details);
    990 			item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP));
    991 			model.appendRow(item);
    992 		}
    993 	}
    994 
    995 	if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) {
    996 		/* P2P-GROUP-REMOVED wlan0-p2p-0 GO */
    997 		QStringList items = text.split(' ');
    998 		if (items.size() < 2)
    999 			return;
   1000 
   1001 		if (model.rowCount() == 0)
   1002 			return;
   1003 
   1004 		QModelIndexList lst = model.match(model.index(0, 0),
   1005 						  peer_role_ifname, items[1]);
   1006 		for (int i = 0; i < lst.size(); i++)
   1007 			model.removeRow(lst[i].row());
   1008 		return;
   1009 	}
   1010 
   1011 	if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) {
   1012 		/* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */
   1013 		QStringList items = text.split(' ');
   1014 		if (items.size() < 3)
   1015 			return;
   1016 		QString addr = items[1];
   1017 		QString pin = items[2];
   1018 
   1019 		QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P);
   1020 		if (item == NULL)
   1021 			return;
   1022 		item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY,
   1023 			      peer_role_selected_method);
   1024 		item->setData(pin, peer_role_selected_pin);
   1025 		QVariant var = item->data(peer_role_requested_method);
   1026 		if (var.isValid() &&
   1027 		    var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) {
   1028 			ctx_item = item;
   1029 			ctx_p2p_display_pin_pd();
   1030 		}
   1031 		return;
   1032 	}
   1033 
   1034 	if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) {
   1035 		/* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */
   1036 		QStringList items = text.split(' ');
   1037 		if (items.size() < 2)
   1038 			return;
   1039 		QString addr = items[1];
   1040 
   1041 		QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P);
   1042 		if (item == NULL)
   1043 			return;
   1044 		item->setData(SEL_METHOD_PIN_PEER_DISPLAY,
   1045 			      peer_role_selected_method);
   1046 		QVariant var = item->data(peer_role_requested_method);
   1047 		if (var.isValid() &&
   1048 		    var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) {
   1049 			ctx_item = item;
   1050 			ctx_p2p_connect();
   1051 		}
   1052 		return;
   1053 	}
   1054 
   1055 	if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) {
   1056 		/* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */
   1057 		QStringList items = text.split(' ');
   1058 		if (items.size() < 3)
   1059 			return;
   1060 		if (!items[1].startsWith("sa=") ||
   1061 		    !items[2].startsWith("persistent="))
   1062 			return;
   1063 		QString addr = items[1].mid(3);
   1064 		int id = items[2].mid(11).toInt();
   1065 
   1066 		char cmd[100];
   1067 		char reply[100];
   1068 		size_t reply_len;
   1069 
   1070 		snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id);
   1071 		reply_len = sizeof(reply) - 1;
   1072 		if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
   1073 			return;
   1074 		reply[reply_len] = '\0';
   1075 		QString name;
   1076 		char *pos = strrchr(reply, '"');
   1077 		if (pos && reply[0] == '"') {
   1078 			*pos = '\0';
   1079 			name = reply + 1;
   1080 		} else
   1081 			name = reply;
   1082 
   1083 		QStandardItem *item;
   1084 		item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION);
   1085 		if (item)
   1086 			model.removeRow(item->row());
   1087 
   1088 		item = new QStandardItem(*invitation_icon, name);
   1089 		if (!item)
   1090 			return;
   1091 		item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type);
   1092 		item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION));
   1093 		item->setData(addr, peer_role_address);
   1094 		item->setData(id, peer_role_network_id);
   1095 
   1096 		model.appendRow(item);
   1097 
   1098 		enable_persistent(id);
   1099 
   1100 		return;
   1101 	}
   1102 
   1103 	if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) {
   1104 		/* P2P-INVITATION-RESULT status=1 */
   1105 		/* TODO */
   1106 		return;
   1107 	}
   1108 
   1109 	if (text.startsWith(WPS_EVENT_ER_AP_ADD)) {
   1110 		/*
   1111 		 * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002
   1112 		 * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1
   1113 		 * |Very friendly name|Company|Long description of the model|
   1114 		 * WAP|http://w1.fi/|http://w1.fi/hostapd/
   1115 		 */
   1116 		QStringList items = text.split(' ');
   1117 		if (items.size() < 5)
   1118 			return;
   1119 		QString uuid = items[1];
   1120 		QString addr = items[2];
   1121 		QString pri_dev_type = items[3].mid(13);
   1122 		int wps_state = items[4].mid(10).toInt();
   1123 
   1124 		int pos = text.indexOf('|');
   1125 		if (pos < 0)
   1126 			return;
   1127 		items = text.mid(pos + 1).split('|');
   1128 		if (items.size() < 1)
   1129 			return;
   1130 
   1131 		QStandardItem *item = find_uuid(uuid);
   1132 		if (item)
   1133 			return;
   1134 
   1135 		item = new QStandardItem(*ap_icon, items[0]);
   1136 		if (item) {
   1137 			item->setData(uuid, peer_role_uuid);
   1138 			item->setData(addr, peer_role_address);
   1139 			int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP:
   1140 				PEER_TYPE_WPS_ER_AP_UNCONFIGURED;
   1141 			item->setData(type, peer_role_type);
   1142 			item->setToolTip(ItemType(type));
   1143 			item->setData(pri_dev_type, peer_role_pri_dev_type);
   1144 			item->setData(items.join(QString("\n")),
   1145 				      peer_role_details);
   1146 			model.appendRow(item);
   1147 		}
   1148 
   1149 		return;
   1150 	}
   1151 
   1152 	if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) {
   1153 		/* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */
   1154 		QStringList items = text.split(' ');
   1155 		if (items.size() < 2)
   1156 			return;
   1157 		if (model.rowCount() == 0)
   1158 			return;
   1159 
   1160 		QModelIndexList lst = model.match(model.index(0, 0),
   1161 						  peer_role_uuid, items[1]);
   1162 		for (int i = 0; i < lst.size(); i++) {
   1163 			QStandardItem *item = model.itemFromIndex(lst[i]);
   1164 			if (item &&
   1165 			    (item->data(peer_role_type).toInt() ==
   1166 			     PEER_TYPE_WPS_ER_AP ||
   1167 			     item->data(peer_role_type).toInt() ==
   1168 			     PEER_TYPE_WPS_ER_AP_UNCONFIGURED))
   1169 				model.removeRow(lst[i].row());
   1170 		}
   1171 		return;
   1172 	}
   1173 
   1174 	if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) {
   1175 		/*
   1176 		 * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333
   1177 		 * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0
   1178 		 * pri_dev_type=1-0050F204-1
   1179 		 * |Wireless Client|Company|cmodel|123|12345|
   1180 		 */
   1181 		QStringList items = text.split(' ');
   1182 		if (items.size() < 3)
   1183 			return;
   1184 		QString uuid = items[1];
   1185 		QString addr = items[2];
   1186 		QString pri_dev_type = items[6].mid(13);
   1187 		int config_methods = -1;
   1188 		int dev_passwd_id = -1;
   1189 
   1190 		for (int i = 3; i < items.size(); i++) {
   1191 			int pos = items[i].indexOf('=') + 1;
   1192 			if (pos < 1)
   1193 				continue;
   1194 			QString val = items[i].mid(pos);
   1195 			if (items[i].startsWith("config_methods=")) {
   1196 				config_methods = val.toInt(0, 0);
   1197 			} else if (items[i].startsWith("dev_passwd_id=")) {
   1198 				dev_passwd_id = val.toInt();
   1199 			}
   1200 		}
   1201 
   1202 		int pos = text.indexOf('|');
   1203 		if (pos < 0)
   1204 			return;
   1205 		items = text.mid(pos + 1).split('|');
   1206 		if (items.size() < 1)
   1207 			return;
   1208 		QString name = items[0];
   1209 		if (name.length() == 0)
   1210 			name = addr;
   1211 
   1212 		remove_enrollee_uuid(uuid);
   1213 
   1214 		QStandardItem *item;
   1215 		item = new QStandardItem(*laptop_icon, name);
   1216 		if (item) {
   1217 			item->setData(uuid, peer_role_uuid);
   1218 			item->setData(addr, peer_role_address);
   1219 			item->setData(PEER_TYPE_WPS_ER_ENROLLEE,
   1220 				      peer_role_type);
   1221 			item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE));
   1222 			item->setData(items.join(QString("\n")),
   1223 				      peer_role_details);
   1224 			item->setData(pri_dev_type, peer_role_pri_dev_type);
   1225 			if (config_methods >= 0)
   1226 				item->setData(config_methods,
   1227 					      peer_role_config_methods);
   1228 			if (dev_passwd_id >= 0)
   1229 				item->setData(dev_passwd_id,
   1230 					      peer_role_dev_passwd_id);
   1231 			model.appendRow(item);
   1232 		}
   1233 
   1234 		return;
   1235 	}
   1236 
   1237 	if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) {
   1238 		/*
   1239 		 * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333
   1240 		 * 02:66:a0:ee:17:27
   1241 		 */
   1242 		QStringList items = text.split(' ');
   1243 		if (items.size() < 2)
   1244 			return;
   1245 		remove_enrollee_uuid(items[1]);
   1246 		return;
   1247 	}
   1248 
   1249 	if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) {
   1250 		/* TODO: need to time out this somehow or remove on successful
   1251 		 * WPS run, etc. */
   1252 		/*
   1253 		 * WPS-ENROLLEE-SEEN 02:00:00:00:01:00
   1254 		 * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1
   1255 		 * [Wireless Client]
   1256 		 * (MAC addr, UUID-E, pri dev type, config methods,
   1257 		 * dev passwd id, request type, [dev name])
   1258 		 */
   1259 		QStringList items = text.split(' ');
   1260 		if (items.size() < 7)
   1261 			return;
   1262 		QString addr = items[1];
   1263 		QString uuid = items[2];
   1264 		QString pri_dev_type = items[3];
   1265 		int config_methods = items[4].toInt(0, 0);
   1266 		int dev_passwd_id = items[5].toInt();
   1267 		QString name;
   1268 
   1269 		QStandardItem *item = find_addr(addr);
   1270 		if (item) {
   1271 			int type = item->data(peer_role_type).toInt();
   1272 			if (type == PEER_TYPE_ASSOCIATED_STATION)
   1273 				return; /* already associated */
   1274 		}
   1275 
   1276 		int pos = text.indexOf('[');
   1277 		if (pos >= 0) {
   1278 			int pos2 = text.lastIndexOf(']');
   1279 			if (pos2 >= pos) {
   1280 				QStringList items2 =
   1281 					text.mid(pos + 1, pos2 - pos - 1).
   1282 					split('|');
   1283 				name = items2[0];
   1284 			}
   1285 		}
   1286 		if (name.isEmpty())
   1287 			name = addr;
   1288 
   1289 		item = find_uuid(uuid);
   1290 		if (item) {
   1291 			QVariant var = item->data(peer_role_config_methods);
   1292 			QVariant var2 = item->data(peer_role_dev_passwd_id);
   1293 			if ((var.isValid() && config_methods != var.toInt()) ||
   1294 			    (var2.isValid() && dev_passwd_id != var2.toInt()))
   1295 				remove_enrollee_uuid(uuid);
   1296 			else
   1297 				return;
   1298 		}
   1299 
   1300 		item = new QStandardItem(*laptop_icon, name);
   1301 		if (item) {
   1302 			item->setData(uuid, peer_role_uuid);
   1303 			item->setData(addr, peer_role_address);
   1304 			item->setData(PEER_TYPE_WPS_ENROLLEE,
   1305 				      peer_role_type);
   1306 			item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE));
   1307 			item->setData(items.join(QString("\n")),
   1308 				      peer_role_details);
   1309 			item->setData(pri_dev_type, peer_role_pri_dev_type);
   1310 			item->setData(config_methods,
   1311 				      peer_role_config_methods);
   1312 			item->setData(dev_passwd_id, peer_role_dev_passwd_id);
   1313 			model.appendRow(item);
   1314 		}
   1315 
   1316 		return;
   1317 	}
   1318 
   1319 	if (text.startsWith(WPA_EVENT_BSS_ADDED)) {
   1320 		/* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */
   1321 		QStringList items = text.split(' ');
   1322 		if (items.size() < 2)
   1323 			return;
   1324 		char cmd[20];
   1325 		snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt());
   1326 		add_bss(cmd);
   1327 		return;
   1328 	}
   1329 
   1330 	if (text.startsWith(WPA_EVENT_BSS_REMOVED)) {
   1331 		/* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */
   1332 		QStringList items = text.split(' ');
   1333 		if (items.size() < 2)
   1334 			return;
   1335 		remove_bss(items[1].toInt());
   1336 		return;
   1337 	}
   1338 }
   1339 
   1340 
   1341 void Peers::ctx_p2p_connect()
   1342 {
   1343 	if (ctx_item == NULL)
   1344 		return;
   1345 	QString addr = ctx_item->data(peer_role_address).toString();
   1346 	QString arg;
   1347 	int config_methods =
   1348 		ctx_item->data(peer_role_config_methods).toInt();
   1349 	enum selected_method method = SEL_METHOD_NONE;
   1350 	QVariant var = ctx_item->data(peer_role_selected_method);
   1351 	if (var.isValid())
   1352 		method = (enum selected_method) var.toInt();
   1353 	if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) {
   1354 		arg = ctx_item->data(peer_role_selected_pin).toString();
   1355 		char cmd[100];
   1356 		char reply[100];
   1357 		size_t reply_len;
   1358 		snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display",
   1359 			 addr.toAscii().constData(),
   1360 			 arg.toAscii().constData());
   1361 		reply_len = sizeof(reply) - 1;
   1362 		if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1363 			QMessageBox msg;
   1364 			msg.setIcon(QMessageBox::Warning);
   1365 			msg.setText("Failed to initiate P2P connect.");
   1366 			msg.exec();
   1367 			return;
   1368 		}
   1369 		QMessageBox::information(this,
   1370 					 tr("PIN for ") + ctx_item->text(),
   1371 					 tr("Enter the following PIN on the\n"
   1372 					    "peer device: ") + arg);
   1373 	} else if (method == SEL_METHOD_PIN_PEER_DISPLAY) {
   1374 		StringQuery input(tr("PIN from peer display:"));
   1375 		input.setWindowTitle(tr("PIN for ") + ctx_item->text());
   1376 		if (input.exec() != QDialog::Accepted)
   1377 			return;
   1378 		arg = input.get_string();
   1379 	} else if (config_methods == 0x0080 /* PBC */) {
   1380 		arg = "pbc";
   1381 	} else {
   1382 		StringQuery input(tr("PIN:"));
   1383 		input.setWindowTitle(tr("PIN for ") + ctx_item->text());
   1384 		if (input.exec() != QDialog::Accepted)
   1385 			return;
   1386 		arg = input.get_string();
   1387 	}
   1388 
   1389 	char cmd[100];
   1390 	char reply[100];
   1391 	size_t reply_len;
   1392 	snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s",
   1393 		 addr.toAscii().constData(),
   1394 		 arg.toAscii().constData());
   1395 	reply_len = sizeof(reply) - 1;
   1396 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1397 		QMessageBox msg;
   1398 		msg.setIcon(QMessageBox::Warning);
   1399 		msg.setText("Failed to initiate P2P connect.");
   1400 		msg.exec();
   1401 	}
   1402 }
   1403 
   1404 
   1405 void Peers::ctx_p2p_req_pin()
   1406 {
   1407 	if (ctx_item == NULL)
   1408 		return;
   1409 	QString addr = ctx_item->data(peer_role_address).toString();
   1410 	ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY,
   1411 			  peer_role_requested_method);
   1412 
   1413 	char cmd[100];
   1414 	char reply[100];
   1415 	size_t reply_len;
   1416 	snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display",
   1417 		 addr.toAscii().constData());
   1418 	reply_len = sizeof(reply) - 1;
   1419 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1420 		QMessageBox msg;
   1421 		msg.setIcon(QMessageBox::Warning);
   1422 		msg.setText(tr("Failed to request PIN from peer."));
   1423 		msg.exec();
   1424 	}
   1425 }
   1426 
   1427 
   1428 void Peers::ctx_p2p_show_pin()
   1429 {
   1430 	if (ctx_item == NULL)
   1431 		return;
   1432 	QString addr = ctx_item->data(peer_role_address).toString();
   1433 	ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY,
   1434 			  peer_role_requested_method);
   1435 
   1436 	char cmd[100];
   1437 	char reply[100];
   1438 	size_t reply_len;
   1439 	snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad",
   1440 		 addr.toAscii().constData());
   1441 	reply_len = sizeof(reply) - 1;
   1442 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1443 		QMessageBox msg;
   1444 		msg.setIcon(QMessageBox::Warning);
   1445 		msg.setText(tr("Failed to request peer to enter PIN."));
   1446 		msg.exec();
   1447 	}
   1448 }
   1449 
   1450 
   1451 void Peers::ctx_p2p_display_pin()
   1452 {
   1453 	if (ctx_item == NULL)
   1454 		return;
   1455 	QString addr = ctx_item->data(peer_role_address).toString();
   1456 
   1457 	char cmd[100];
   1458 	char reply[100];
   1459 	size_t reply_len;
   1460 	snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin",
   1461 		 addr.toAscii().constData());
   1462 	reply_len = sizeof(reply) - 1;
   1463 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1464 		QMessageBox msg;
   1465 		msg.setIcon(QMessageBox::Warning);
   1466 		msg.setText("Failed to initiate P2P connect.");
   1467 		msg.exec();
   1468 		return;
   1469 	}
   1470 	reply[reply_len] = '\0';
   1471 	QMessageBox::information(this,
   1472 				 tr("PIN for ") + ctx_item->text(),
   1473 				 tr("Enter the following PIN on the\n"
   1474 				    "peer device: ") + reply);
   1475 }
   1476 
   1477 
   1478 void Peers::ctx_p2p_display_pin_pd()
   1479 {
   1480 	if (ctx_item == NULL)
   1481 		return;
   1482 	QString addr = ctx_item->data(peer_role_address).toString();
   1483 	QString arg = ctx_item->data(peer_role_selected_pin).toString();
   1484 
   1485 	char cmd[100];
   1486 	char reply[100];
   1487 	size_t reply_len;
   1488 	snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display",
   1489 		 addr.toAscii().constData(),
   1490 		 arg.toAscii().constData());
   1491 	reply_len = sizeof(reply) - 1;
   1492 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1493 		QMessageBox msg;
   1494 		msg.setIcon(QMessageBox::Warning);
   1495 		msg.setText("Failed to initiate P2P connect.");
   1496 		msg.exec();
   1497 		return;
   1498 	}
   1499 	reply[reply_len] = '\0';
   1500 	QMessageBox::information(this,
   1501 				 tr("PIN for ") + ctx_item->text(),
   1502 				 tr("Enter the following PIN on the\n"
   1503 				    "peer device: ") + arg);
   1504 }
   1505 
   1506 
   1507 void Peers::ctx_p2p_enter_pin()
   1508 {
   1509 	if (ctx_item == NULL)
   1510 		return;
   1511 	QString addr = ctx_item->data(peer_role_address).toString();
   1512 	QString arg;
   1513 
   1514 	StringQuery input(tr("PIN from peer:"));
   1515 	input.setWindowTitle(tr("PIN for ") + ctx_item->text());
   1516 	if (input.exec() != QDialog::Accepted)
   1517 		return;
   1518 	arg = input.get_string();
   1519 
   1520 	char cmd[100];
   1521 	char reply[100];
   1522 	size_t reply_len;
   1523 	snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad",
   1524 		 addr.toAscii().constData(),
   1525 		 arg.toAscii().constData());
   1526 	reply_len = sizeof(reply) - 1;
   1527 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1528 		QMessageBox msg;
   1529 		msg.setIcon(QMessageBox::Warning);
   1530 		msg.setText("Failed to initiate P2P connect.");
   1531 		msg.exec();
   1532 	}
   1533 }
   1534 
   1535 
   1536 void Peers::ctx_p2p_remove_group()
   1537 {
   1538 	if (ctx_item == NULL)
   1539 		return;
   1540 	char cmd[100];
   1541 	char reply[100];
   1542 	size_t reply_len;
   1543 	snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s",
   1544 		 ctx_item->data(peer_role_ifname).toString().toAscii().
   1545 		 constData());
   1546 	reply_len = sizeof(reply) - 1;
   1547 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1548 		QMessageBox msg;
   1549 		msg.setIcon(QMessageBox::Warning);
   1550 		msg.setText("Failed to remove P2P Group.");
   1551 		msg.exec();
   1552 	}
   1553 }
   1554 
   1555 
   1556 void Peers::closeEvent(QCloseEvent *)
   1557 {
   1558 	if (wpagui) {
   1559 		char reply[20];
   1560 		size_t replylen = sizeof(reply) - 1;
   1561 		wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen);
   1562 	}
   1563 }
   1564 
   1565 
   1566 void Peers::done(int r)
   1567 {
   1568 	QDialog::done(r);
   1569 	close();
   1570 }
   1571 
   1572 
   1573 void Peers::remove_enrollee_uuid(QString uuid)
   1574 {
   1575 	if (model.rowCount() == 0)
   1576 		return;
   1577 
   1578 	QModelIndexList lst = model.match(model.index(0, 0),
   1579 					  peer_role_uuid, uuid);
   1580 	for (int i = 0; i < lst.size(); i++) {
   1581 		QStandardItem *item = model.itemFromIndex(lst[i]);
   1582 		if (item == NULL)
   1583 			continue;
   1584 		int type = item->data(peer_role_type).toInt();
   1585 		if (type == PEER_TYPE_WPS_ER_ENROLLEE ||
   1586 		    type == PEER_TYPE_WPS_ENROLLEE)
   1587 			model.removeRow(lst[i].row());
   1588 	}
   1589 }
   1590 
   1591 
   1592 void Peers::properties()
   1593 {
   1594 	if (ctx_item == NULL)
   1595 		return;
   1596 
   1597 	QMessageBox msg(this);
   1598 	msg.setStandardButtons(QMessageBox::Ok);
   1599 	msg.setDefaultButton(QMessageBox::Ok);
   1600 	msg.setEscapeButton(QMessageBox::Ok);
   1601 	msg.setWindowTitle(tr("Peer Properties"));
   1602 
   1603 	int type = ctx_item->data(peer_role_type).toInt();
   1604 	QString title = Peers::ItemType(type);
   1605 
   1606 	msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text());
   1607 
   1608 	QVariant var;
   1609 	QString info;
   1610 
   1611 	var = ctx_item->data(peer_role_address);
   1612 	if (var.isValid())
   1613 		info += tr("Address: ") + var.toString() + QString("\n");
   1614 
   1615 	var = ctx_item->data(peer_role_uuid);
   1616 	if (var.isValid())
   1617 		info += tr("UUID: ") + var.toString() + QString("\n");
   1618 
   1619 	var = ctx_item->data(peer_role_pri_dev_type);
   1620 	if (var.isValid())
   1621 		info += tr("Primary Device Type: ") + var.toString() +
   1622 			QString("\n");
   1623 
   1624 	var = ctx_item->data(peer_role_ssid);
   1625 	if (var.isValid())
   1626 		info += tr("SSID: ") + var.toString() + QString("\n");
   1627 
   1628 	var = ctx_item->data(peer_role_config_methods);
   1629 	if (var.isValid()) {
   1630 		int methods = var.toInt();
   1631 		info += tr("Configuration Methods: ");
   1632 		if (methods & 0x0001)
   1633 			info += tr("[USBA]");
   1634 		if (methods & 0x0002)
   1635 			info += tr("[Ethernet]");
   1636 		if (methods & 0x0004)
   1637 			info += tr("[Label]");
   1638 		if (methods & 0x0008)
   1639 			info += tr("[Display]");
   1640 		if (methods & 0x0010)
   1641 			info += tr("[Ext. NFC Token]");
   1642 		if (methods & 0x0020)
   1643 			info += tr("[Int. NFC Token]");
   1644 		if (methods & 0x0040)
   1645 			info += tr("[NFC Interface]");
   1646 		if (methods & 0x0080)
   1647 			info += tr("[Push Button]");
   1648 		if (methods & 0x0100)
   1649 			info += tr("[Keypad]");
   1650 		info += "\n";
   1651 	}
   1652 
   1653 	var = ctx_item->data(peer_role_selected_method);
   1654 	if (var.isValid()) {
   1655 		enum selected_method method =
   1656 			(enum selected_method) var.toInt();
   1657 		switch (method) {
   1658 		case SEL_METHOD_NONE:
   1659 			break;
   1660 		case SEL_METHOD_PIN_PEER_DISPLAY:
   1661 			info += tr("Selected Method: PIN on peer display\n");
   1662 			break;
   1663 		case SEL_METHOD_PIN_LOCAL_DISPLAY:
   1664 			info += tr("Selected Method: PIN on local display\n");
   1665 			break;
   1666 		}
   1667 	}
   1668 
   1669 	var = ctx_item->data(peer_role_selected_pin);
   1670 	if (var.isValid()) {
   1671 		info += tr("PIN to enter on peer: ") + var.toString() + "\n";
   1672 	}
   1673 
   1674 	var = ctx_item->data(peer_role_dev_passwd_id);
   1675 	if (var.isValid()) {
   1676 		info += tr("Device Password ID: ") + var.toString();
   1677 		switch (var.toInt()) {
   1678 		case 0:
   1679 			info += tr(" (Default PIN)");
   1680 			break;
   1681 		case 1:
   1682 			info += tr(" (User-specified PIN)");
   1683 			break;
   1684 		case 2:
   1685 			info += tr(" (Machine-specified PIN)");
   1686 			break;
   1687 		case 3:
   1688 			info += tr(" (Rekey)");
   1689 			break;
   1690 		case 4:
   1691 			info += tr(" (Push Button)");
   1692 			break;
   1693 		case 5:
   1694 			info += tr(" (Registrar-specified)");
   1695 			break;
   1696 		}
   1697 		info += "\n";
   1698 	}
   1699 
   1700 	msg.setInformativeText(info);
   1701 
   1702 	var = ctx_item->data(peer_role_details);
   1703 	if (var.isValid())
   1704 		msg.setDetailedText(var.toString());
   1705 
   1706 	msg.exec();
   1707 }
   1708 
   1709 
   1710 void Peers::connect_pbc()
   1711 {
   1712 	if (ctx_item == NULL)
   1713 		return;
   1714 
   1715 	char cmd[100];
   1716 	char reply[100];
   1717 	size_t reply_len;
   1718 
   1719 	int peer_type = ctx_item->data(peer_role_type).toInt();
   1720 	if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
   1721 		snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
   1722 			 ctx_item->data(peer_role_uuid).toString().toAscii().
   1723 			 constData());
   1724 	} else if (peer_type == PEER_TYPE_P2P ||
   1725 		   peer_type == PEER_TYPE_P2P_CLIENT) {
   1726 		snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc",
   1727 			 ctx_item->data(peer_role_address).toString().
   1728 			 toAscii().constData());
   1729 	} else {
   1730 		snprintf(cmd, sizeof(cmd), "WPS_PBC");
   1731 	}
   1732 	reply_len = sizeof(reply) - 1;
   1733 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1734 		QMessageBox msg;
   1735 		msg.setIcon(QMessageBox::Warning);
   1736 		msg.setText(tr("Failed to start WPS PBC."));
   1737 		msg.exec();
   1738 	}
   1739 }
   1740 
   1741 
   1742 void Peers::learn_ap_config()
   1743 {
   1744 	if (ctx_item == NULL)
   1745 		return;
   1746 
   1747 	QString uuid = ctx_item->data(peer_role_uuid).toString();
   1748 
   1749 	StringQuery input(tr("AP PIN:"));
   1750 	input.setWindowTitle(tr("AP PIN for ") + ctx_item->text());
   1751 	if (input.exec() != QDialog::Accepted)
   1752 		return;
   1753 
   1754 	char cmd[100];
   1755 	char reply[100];
   1756 	size_t reply_len;
   1757 
   1758 	snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
   1759 		 uuid.toAscii().constData(),
   1760 		 input.get_string().toAscii().constData());
   1761 	reply_len = sizeof(reply) - 1;
   1762 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
   1763 		QMessageBox msg;
   1764 		msg.setIcon(QMessageBox::Warning);
   1765 		msg.setText(tr("Failed to start learning AP configuration."));
   1766 		msg.exec();
   1767 	}
   1768 }
   1769 
   1770 
   1771 void Peers::ctx_hide_ap()
   1772 {
   1773 	hide_ap = true;
   1774 
   1775 	if (model.rowCount() == 0)
   1776 		return;
   1777 
   1778 	do {
   1779 		QModelIndexList lst;
   1780 		lst = model.match(model.index(0, 0),
   1781 				  peer_role_type, PEER_TYPE_AP);
   1782 		if (lst.size() == 0) {
   1783 			lst = model.match(model.index(0, 0),
   1784 					  peer_role_type, PEER_TYPE_AP_WPS);
   1785 			if (lst.size() == 0)
   1786 				break;
   1787 		}
   1788 
   1789 		model.removeRow(lst[0].row());
   1790 	} while (1);
   1791 }
   1792 
   1793 
   1794 void Peers::ctx_show_ap()
   1795 {
   1796 	hide_ap = false;
   1797 	add_scan_results();
   1798 }
   1799 
   1800 
   1801 void Peers::ctx_p2p_show_passphrase()
   1802 {
   1803 	char reply[64];
   1804 	size_t reply_len;
   1805 
   1806 	reply_len = sizeof(reply) - 1;
   1807 	if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 ||
   1808 	    memcmp(reply, "FAIL", 4) == 0) {
   1809 		QMessageBox msg;
   1810 		msg.setIcon(QMessageBox::Warning);
   1811 		msg.setText("Failed to get P2P group passphrase.");
   1812 		msg.exec();
   1813 	} else {
   1814 		reply[reply_len] = '\0';
   1815 		QMessageBox::information(this, tr("Passphrase"),
   1816 					 tr("P2P group passphrase:\n") +
   1817 					 reply);
   1818 	}
   1819 }
   1820 
   1821 
   1822 void Peers::ctx_p2p_start_persistent()
   1823 {
   1824 	if (ctx_item == NULL)
   1825 		return;
   1826 
   1827 	char cmd[100];
   1828 	char reply[100];
   1829 	size_t reply_len;
   1830 
   1831 	snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d",
   1832 		 ctx_item->data(peer_role_network_id).toInt());
   1833 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 ||
   1834 	    memcmp(reply, "FAIL", 4) == 0) {
   1835 		QMessageBox msg;
   1836 		msg.setIcon(QMessageBox::Warning);
   1837 		msg.setText(tr("Failed to start persistent P2P Group."));
   1838 		msg.exec();
   1839 	} else if (ctx_item->data(peer_role_type).toInt() ==
   1840 		   PEER_TYPE_P2P_INVITATION)
   1841 		model.removeRow(ctx_item->row());
   1842 }
   1843 
   1844 
   1845 void Peers::ctx_p2p_invite()
   1846 {
   1847 	if (ctx_item == NULL)
   1848 		return;
   1849 
   1850 	char cmd[100];
   1851 	char reply[100];
   1852 	size_t reply_len;
   1853 
   1854 	snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d",
   1855 		 ctx_item->data(peer_role_network_id).toInt());
   1856 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 ||
   1857 	    memcmp(reply, "FAIL", 4) == 0) {
   1858 		QMessageBox msg;
   1859 		msg.setIcon(QMessageBox::Warning);
   1860 		msg.setText(tr("Failed to invite peer to start persistent "
   1861 			       "P2P Group."));
   1862 		msg.exec();
   1863 	}
   1864 }
   1865 
   1866 
   1867 void Peers::ctx_p2p_delete()
   1868 {
   1869 	if (ctx_item == NULL)
   1870 		return;
   1871 	model.removeRow(ctx_item->row());
   1872 }
   1873 
   1874 
   1875 void Peers::enable_persistent(int id)
   1876 {
   1877 	if (model.rowCount() == 0)
   1878 		return;
   1879 
   1880 	QModelIndexList lst = model.match(model.index(0, 0),
   1881 					  peer_role_network_id, id);
   1882 	for (int i = 0; i < lst.size(); i++) {
   1883 		QStandardItem *item = model.itemFromIndex(lst[i]);
   1884 		int type = item->data(peer_role_type).toInt();
   1885 		if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
   1886 		    type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT)
   1887 			item->setBackground(Qt::NoBrush);
   1888 	}
   1889 }
   1890