/* * wpa_gui - Peers class * Copyright (c) 2009-2010, Atheros Communications * * This software may be distributed under the terms of the BSD license. * See README 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); } }