2 * wpa_gui - Peers class
3 * Copyright (c) 2009, Atheros Communications
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
16 #include <QImageReader>
17 #include <QMessageBox>
21 #include "stringquery.h"
25 static const int peer_role_address = Qt::UserRole + 1;
26 static const int peer_role_type = Qt::UserRole + 2;
27 static const int peer_role_uuid = Qt::UserRole + 3;
31 * - add current AP info (e.g., from WPS) in station mode
32 * - different icons to indicate peer type
36 PEER_TYPE_ASSOCIATED_STATION,
39 PEER_TYPE_WPS_PIN_NEEDED,
41 PEER_TYPE_WPS_ER_ENROLLEE
45 Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags)
50 if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
52 default_icon = new QIcon(":/icons/wpa_gui.svg");
53 ap_icon = new QIcon(":/icons/ap.svg");
54 laptop_icon = new QIcon(":/icons/laptop.svg");
56 default_icon = new QIcon(":/icons/wpa_gui.png");
57 ap_icon = new QIcon(":/icons/ap.png");
58 laptop_icon = new QIcon(":/icons/laptop.png");
61 peers->setModel(&model);
62 peers->setResizeMode(QListView::Adjust);
64 peers->setContextMenuPolicy(Qt::CustomContextMenu);
65 connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)),
66 this, SLOT(context_menu(const QPoint &)));
72 void Peers::setWpaGui(WpaGui *_wpagui)
87 void Peers::languageChange()
93 void Peers::context_menu(const QPoint &pos)
95 QMenu *menu = new QMenu;
99 QModelIndex idx = peers->indexAt(pos);
101 ctx_item = model.itemFromIndex(idx);
102 int type = ctx_item->data(peer_role_type).toInt();
105 case PEER_TYPE_ASSOCIATED_STATION:
106 title = tr("Associated station");
111 case PEER_TYPE_AP_WPS:
112 title = tr("WPS AP");
114 case PEER_TYPE_WPS_PIN_NEEDED:
115 title = tr("WPS PIN needed");
117 case PEER_TYPE_WPS_ER_AP:
118 title = tr("ER: WPS AP");
120 case PEER_TYPE_WPS_ER_ENROLLEE:
121 title = tr("ER: WPS Enrollee");
124 menu->addAction(title)->setEnabled(false);
125 menu->addSeparator();
127 if (type == PEER_TYPE_ASSOCIATED_STATION ||
128 type == PEER_TYPE_AP_WPS ||
129 type == PEER_TYPE_WPS_PIN_NEEDED ||
130 type == PEER_TYPE_WPS_ER_ENROLLEE) {
131 /* TODO: only for peers that are requesting WPS PIN
133 menu->addAction(QString("Enter WPS PIN"), this,
138 menu->addAction(QString("Refresh"), this, SLOT(ctx_refresh()));
141 menu->exec(peers->mapToGlobal(pos));
145 void Peers::enter_pin()
147 if (ctx_item == NULL)
150 int peer_type = ctx_item->data(peer_role_type).toInt();
153 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE)
154 uuid = ctx_item->data(peer_role_uuid).toString();
156 addr = ctx_item->data(peer_role_address).toString();
158 StringQuery input(tr("PIN:"));
159 input.setWindowTitle(tr("PIN for ") + ctx_item->text());
160 if (input.exec() != QDialog::Accepted)
167 if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
168 snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
169 uuid.toAscii().constData(),
170 input.get_string().toAscii().constData());
172 snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
173 addr.toAscii().constData(),
174 input.get_string().toAscii().constData());
176 reply_len = sizeof(reply) - 1;
177 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
179 msg.setIcon(QMessageBox::Warning);
180 msg.setText("Failed to set the WPS PIN.");
186 void Peers::ctx_refresh()
192 void Peers::add_station(QString info)
194 QStringList lines = info.split(QRegExp("\\n"));
197 for (QStringList::Iterator it = lines.begin();
198 it != lines.end(); it++) {
199 int pos = (*it).indexOf('=') + 1;
203 if ((*it).startsWith("wpsDeviceName="))
204 name = (*it).mid(pos);
210 QStandardItem *item = new QStandardItem(*laptop_icon, name);
212 item->setData(lines[0], peer_role_address);
213 item->setData(PEER_TYPE_ASSOCIATED_STATION,
215 item->setToolTip(info);
216 model.appendRow(item);
221 void Peers::add_stations()
228 reply_len = sizeof(reply) - 1;
229 if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0)
233 reply[reply_len] = '\0';
236 while (*txt != '\0' && *txt != '\n')
239 if (strncmp(reply, "FAIL", 4) == 0 ||
240 strncmp(reply, "UNKNOWN", 7) == 0)
245 reply_len = sizeof(reply) - 1;
246 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
247 res = wpagui->ctrlRequest(cmd, reply, &reply_len);
252 void Peers::add_single_station(const char *addr)
258 reply_len = sizeof(reply) - 1;
259 snprintf(cmd, sizeof(cmd), "STA %s", addr);
260 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
263 reply[reply_len] = '\0';
266 while (*txt != '\0' && *txt != '\n')
269 if (strncmp(reply, "FAIL", 4) == 0 ||
270 strncmp(reply, "UNKNOWN", 7) == 0)
277 void Peers::add_scan_results()
286 snprintf(cmd, sizeof(cmd), "BSS %d", index++);
290 reply_len = sizeof(reply) - 1;
291 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
293 reply[reply_len] = '\0';
296 if (bss.isEmpty() || bss.startsWith("FAIL"))
299 QString ssid, bssid, flags, wps_name;
301 QStringList lines = bss.split(QRegExp("\\n"));
302 for (QStringList::Iterator it = lines.begin();
303 it != lines.end(); it++) {
304 int pos = (*it).indexOf('=') + 1;
308 if ((*it).startsWith("bssid="))
309 bssid = (*it).mid(pos);
310 else if ((*it).startsWith("flags="))
311 flags = (*it).mid(pos);
312 else if ((*it).startsWith("ssid="))
313 ssid = (*it).mid(pos);
314 else if ((*it).startsWith("wps_device_name="))
315 wps_name = (*it).mid(pos);
318 QString name = wps_name;
320 name = ssid + "\n" + bssid;
322 QStandardItem *item = new QStandardItem(*ap_icon, name);
324 item->setData(bssid, peer_role_address);
325 if (flags.contains("[WPS"))
326 item->setData(PEER_TYPE_AP_WPS,
329 item->setData(PEER_TYPE_AP, peer_role_type);
331 for (int i = 0; i < lines.size(); i++) {
332 if (lines[i].length() > 60) {
334 60, lines[i].length());
338 item->setToolTip(lines.join("\n"));
339 model.appendRow(item);
345 void Peers::update_peers()
352 size_t replylen = sizeof(reply) - 1;
353 wpagui->ctrlRequest("WPS_ER_START", reply, &replylen);
360 QStandardItem * Peers::find_addr(QString addr)
362 if (model.rowCount() == 0)
365 QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
369 return model.itemFromIndex(lst[0]);
373 QStandardItem * Peers::find_uuid(QString uuid)
375 if (model.rowCount() == 0)
378 QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid,
382 return model.itemFromIndex(lst[0]);
386 void Peers::event_notify(WpaMsg msg)
388 QString text = msg.getMsg();
390 if (text.startsWith(WPS_EVENT_PIN_NEEDED)) {
392 * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7
394 * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
396 QStringList items = text.split(' ');
397 QString uuid = items[1];
398 QString addr = items[2];
401 QStandardItem *item = find_addr(addr);
405 int pos = text.indexOf('[');
407 int pos2 = text.lastIndexOf(']');
409 items = text.mid(pos + 1, pos2 - pos - 1).
416 item = new QStandardItem(*laptop_icon, name);
418 item->setData(addr, peer_role_address);
419 item->setData(PEER_TYPE_WPS_PIN_NEEDED,
421 item->setToolTip(items.join(QString("\n")));
422 model.appendRow(item);
427 if (text.startsWith(AP_STA_CONNECTED)) {
428 /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */
429 QStringList items = text.split(' ');
430 QString addr = items[1];
431 QStandardItem *item = find_addr(addr);
432 if (item == NULL || item->data(peer_role_type).toInt() !=
433 PEER_TYPE_ASSOCIATED_STATION)
434 add_single_station(addr.toAscii().constData());
438 if (text.startsWith(AP_STA_DISCONNECTED)) {
439 /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */
440 QStringList items = text.split(' ');
441 QString addr = items[1];
443 if (model.rowCount() == 0)
446 QModelIndexList lst = model.match(model.index(0, 0),
447 peer_role_address, addr);
448 for (int i = 0; i < lst.size(); i++) {
449 QStandardItem *item = model.itemFromIndex(lst[i]);
450 if (item && item->data(peer_role_type).toInt() ==
451 PEER_TYPE_ASSOCIATED_STATION)
452 model.removeRow(lst[i].row());
457 if (text.startsWith(WPS_EVENT_ER_AP_ADD)) {
459 * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002|
460 * Very friendly name|Company|Long description of the model|
461 * WAP|http://w1.fi/|http://w1.fi/hostapd/
463 int pos = text.indexOf(' ');
466 QStringList items = text.mid(pos + 1).split('|');
467 if (items.size() < 2)
470 QStandardItem *item = find_uuid(items[0]);
474 item = new QStandardItem(*ap_icon, items[1]);
476 item->setData(items[0], peer_role_uuid);
477 item->setData(PEER_TYPE_WPS_ER_AP, peer_role_type);
478 item->setToolTip(items.join(QString("\n")));
479 model.appendRow(item);
485 if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) {
486 /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */
487 QStringList items = text.split(' ');
488 if (items.size() < 2)
490 if (model.rowCount() == 0)
493 QModelIndexList lst = model.match(model.index(0, 0),
494 peer_role_uuid, items[1]);
495 for (int i = 0; i < lst.size(); i++) {
496 QStandardItem *item = model.itemFromIndex(lst[i]);
497 if (item && item->data(peer_role_type).toInt() ==
499 model.removeRow(lst[i].row());
504 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) {
506 * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333
507 * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0
508 * pri_dev_type=1-0050F204-1
509 * |Wireless Client|Company|cmodel|123|12345|
511 QStringList items = text.split(' ');
512 if (items.size() < 3)
514 QString uuid = items[1];
515 QString addr = items[2];
517 int pos = text.indexOf('|');
520 items = text.mid(pos + 1).split('|');
521 if (items.size() < 1)
523 QString name = items[0];
524 if (name.length() == 0)
527 remove_enrollee_uuid(uuid);
530 item = new QStandardItem(*laptop_icon, name);
532 item->setData(uuid, peer_role_uuid);
533 item->setData(addr, peer_role_address);
534 item->setData(PEER_TYPE_WPS_ER_ENROLLEE,
536 item->setToolTip(items.join(QString("\n")));
537 model.appendRow(item);
543 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) {
545 * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333
548 QStringList items = text.split(' ');
549 if (items.size() < 2)
551 remove_enrollee_uuid(items[1]);
557 void Peers::closeEvent(QCloseEvent *)
561 size_t replylen = sizeof(reply) - 1;
562 wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen);
567 void Peers::done(int r)
574 void Peers::remove_enrollee_uuid(QString uuid)
576 if (model.rowCount() == 0)
579 QModelIndexList lst = model.match(model.index(0, 0),
580 peer_role_uuid, uuid);
581 for (int i = 0; i < lst.size(); i++) {
582 QStandardItem *item = model.itemFromIndex(lst[i]);
583 if (item && item->data(peer_role_type).toInt() ==
584 PEER_TYPE_WPS_ER_ENROLLEE)
585 model.removeRow(lst[i].row());