blob: 65bb17dbd022962164b2ae77b2dce610609094b9 [file] [log] [blame]
/*
* wpa_gui - Peers class
* Copyright (c) 2009-2010, Atheros Communications
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include <cstdio>
#include <QImageReader>
#include <QMessageBox>
#include "common/wpa_ctrl.h"
#include "wpagui.h"
#include "stringquery.h"
#include "peers.h"
enum {
peer_role_address = Qt::UserRole + 1,
peer_role_type,
peer_role_uuid,
peer_role_details,
peer_role_ifname,
peer_role_pri_dev_type,
peer_role_ssid,
peer_role_config_methods,
peer_role_dev_passwd_id,
peer_role_bss_id,
peer_role_selected_method,
peer_role_selected_pin,
peer_role_requested_method,
peer_role_network_id
};
enum selected_method {
SEL_METHOD_NONE,
SEL_METHOD_PIN_PEER_DISPLAY,
SEL_METHOD_PIN_LOCAL_DISPLAY
};
/*
* TODO:
* - add current AP info (e.g., from WPS) in station mode
*/
enum peer_type {
PEER_TYPE_ASSOCIATED_STATION,
PEER_TYPE_AP,
PEER_TYPE_AP_WPS,
PEER_TYPE_WPS_PIN_NEEDED,
PEER_TYPE_P2P,
PEER_TYPE_P2P_CLIENT,
PEER_TYPE_P2P_GROUP,
PEER_TYPE_P2P_PERSISTENT_GROUP_GO,
PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT,
PEER_TYPE_P2P_INVITATION,
PEER_TYPE_WPS_ER_AP,
PEER_TYPE_WPS_ER_AP_UNCONFIGURED,
PEER_TYPE_WPS_ER_ENROLLEE,
PEER_TYPE_WPS_ENROLLEE
};
Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags)
: QDialog(parent)
{
setupUi(this);
if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
{
default_icon = new QIcon(":/icons/wpa_gui.svg");
ap_icon = new QIcon(":/icons/ap.svg");
laptop_icon = new QIcon(":/icons/laptop.svg");
group_icon = new QIcon(":/icons/group.svg");
invitation_icon = new QIcon(":/icons/invitation.svg");
} else {
default_icon = new QIcon(":/icons/wpa_gui.png");
ap_icon = new QIcon(":/icons/ap.png");
laptop_icon = new QIcon(":/icons/laptop.png");
group_icon = new QIcon(":/icons/group.png");
invitation_icon = new QIcon(":/icons/invitation.png");
}
peers->setModel(&model);
peers->setResizeMode(QListView::Adjust);
peers->setDragEnabled(false);
peers->setSelectionMode(QAbstractItemView::NoSelection);
peers->setContextMenuPolicy(Qt::CustomContextMenu);
connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(context_menu(const QPoint &)));
wpagui = NULL;
hide_ap = false;
}
void Peers::setWpaGui(WpaGui *_wpagui)
{
wpagui = _wpagui;
update_peers();
}
Peers::~Peers()
{
delete default_icon;
delete ap_icon;
delete laptop_icon;
delete group_icon;
delete invitation_icon;
}
void Peers::languageChange()
{
retranslateUi(this);
}
QString Peers::ItemType(int type)
{
QString title;
switch (type) {
case PEER_TYPE_ASSOCIATED_STATION:
title = tr("Associated station");
break;
case PEER_TYPE_AP:
title = tr("AP");
break;
case PEER_TYPE_AP_WPS:
title = tr("WPS AP");
break;
case PEER_TYPE_WPS_PIN_NEEDED:
title = tr("WPS PIN needed");
break;
case PEER_TYPE_P2P:
title = tr("P2P Device");
break;
case PEER_TYPE_P2P_CLIENT:
title = tr("P2P Device (group client)");
break;
case PEER_TYPE_P2P_GROUP:
title = tr("P2P Group");
break;
case PEER_TYPE_P2P_PERSISTENT_GROUP_GO:
title = tr("P2P Persistent Group (GO)");
break;
case PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT:
title = tr("P2P Persistent Group (client)");
break;
case PEER_TYPE_P2P_INVITATION:
title = tr("P2P Invitation");
break;
case PEER_TYPE_WPS_ER_AP:
title = tr("ER: WPS AP");
break;
case PEER_TYPE_WPS_ER_AP_UNCONFIGURED:
title = tr("ER: WPS AP (Unconfigured)");
break;
case PEER_TYPE_WPS_ER_ENROLLEE:
title = tr("ER: WPS Enrollee");
break;
case PEER_TYPE_WPS_ENROLLEE:
title = tr("WPS Enrollee");
break;
}
return title;
}
void Peers::context_menu(const QPoint &pos)
{
QMenu *menu = new QMenu;
if (menu == NULL)
return;
QModelIndex idx = peers->indexAt(pos);
if (idx.isValid()) {
ctx_item = model.itemFromIndex(idx);
int type = ctx_item->data(peer_role_type).toInt();
menu->addAction(Peers::ItemType(type))->setEnabled(false);
menu->addSeparator();
int config_methods = -1;
QVariant var = ctx_item->data(peer_role_config_methods);
if (var.isValid())
config_methods = var.toInt();
enum selected_method method = SEL_METHOD_NONE;
var = ctx_item->data(peer_role_selected_method);
if (var.isValid())
method = (enum selected_method) var.toInt();
if ((type == PEER_TYPE_ASSOCIATED_STATION ||
type == PEER_TYPE_AP_WPS ||
type == PEER_TYPE_WPS_PIN_NEEDED ||
type == PEER_TYPE_WPS_ER_ENROLLEE ||
type == PEER_TYPE_WPS_ENROLLEE) &&
(config_methods == -1 || (config_methods & 0x010c))) {
menu->addAction(tr("Enter WPS PIN"), this,
SLOT(enter_pin()));
}
if (type == PEER_TYPE_P2P || type == PEER_TYPE_P2P_CLIENT) {
menu->addAction(tr("P2P Connect"), this,
SLOT(ctx_p2p_connect()));
if (method == SEL_METHOD_NONE &&
config_methods > -1 &&
config_methods & 0x0080 /* PBC */ &&
config_methods != 0x0080)
menu->addAction(tr("P2P Connect (PBC)"), this,
SLOT(connect_pbc()));
if (method == SEL_METHOD_NONE) {
menu->addAction(tr("P2P Request PIN"), this,
SLOT(ctx_p2p_req_pin()));
menu->addAction(tr("P2P Show PIN"), this,
SLOT(ctx_p2p_show_pin()));
}
if (config_methods > -1 && (config_methods & 0x0100)) {
/* Peer has Keypad */
menu->addAction(tr("P2P Display PIN"), this,
SLOT(ctx_p2p_display_pin()));
}
if (config_methods > -1 && (config_methods & 0x000c)) {
/* Peer has Label or Display */
menu->addAction(tr("P2P Enter PIN"), this,
SLOT(ctx_p2p_enter_pin()));
}
}
if (type == PEER_TYPE_P2P_GROUP) {
menu->addAction(tr("Show passphrase"), this,
SLOT(ctx_p2p_show_passphrase()));
menu->addAction(tr("Remove P2P Group"), this,
SLOT(ctx_p2p_remove_group()));
}
if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT ||
type == PEER_TYPE_P2P_INVITATION) {
menu->addAction(tr("Start group"), this,
SLOT(ctx_p2p_start_persistent()));
}
if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) {
menu->addAction(tr("Invite"), this,
SLOT(ctx_p2p_invite()));
}
if (type == PEER_TYPE_P2P_INVITATION) {
menu->addAction(tr("Ignore"), this,
SLOT(ctx_p2p_delete()));
}
if (type == PEER_TYPE_AP_WPS) {
menu->addAction(tr("Connect (PBC)"), this,
SLOT(connect_pbc()));
}
if ((type == PEER_TYPE_ASSOCIATED_STATION ||
type == PEER_TYPE_WPS_ER_ENROLLEE ||
type == PEER_TYPE_WPS_ENROLLEE) &&
config_methods >= 0 && (config_methods & 0x0080)) {
menu->addAction(tr("Enroll (PBC)"), this,
SLOT(connect_pbc()));
}
if (type == PEER_TYPE_WPS_ER_AP) {
menu->addAction(tr("Learn Configuration"), this,
SLOT(learn_ap_config()));
}
menu->addAction(tr("Properties"), this, SLOT(properties()));
} else {
ctx_item = NULL;
menu->addAction(QString(tr("Refresh")), this,
SLOT(ctx_refresh()));
menu->addAction(tr("Start P2P discovery"), this,
SLOT(ctx_p2p_start()));
menu->addAction(tr("Stop P2P discovery"), this,
SLOT(ctx_p2p_stop()));
menu->addAction(tr("P2P listen only"), this,
SLOT(ctx_p2p_listen()));
menu->addAction(tr("Start P2P group"), this,
SLOT(ctx_p2p_start_group()));
if (hide_ap)
menu->addAction(tr("Show AP entries"), this,
SLOT(ctx_show_ap()));
else
menu->addAction(tr("Hide AP entries"), this,
SLOT(ctx_hide_ap()));
}
menu->exec(peers->mapToGlobal(pos));
}
void Peers::enter_pin()
{
if (ctx_item == NULL)
return;
int peer_type = ctx_item->data(peer_role_type).toInt();
QString uuid;
QString addr;
addr = ctx_item->data(peer_role_address).toString();
if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE)
uuid = ctx_item->data(peer_role_uuid).toString();
StringQuery input(tr("PIN:"));
input.setWindowTitle(tr("PIN for ") + ctx_item->text());
if (input.exec() != QDialog::Accepted)
return;
char cmd[100];
char reply[100];
size_t reply_len;
if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
uuid.toAscii().constData(),
input.get_string().toAscii().constData(),
addr.toAscii().constData());
} else {
snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
addr.toAscii().constData(),
input.get_string().toAscii().constData());
}
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText(tr("Failed to set the WPS PIN."));
msg.exec();
}
}
void Peers::ctx_refresh()
{
update_peers();
}
void Peers::ctx_p2p_start()
{
char reply[20];
size_t reply_len;
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest("P2P_FIND", reply, &reply_len) < 0 ||
memcmp(reply, "FAIL", 4) == 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to start P2P discovery.");
msg.exec();
}
}
void Peers::ctx_p2p_stop()
{
char reply[20];
size_t reply_len;
reply_len = sizeof(reply) - 1;
wpagui->ctrlRequest("P2P_STOP_FIND", reply, &reply_len);
}
void Peers::ctx_p2p_listen()
{
char reply[20];
size_t reply_len;
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest("P2P_LISTEN 3600", reply, &reply_len) < 0 ||
memcmp(reply, "FAIL", 4) == 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to start P2P listen.");
msg.exec();
}
}
void Peers::ctx_p2p_start_group()
{
char reply[20];
size_t reply_len;
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest("P2P_GROUP_ADD", reply, &reply_len) < 0 ||
memcmp(reply, "FAIL", 4) == 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to start P2P group.");
msg.exec();
}
}
void Peers::add_station(QString info)
{
QStringList lines = info.split(QRegExp("\\n"));
QString name;
for (QStringList::Iterator it = lines.begin();
it != lines.end(); it++) {
int pos = (*it).indexOf('=') + 1;
if (pos < 1)
continue;
if ((*it).startsWith("wpsDeviceName="))
name = (*it).mid(pos);
else if ((*it).startsWith("p2p_device_name="))
name = (*it).mid(pos);
}
if (name.isEmpty())
name = lines[0];
QStandardItem *item = new QStandardItem(*laptop_icon, name);
if (item) {
/* Remove WPS enrollee entry if one is still pending */
if (model.rowCount() > 0) {
QModelIndexList lst = model.match(model.index(0, 0),
peer_role_address,
lines[0]);
for (int i = 0; i < lst.size(); i++) {
QStandardItem *item;
item = model.itemFromIndex(lst[i]);
if (item == NULL)
continue;
int type = item->data(peer_role_type).toInt();
if (type == PEER_TYPE_WPS_ENROLLEE) {
model.removeRow(lst[i].row());
break;
}
}
}
item->setData(lines[0], peer_role_address);
item->setData(PEER_TYPE_ASSOCIATED_STATION,
peer_role_type);
item->setData(info, peer_role_details);
item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION));
model.appendRow(item);
}
}
void Peers::add_stations()
{
char reply[2048];
size_t reply_len;
char cmd[30];
int res;
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0)
return;
do {
reply[reply_len] = '\0';
QString info(reply);
char *txt = reply;
while (*txt != '\0' && *txt != '\n')
txt++;
*txt++ = '\0';
if (strncmp(reply, "FAIL", 4) == 0 ||
strncmp(reply, "UNKNOWN", 7) == 0)
break;
add_station(info);
reply_len = sizeof(reply) - 1;
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
res = wpagui->ctrlRequest(cmd, reply, &reply_len);
} while (res >= 0);
}
void Peers::add_single_station(const char *addr)
{
char reply[2048];
size_t reply_len;
char cmd[30];
reply_len = sizeof(reply) - 1;
snprintf(cmd, sizeof(cmd), "STA %s", addr);
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
return;
reply[reply_len] = '\0';
QString info(reply);
char *txt = reply;
while (*txt != '\0' && *txt != '\n')
txt++;
*txt++ = '\0';
if (strncmp(reply, "FAIL", 4) == 0 ||
strncmp(reply, "UNKNOWN", 7) == 0)
return;
add_station(info);
}
void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params)
{
/*
* dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0
* dev_type=1-0050f204-1 dev_name='Wireless Client'
* config_methods=0x8c
*/
QStringList items =
params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
QString addr = "";
QString name = "";
int config_methods = 0;
QString dev_type;
for (int i = 0; i < items.size(); i++) {
QString str = items.at(i);
int pos = str.indexOf('=') + 1;
if (str.startsWith("dev_name='"))
name = str.section('\'', 1, -2);
else if (str.startsWith("config_methods="))
config_methods =
str.section('=', 1).toInt(0, 0);
else if (str.startsWith("dev="))
addr = str.mid(pos);
else if (str.startsWith("dev_type=") && dev_type.isEmpty())
dev_type = str.mid(pos);
}
QStandardItem *item = find_addr(addr);
if (item)
return;
item = new QStandardItem(*default_icon, name);
if (item) {
/* TODO: indicate somehow the relationship to the group owner
* (parent) */
item->setData(addr, peer_role_address);
item->setData(config_methods, peer_role_config_methods);
item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type);
if (!dev_type.isEmpty())
item->setData(dev_type, peer_role_pri_dev_type);
item->setData(items.join(QString("\n")), peer_role_details);
item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT));
model.appendRow(item);
}
}
void Peers::remove_bss(int id)
{
if (model.rowCount() == 0)
return;
QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id,
id);
if (lst.size() == 0)
return;
model.removeRow(lst[0].row());
}
bool Peers::add_bss(const char *cmd)
{
char reply[2048];
size_t reply_len;
if (hide_ap)
return false;
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
return false;
reply[reply_len] = '\0';
QString bss(reply);
if (bss.isEmpty() || bss.startsWith("FAIL"))
return false;
QString ssid, bssid, flags, wps_name, pri_dev_type;
int id = -1;
QStringList lines = bss.split(QRegExp("\\n"));
for (QStringList::Iterator it = lines.begin();
it != lines.end(); it++) {
int pos = (*it).indexOf('=') + 1;
if (pos < 1)
continue;
if ((*it).startsWith("bssid="))
bssid = (*it).mid(pos);
else if ((*it).startsWith("id="))
id = (*it).mid(pos).toInt();
else if ((*it).startsWith("flags="))
flags = (*it).mid(pos);
else if ((*it).startsWith("ssid="))
ssid = (*it).mid(pos);
else if ((*it).startsWith("wps_device_name="))
wps_name = (*it).mid(pos);
else if ((*it).startsWith("wps_primary_device_type="))
pri_dev_type = (*it).mid(pos);
}
QString name = wps_name;
if (name.isEmpty())
name = ssid + "\n" + bssid;
QStandardItem *item = new QStandardItem(*ap_icon, name);
if (item) {
item->setData(bssid, peer_role_address);
if (id >= 0)
item->setData(id, peer_role_bss_id);
int type;
if (flags.contains("[WPS"))
type = PEER_TYPE_AP_WPS;
else
type = PEER_TYPE_AP;
item->setData(type, peer_role_type);
for (int i = 0; i < lines.size(); i++) {
if (lines[i].length() > 60) {
lines[i].remove(60, lines[i].length());
lines[i] += "..";
}
}
item->setToolTip(ItemType(type));
item->setData(lines.join("\n"), peer_role_details);
if (!pri_dev_type.isEmpty())
item->setData(pri_dev_type,
peer_role_pri_dev_type);
if (!ssid.isEmpty())
item->setData(ssid, peer_role_ssid);
model.appendRow(item);
lines = bss.split(QRegExp("\\n"));
for (QStringList::Iterator it = lines.begin();
it != lines.end(); it++) {
if ((*it).startsWith("p2p_group_client:"))
add_p2p_group_client(item,
(*it).mid(18));
}
}
return true;
}
void Peers::add_scan_results()
{
int index;
char cmd[20];
index = 0;
while (wpagui) {
snprintf(cmd, sizeof(cmd), "BSS %d", index++);
if (index > 1000)
break;
if (!add_bss(cmd))
break;
}
}
void Peers::add_persistent(int id, const char *ssid, const char *bssid)
{
char cmd[100];
char reply[100];
size_t reply_len;
int mode;
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id);
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
return;
reply[reply_len] = '\0';
mode = atoi(reply);
QString name = ssid;
name = '[' + name + ']';
QStandardItem *item = new QStandardItem(*group_icon, name);
if (!item)
return;
int type;
if (mode == 3)
type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO;
else
type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT;
item->setData(type, peer_role_type);
item->setToolTip(ItemType(type));
item->setData(ssid, peer_role_ssid);
if (bssid && strcmp(bssid, "any") == 0)
bssid = NULL;
if (bssid)
item->setData(bssid, peer_role_address);
item->setData(id, peer_role_network_id);
item->setBackground(Qt::BDiagPattern);
model.appendRow(item);
}
void Peers::add_persistent_groups()
{
char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
size_t len;
len = sizeof(buf) - 1;
if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
return;
buf[len] = '\0';
start = strchr(buf, '\n');
if (start == NULL)
return;
start++;
while (*start) {
bool last = false;
end = strchr(start, '\n');
if (end == NULL) {
last = true;
end = start;
while (end[0] && end[1])
end++;
}
*end = '\0';
id = start;
ssid = strchr(id, '\t');
if (ssid == NULL)
break;
*ssid++ = '\0';
bssid = strchr(ssid, '\t');
if (bssid == NULL)
break;
*bssid++ = '\0';
flags = strchr(bssid, '\t');
if (flags == NULL)
break;
*flags++ = '\0';
if (strstr(flags, "[DISABLED][P2P-PERSISTENT]"))
add_persistent(atoi(id), ssid, bssid);
if (last)
break;
start = end + 1;
}
}
void Peers::update_peers()
{
model.clear();
if (wpagui == NULL)
return;
char reply[20];
size_t replylen = sizeof(reply) - 1;
wpagui->ctrlRequest("WPS_ER_START", reply, &replylen);
add_stations();
add_scan_results();
add_persistent_groups();
}
QStandardItem * Peers::find_addr(QString addr)
{
if (model.rowCount() == 0)
return NULL;
QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
addr);
if (lst.size() == 0)
return NULL;
return model.itemFromIndex(lst[0]);
}
QStandardItem * Peers::find_addr_type(QString addr, int type)
{
if (model.rowCount() == 0)
return NULL;
QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
addr);
for (int i = 0; i < lst.size(); i++) {
QStandardItem *item = model.itemFromIndex(lst[i]);
if (item->data(peer_role_type).toInt() == type)
return item;
}
return NULL;
}
QStandardItem * Peers::find_uuid(QString uuid)
{
if (model.rowCount() == 0)
return NULL;
QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid,
uuid);
if (lst.size() == 0)
return NULL;
return model.itemFromIndex(lst[0]);
}
void Peers::event_notify(WpaMsg msg)
{
QString text = msg.getMsg();
if (text.startsWith(WPS_EVENT_PIN_NEEDED)) {
/*
* WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7
* 02:2a:c4:18:5b:f3
* [Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
*/
QStringList items = text.split(' ');
QString uuid = items[1];
QString addr = items[2];
QString name = "";
QStandardItem *item = find_addr(addr);
if (item)
return;
int pos = text.indexOf('[');
if (pos >= 0) {
int pos2 = text.lastIndexOf(']');
if (pos2 >= pos) {
items = text.mid(pos + 1, pos2 - pos - 1).
split('|');
name = items[0];
items.append(addr);
}
}
item = new QStandardItem(*laptop_icon, name);
if (item) {
item->setData(addr, peer_role_address);
item->setData(PEER_TYPE_WPS_PIN_NEEDED,
peer_role_type);
item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED));
item->setData(items.join("\n"), peer_role_details);
item->setData(items[5], peer_role_pri_dev_type);
model.appendRow(item);
}
return;
}
if (text.startsWith(AP_STA_CONNECTED)) {
/* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */
QStringList items = text.split(' ');
QString addr = items[1];
QStandardItem *item = find_addr(addr);
if (item == NULL || item->data(peer_role_type).toInt() !=
PEER_TYPE_ASSOCIATED_STATION)
add_single_station(addr.toAscii().constData());
return;
}
if (text.startsWith(AP_STA_DISCONNECTED)) {
/* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */
QStringList items = text.split(' ');
QString addr = items[1];
if (model.rowCount() == 0)
return;
QModelIndexList lst = model.match(model.index(0, 0),
peer_role_address, addr, -1);
for (int i = 0; i < lst.size(); i++) {
QStandardItem *item = model.itemFromIndex(lst[i]);
if (item && item->data(peer_role_type).toInt() ==
PEER_TYPE_ASSOCIATED_STATION) {
model.removeRow(lst[i].row());
break;
}
}
return;
}
if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) {
/*
* P2P-DEVICE-FOUND 02:b5:64:63:30:63
* p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1
* name='Wireless Client' config_methods=0x84 dev_capab=0x21
* group_capab=0x0
*/
QStringList items =
text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
QString addr = items[1];
QString name = "";
QString pri_dev_type;
int config_methods = 0;
for (int i = 0; i < items.size(); i++) {
QString str = items.at(i);
if (str.startsWith("name='"))
name = str.section('\'', 1, -2);
else if (str.startsWith("config_methods="))
config_methods =
str.section('=', 1).toInt(0, 0);
else if (str.startsWith("pri_dev_type="))
pri_dev_type = str.section('=', 1);
}
QStandardItem *item = find_addr(addr);
if (item) {
int type = item->data(peer_role_type).toInt();
if (type == PEER_TYPE_P2P)
return;
}
item = new QStandardItem(*default_icon, name);
if (item) {
item->setData(addr, peer_role_address);
item->setData(config_methods,
peer_role_config_methods);
item->setData(PEER_TYPE_P2P, peer_role_type);
if (!pri_dev_type.isEmpty())
item->setData(pri_dev_type,
peer_role_pri_dev_type);
item->setData(items.join(QString("\n")),
peer_role_details);
item->setToolTip(ItemType(PEER_TYPE_P2P));
model.appendRow(item);
}
item = find_addr_type(addr,
PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT);
if (item)
item->setBackground(Qt::NoBrush);
}
if (text.startsWith(P2P_EVENT_GROUP_STARTED)) {
/* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F"
* passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7
* [PERSISTENT] */
QStringList items = text.split(' ');
if (items.size() < 4)
return;
int pos = text.indexOf(" ssid=\"");
if (pos < 0)
return;
QString ssid = text.mid(pos + 7);
pos = ssid.indexOf(" passphrase=\"");
if (pos < 0)
pos = ssid.indexOf(" psk=");
if (pos >= 0)
ssid.truncate(pos);
pos = ssid.lastIndexOf('"');
if (pos >= 0)
ssid.truncate(pos);
QStandardItem *item = new QStandardItem(*group_icon, ssid);
if (item) {
item->setData(PEER_TYPE_P2P_GROUP, peer_role_type);
item->setData(items[1], peer_role_ifname);
QString details;
if (items[2] == "GO") {
details = tr("P2P GO for interface ") +
items[1];
} else {
details = tr("P2P client for interface ") +
items[1];
}
if (text.contains(" [PERSISTENT]"))
details += "\nPersistent group";
item->setData(details, peer_role_details);
item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP));
model.appendRow(item);
}
}
if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) {
/* P2P-GROUP-REMOVED wlan0-p2p-0 GO */
QStringList items = text.split(' ');
if (items.size() < 2)
return;
if (model.rowCount() == 0)
return;
QModelIndexList lst = model.match(model.index(0, 0),
peer_role_ifname, items[1]);
for (int i = 0; i < lst.size(); i++)
model.removeRow(lst[i].row());
return;
}
if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) {
/* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */
QStringList items = text.split(' ');
if (items.size() < 3)
return;
QString addr = items[1];
QString pin = items[2];
QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P);
if (item == NULL)
return;
item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY,
peer_role_selected_method);
item->setData(pin, peer_role_selected_pin);
QVariant var = item->data(peer_role_requested_method);
if (var.isValid() &&
var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) {
ctx_item = item;
ctx_p2p_display_pin_pd();
}
return;
}
if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) {
/* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */
QStringList items = text.split(' ');
if (items.size() < 2)
return;
QString addr = items[1];
QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P);
if (item == NULL)
return;
item->setData(SEL_METHOD_PIN_PEER_DISPLAY,
peer_role_selected_method);
QVariant var = item->data(peer_role_requested_method);
if (var.isValid() &&
var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) {
ctx_item = item;
ctx_p2p_connect();
}
return;
}
if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) {
/* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */
QStringList items = text.split(' ');
if (items.size() < 3)
return;
if (!items[1].startsWith("sa=") ||
!items[2].startsWith("persistent="))
return;
QString addr = items[1].mid(3);
int id = items[2].mid(11).toInt();
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id);
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
return;
reply[reply_len] = '\0';
QString name;
char *pos = strrchr(reply, '"');
if (pos && reply[0] == '"') {
*pos = '\0';
name = reply + 1;
} else
name = reply;
QStandardItem *item;
item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION);
if (item)
model.removeRow(item->row());
item = new QStandardItem(*invitation_icon, name);
if (!item)
return;
item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type);
item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION));
item->setData(addr, peer_role_address);
item->setData(id, peer_role_network_id);
model.appendRow(item);
enable_persistent(id);
return;
}
if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) {
/* P2P-INVITATION-RESULT status=1 */
/* TODO */
return;
}
if (text.startsWith(WPS_EVENT_ER_AP_ADD)) {
/*
* WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002
* 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1
* |Very friendly name|Company|Long description of the model|
* WAP|http://w1.fi/|http://w1.fi/hostapd/
*/
QStringList items = text.split(' ');
if (items.size() < 5)
return;
QString uuid = items[1];
QString addr = items[2];
QString pri_dev_type = items[3].mid(13);
int wps_state = items[4].mid(10).toInt();
int pos = text.indexOf('|');
if (pos < 0)
return;
items = text.mid(pos + 1).split('|');
if (items.size() < 1)
return;
QStandardItem *item = find_uuid(uuid);
if (item)
return;
item = new QStandardItem(*ap_icon, items[0]);
if (item) {
item->setData(uuid, peer_role_uuid);
item->setData(addr, peer_role_address);
int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP:
PEER_TYPE_WPS_ER_AP_UNCONFIGURED;
item->setData(type, peer_role_type);
item->setToolTip(ItemType(type));
item->setData(pri_dev_type, peer_role_pri_dev_type);
item->setData(items.join(QString("\n")),
peer_role_details);
model.appendRow(item);
}
return;
}
if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) {
/* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */
QStringList items = text.split(' ');
if (items.size() < 2)
return;
if (model.rowCount() == 0)
return;
QModelIndexList lst = model.match(model.index(0, 0),
peer_role_uuid, items[1]);
for (int i = 0; i < lst.size(); i++) {
QStandardItem *item = model.itemFromIndex(lst[i]);
if (item &&
(item->data(peer_role_type).toInt() ==
PEER_TYPE_WPS_ER_AP ||
item->data(peer_role_type).toInt() ==
PEER_TYPE_WPS_ER_AP_UNCONFIGURED))
model.removeRow(lst[i].row());
}
return;
}
if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) {
/*
* WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333
* 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0
* pri_dev_type=1-0050F204-1
* |Wireless Client|Company|cmodel|123|12345|
*/
QStringList items = text.split(' ');
if (items.size() < 3)
return;
QString uuid = items[1];
QString addr = items[2];
QString pri_dev_type = items[6].mid(13);
int config_methods = -1;
int dev_passwd_id = -1;
for (int i = 3; i < items.size(); i++) {
int pos = items[i].indexOf('=') + 1;
if (pos < 1)
continue;
QString val = items[i].mid(pos);
if (items[i].startsWith("config_methods=")) {
config_methods = val.toInt(0, 0);
} else if (items[i].startsWith("dev_passwd_id=")) {
dev_passwd_id = val.toInt();
}
}
int pos = text.indexOf('|');
if (pos < 0)
return;
items = text.mid(pos + 1).split('|');
if (items.size() < 1)
return;
QString name = items[0];
if (name.length() == 0)
name = addr;
remove_enrollee_uuid(uuid);
QStandardItem *item;
item = new QStandardItem(*laptop_icon, name);
if (item) {
item->setData(uuid, peer_role_uuid);
item->setData(addr, peer_role_address);
item->setData(PEER_TYPE_WPS_ER_ENROLLEE,
peer_role_type);
item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE));
item->setData(items.join(QString("\n")),
peer_role_details);
item->setData(pri_dev_type, peer_role_pri_dev_type);
if (config_methods >= 0)
item->setData(config_methods,
peer_role_config_methods);
if (dev_passwd_id >= 0)
item->setData(dev_passwd_id,
peer_role_dev_passwd_id);
model.appendRow(item);
}
return;
}
if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) {
/*
* WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333
* 02:66:a0:ee:17:27
*/
QStringList items = text.split(' ');
if (items.size() < 2)
return;
remove_enrollee_uuid(items[1]);
return;
}
if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) {
/* TODO: need to time out this somehow or remove on successful
* WPS run, etc. */
/*
* WPS-ENROLLEE-SEEN 02:00:00:00:01:00
* 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1
* [Wireless Client]
* (MAC addr, UUID-E, pri dev type, config methods,
* dev passwd id, request type, [dev name])
*/
QStringList items = text.split(' ');
if (items.size() < 7)
return;
QString addr = items[1];
QString uuid = items[2];
QString pri_dev_type = items[3];
int config_methods = items[4].toInt(0, 0);
int dev_passwd_id = items[5].toInt();
QString name;
QStandardItem *item = find_addr(addr);
if (item) {
int type = item->data(peer_role_type).toInt();
if (type == PEER_TYPE_ASSOCIATED_STATION)
return; /* already associated */
}
int pos = text.indexOf('[');
if (pos >= 0) {
int pos2 = text.lastIndexOf(']');
if (pos2 >= pos) {
QStringList items2 =
text.mid(pos + 1, pos2 - pos - 1).
split('|');
name = items2[0];
}
}
if (name.isEmpty())
name = addr;
item = find_uuid(uuid);
if (item) {
QVariant var = item->data(peer_role_config_methods);
QVariant var2 = item->data(peer_role_dev_passwd_id);
if ((var.isValid() && config_methods != var.toInt()) ||
(var2.isValid() && dev_passwd_id != var2.toInt()))
remove_enrollee_uuid(uuid);
else
return;
}
item = new QStandardItem(*laptop_icon, name);
if (item) {
item->setData(uuid, peer_role_uuid);
item->setData(addr, peer_role_address);
item->setData(PEER_TYPE_WPS_ENROLLEE,
peer_role_type);
item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE));
item->setData(items.join(QString("\n")),
peer_role_details);
item->setData(pri_dev_type, peer_role_pri_dev_type);
item->setData(config_methods,
peer_role_config_methods);
item->setData(dev_passwd_id, peer_role_dev_passwd_id);
model.appendRow(item);
}
return;
}
if (text.startsWith(WPA_EVENT_BSS_ADDED)) {
/* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */
QStringList items = text.split(' ');
if (items.size() < 2)
return;
char cmd[20];
snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt());
add_bss(cmd);
return;
}
if (text.startsWith(WPA_EVENT_BSS_REMOVED)) {
/* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */
QStringList items = text.split(' ');
if (items.size() < 2)
return;
remove_bss(items[1].toInt());
return;
}
}
void Peers::ctx_p2p_connect()
{
if (ctx_item == NULL)
return;
QString addr = ctx_item->data(peer_role_address).toString();
QString arg;
int config_methods =
ctx_item->data(peer_role_config_methods).toInt();
enum selected_method method = SEL_METHOD_NONE;
QVariant var = ctx_item->data(peer_role_selected_method);
if (var.isValid())
method = (enum selected_method) var.toInt();
if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) {
arg = ctx_item->data(peer_role_selected_pin).toString();
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display",
addr.toAscii().constData(),
arg.toAscii().constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to initiate P2P connect.");
msg.exec();
return;
}
QMessageBox::information(this,
tr("PIN for ") + ctx_item->text(),
tr("Enter the following PIN on the\n"
"peer device: ") + arg);
} else if (method == SEL_METHOD_PIN_PEER_DISPLAY) {
StringQuery input(tr("PIN from peer display:"));
input.setWindowTitle(tr("PIN for ") + ctx_item->text());
if (input.exec() != QDialog::Accepted)
return;
arg = input.get_string();
} else if (config_methods == 0x0080 /* PBC */) {
arg = "pbc";
} else {
StringQuery input(tr("PIN:"));
input.setWindowTitle(tr("PIN for ") + ctx_item->text());
if (input.exec() != QDialog::Accepted)
return;
arg = input.get_string();
}
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s",
addr.toAscii().constData(),
arg.toAscii().constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to initiate P2P connect.");
msg.exec();
}
}
void Peers::ctx_p2p_req_pin()
{
if (ctx_item == NULL)
return;
QString addr = ctx_item->data(peer_role_address).toString();
ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY,
peer_role_requested_method);
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display",
addr.toAscii().constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText(tr("Failed to request PIN from peer."));
msg.exec();
}
}
void Peers::ctx_p2p_show_pin()
{
if (ctx_item == NULL)
return;
QString addr = ctx_item->data(peer_role_address).toString();
ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY,
peer_role_requested_method);
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad",
addr.toAscii().constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText(tr("Failed to request peer to enter PIN."));
msg.exec();
}
}
void Peers::ctx_p2p_display_pin()
{
if (ctx_item == NULL)
return;
QString addr = ctx_item->data(peer_role_address).toString();
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin",
addr.toAscii().constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to initiate P2P connect.");
msg.exec();
return;
}
reply[reply_len] = '\0';
QMessageBox::information(this,
tr("PIN for ") + ctx_item->text(),
tr("Enter the following PIN on the\n"
"peer device: ") + reply);
}
void Peers::ctx_p2p_display_pin_pd()
{
if (ctx_item == NULL)
return;
QString addr = ctx_item->data(peer_role_address).toString();
QString arg = ctx_item->data(peer_role_selected_pin).toString();
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display",
addr.toAscii().constData(),
arg.toAscii().constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to initiate P2P connect.");
msg.exec();
return;
}
reply[reply_len] = '\0';
QMessageBox::information(this,
tr("PIN for ") + ctx_item->text(),
tr("Enter the following PIN on the\n"
"peer device: ") + arg);
}
void Peers::ctx_p2p_enter_pin()
{
if (ctx_item == NULL)
return;
QString addr = ctx_item->data(peer_role_address).toString();
QString arg;
StringQuery input(tr("PIN from peer:"));
input.setWindowTitle(tr("PIN for ") + ctx_item->text());
if (input.exec() != QDialog::Accepted)
return;
arg = input.get_string();
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad",
addr.toAscii().constData(),
arg.toAscii().constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to initiate P2P connect.");
msg.exec();
}
}
void Peers::ctx_p2p_remove_group()
{
if (ctx_item == NULL)
return;
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s",
ctx_item->data(peer_role_ifname).toString().toAscii().
constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to remove P2P Group.");
msg.exec();
}
}
void Peers::closeEvent(QCloseEvent *)
{
if (wpagui) {
char reply[20];
size_t replylen = sizeof(reply) - 1;
wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen);
}
}
void Peers::done(int r)
{
QDialog::done(r);
close();
}
void Peers::remove_enrollee_uuid(QString uuid)
{
if (model.rowCount() == 0)
return;
QModelIndexList lst = model.match(model.index(0, 0),
peer_role_uuid, uuid);
for (int i = 0; i < lst.size(); i++) {
QStandardItem *item = model.itemFromIndex(lst[i]);
if (item == NULL)
continue;
int type = item->data(peer_role_type).toInt();
if (type == PEER_TYPE_WPS_ER_ENROLLEE ||
type == PEER_TYPE_WPS_ENROLLEE)
model.removeRow(lst[i].row());
}
}
void Peers::properties()
{
if (ctx_item == NULL)
return;
QMessageBox msg(this);
msg.setStandardButtons(QMessageBox::Ok);
msg.setDefaultButton(QMessageBox::Ok);
msg.setEscapeButton(QMessageBox::Ok);
msg.setWindowTitle(tr("Peer Properties"));
int type = ctx_item->data(peer_role_type).toInt();
QString title = Peers::ItemType(type);
msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text());
QVariant var;
QString info;
var = ctx_item->data(peer_role_address);
if (var.isValid())
info += tr("Address: ") + var.toString() + QString("\n");
var = ctx_item->data(peer_role_uuid);
if (var.isValid())
info += tr("UUID: ") + var.toString() + QString("\n");
var = ctx_item->data(peer_role_pri_dev_type);
if (var.isValid())
info += tr("Primary Device Type: ") + var.toString() +
QString("\n");
var = ctx_item->data(peer_role_ssid);
if (var.isValid())
info += tr("SSID: ") + var.toString() + QString("\n");
var = ctx_item->data(peer_role_config_methods);
if (var.isValid()) {
int methods = var.toInt();
info += tr("Configuration Methods: ");
if (methods & 0x0001)
info += tr("[USBA]");
if (methods & 0x0002)
info += tr("[Ethernet]");
if (methods & 0x0004)
info += tr("[Label]");
if (methods & 0x0008)
info += tr("[Display]");
if (methods & 0x0010)
info += tr("[Ext. NFC Token]");
if (methods & 0x0020)
info += tr("[Int. NFC Token]");
if (methods & 0x0040)
info += tr("[NFC Interface]");
if (methods & 0x0080)
info += tr("[Push Button]");
if (methods & 0x0100)
info += tr("[Keypad]");
info += "\n";
}
var = ctx_item->data(peer_role_selected_method);
if (var.isValid()) {
enum selected_method method =
(enum selected_method) var.toInt();
switch (method) {
case SEL_METHOD_NONE:
break;
case SEL_METHOD_PIN_PEER_DISPLAY:
info += tr("Selected Method: PIN on peer display\n");
break;
case SEL_METHOD_PIN_LOCAL_DISPLAY:
info += tr("Selected Method: PIN on local display\n");
break;
}
}
var = ctx_item->data(peer_role_selected_pin);
if (var.isValid()) {
info += tr("PIN to enter on peer: ") + var.toString() + "\n";
}
var = ctx_item->data(peer_role_dev_passwd_id);
if (var.isValid()) {
info += tr("Device Password ID: ") + var.toString();
switch (var.toInt()) {
case 0:
info += tr(" (Default PIN)");
break;
case 1:
info += tr(" (User-specified PIN)");
break;
case 2:
info += tr(" (Machine-specified PIN)");
break;
case 3:
info += tr(" (Rekey)");
break;
case 4:
info += tr(" (Push Button)");
break;
case 5:
info += tr(" (Registrar-specified)");
break;
}
info += "\n";
}
msg.setInformativeText(info);
var = ctx_item->data(peer_role_details);
if (var.isValid())
msg.setDetailedText(var.toString());
msg.exec();
}
void Peers::connect_pbc()
{
if (ctx_item == NULL)
return;
char cmd[100];
char reply[100];
size_t reply_len;
int peer_type = ctx_item->data(peer_role_type).toInt();
if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
ctx_item->data(peer_role_uuid).toString().toAscii().
constData());
} else if (peer_type == PEER_TYPE_P2P ||
peer_type == PEER_TYPE_P2P_CLIENT) {
snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc",
ctx_item->data(peer_role_address).toString().
toAscii().constData());
} else {
snprintf(cmd, sizeof(cmd), "WPS_PBC");
}
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText(tr("Failed to start WPS PBC."));
msg.exec();
}
}
void Peers::learn_ap_config()
{
if (ctx_item == NULL)
return;
QString uuid = ctx_item->data(peer_role_uuid).toString();
StringQuery input(tr("AP PIN:"));
input.setWindowTitle(tr("AP PIN for ") + ctx_item->text());
if (input.exec() != QDialog::Accepted)
return;
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
uuid.toAscii().constData(),
input.get_string().toAscii().constData());
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText(tr("Failed to start learning AP configuration."));
msg.exec();
}
}
void Peers::ctx_hide_ap()
{
hide_ap = true;
if (model.rowCount() == 0)
return;
do {
QModelIndexList lst;
lst = model.match(model.index(0, 0),
peer_role_type, PEER_TYPE_AP);
if (lst.size() == 0) {
lst = model.match(model.index(0, 0),
peer_role_type, PEER_TYPE_AP_WPS);
if (lst.size() == 0)
break;
}
model.removeRow(lst[0].row());
} while (1);
}
void Peers::ctx_show_ap()
{
hide_ap = false;
add_scan_results();
}
void Peers::ctx_p2p_show_passphrase()
{
char reply[64];
size_t reply_len;
reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 ||
memcmp(reply, "FAIL", 4) == 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText("Failed to get P2P group passphrase.");
msg.exec();
} else {
reply[reply_len] = '\0';
QMessageBox::information(this, tr("Passphrase"),
tr("P2P group passphrase:\n") +
reply);
}
}
void Peers::ctx_p2p_start_persistent()
{
if (ctx_item == NULL)
return;
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d",
ctx_item->data(peer_role_network_id).toInt());
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 ||
memcmp(reply, "FAIL", 4) == 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText(tr("Failed to start persistent P2P Group."));
msg.exec();
} else if (ctx_item->data(peer_role_type).toInt() ==
PEER_TYPE_P2P_INVITATION)
model.removeRow(ctx_item->row());
}
void Peers::ctx_p2p_invite()
{
if (ctx_item == NULL)
return;
char cmd[100];
char reply[100];
size_t reply_len;
snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d",
ctx_item->data(peer_role_network_id).toInt());
if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 ||
memcmp(reply, "FAIL", 4) == 0) {
QMessageBox msg;
msg.setIcon(QMessageBox::Warning);
msg.setText(tr("Failed to invite peer to start persistent "
"P2P Group."));
msg.exec();
}
}
void Peers::ctx_p2p_delete()
{
if (ctx_item == NULL)
return;
model.removeRow(ctx_item->row());
}
void Peers::enable_persistent(int id)
{
if (model.rowCount() == 0)
return;
QModelIndexList lst = model.match(model.index(0, 0),
peer_role_network_id, id);
for (int i = 0; i < lst.size(); i++) {
QStandardItem *item = model.itemFromIndex(lst[i]);
int type = item->data(peer_role_type).toInt();
if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT)
item->setBackground(Qt::NoBrush);
}
}