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 StringQuery input(tr("PIN:"));
151 input.setWindowTitle(tr("PIN for ") + ctx_item->text());
152 if (input.exec() != QDialog::Accepted)
159 if (ctx_item->data(peer_role_type).toInt() ==
160 PEER_TYPE_WPS_ER_ENROLLEE) {
161 QString uuid = ctx_item->data(peer_role_uuid).toString();
162 snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
163 uuid.toAscii().constData(),
164 input.get_string().toAscii().constData());
166 QString addr = ctx_item->data(peer_role_address).toString();
167 snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
168 addr.toAscii().constData(),
169 input.get_string().toAscii().constData());
171 reply_len = sizeof(reply) - 1;
172 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
174 msg.setIcon(QMessageBox::Warning);
175 msg.setText("Failed to set the WPS PIN.");
181 void Peers::ctx_refresh()
187 void Peers::add_station(QString info)
189 QStringList lines = info.split(QRegExp("\\n"));
192 for (QStringList::Iterator it = lines.begin();
193 it != lines.end(); it++) {
194 int pos = (*it).indexOf('=') + 1;
198 if ((*it).startsWith("wpsDeviceName="))
199 name = (*it).mid(pos);
205 QStandardItem *item = new QStandardItem(*laptop_icon, name);
207 item->setData(lines[0], peer_role_address);
208 item->setData(PEER_TYPE_ASSOCIATED_STATION,
210 item->setToolTip(info);
211 model.appendRow(item);
216 void Peers::add_stations()
223 reply_len = sizeof(reply) - 1;
224 if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0)
228 reply[reply_len] = '\0';
231 while (*txt != '\0' && *txt != '\n')
234 if (strncmp(reply, "FAIL", 4) == 0 ||
235 strncmp(reply, "UNKNOWN", 7) == 0)
240 reply_len = sizeof(reply) - 1;
241 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
242 res = wpagui->ctrlRequest(cmd, reply, &reply_len);
247 void Peers::add_single_station(const char *addr)
253 reply_len = sizeof(reply) - 1;
254 snprintf(cmd, sizeof(cmd), "STA %s", addr);
255 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
258 reply[reply_len] = '\0';
261 while (*txt != '\0' && *txt != '\n')
264 if (strncmp(reply, "FAIL", 4) == 0 ||
265 strncmp(reply, "UNKNOWN", 7) == 0)
272 void Peers::add_scan_results()
281 snprintf(cmd, sizeof(cmd), "BSS %d", index++);
285 reply_len = sizeof(reply) - 1;
286 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
288 reply[reply_len] = '\0';
291 if (bss.isEmpty() || bss.startsWith("FAIL"))
294 QString ssid, bssid, flags, wps_name;
296 QStringList lines = bss.split(QRegExp("\\n"));
297 for (QStringList::Iterator it = lines.begin();
298 it != lines.end(); it++) {
299 int pos = (*it).indexOf('=') + 1;
303 if ((*it).startsWith("bssid="))
304 bssid = (*it).mid(pos);
305 else if ((*it).startsWith("flags="))
306 flags = (*it).mid(pos);
307 else if ((*it).startsWith("ssid="))
308 ssid = (*it).mid(pos);
309 else if ((*it).startsWith("wps_device_name="))
310 wps_name = (*it).mid(pos);
313 QString name = wps_name;
315 name = ssid + "\n" + bssid;
317 QStandardItem *item = new QStandardItem(*ap_icon, name);
319 item->setData(bssid, peer_role_address);
320 if (flags.contains("[WPS"))
321 item->setData(PEER_TYPE_AP_WPS,
324 item->setData(PEER_TYPE_AP, peer_role_type);
326 for (int i = 0; i < lines.size(); i++) {
327 if (lines[i].length() > 60) {
329 60, lines[i].length());
333 item->setToolTip(lines.join("\n"));
334 model.appendRow(item);
340 void Peers::update_peers()
347 size_t replylen = sizeof(reply) - 1;
348 wpagui->ctrlRequest("WPS_ER_START", reply, &replylen);
355 QStandardItem * Peers::find_addr(QString addr)
357 if (model.rowCount() == 0)
360 QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
364 return model.itemFromIndex(lst[0]);
368 QStandardItem * Peers::find_uuid(QString uuid)
370 if (model.rowCount() == 0)
373 QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid,
377 return model.itemFromIndex(lst[0]);
381 void Peers::event_notify(WpaMsg msg)
383 QString text = msg.getMsg();
385 if (text.startsWith(WPS_EVENT_PIN_NEEDED)) {
387 * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7
389 * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
391 QStringList items = text.split(' ');
392 QString uuid = items[1];
393 QString addr = items[2];
396 QStandardItem *item = find_addr(addr);
400 int pos = text.indexOf('[');
402 int pos2 = text.lastIndexOf(']');
404 items = text.mid(pos + 1, pos2 - pos - 1).
411 item = new QStandardItem(*laptop_icon, name);
413 item->setData(addr, peer_role_address);
414 item->setData(PEER_TYPE_WPS_PIN_NEEDED,
416 item->setToolTip(items.join(QString("\n")));
417 model.appendRow(item);
422 if (text.startsWith(AP_STA_CONNECTED)) {
423 /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */
424 QStringList items = text.split(' ');
425 QString addr = items[1];
426 QStandardItem *item = find_addr(addr);
427 if (item == NULL || item->data(peer_role_type).toInt() !=
428 PEER_TYPE_ASSOCIATED_STATION)
429 add_single_station(addr.toAscii().constData());
433 if (text.startsWith(AP_STA_DISCONNECTED)) {
434 /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */
435 QStringList items = text.split(' ');
436 QString addr = items[1];
438 if (model.rowCount() == 0)
441 QModelIndexList lst = model.match(model.index(0, 0),
442 peer_role_address, addr);
443 for (int i = 0; i < lst.size(); i++) {
444 QStandardItem *item = model.itemFromIndex(lst[i]);
445 if (item && item->data(peer_role_type).toInt() ==
446 PEER_TYPE_ASSOCIATED_STATION)
447 model.removeRow(lst[i].row());
452 if (text.startsWith(WPS_EVENT_ER_AP_ADD)) {
454 * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002|
455 * Very friendly name|Company|Long description of the model|
456 * WAP|http://w1.fi/|http://w1.fi/hostapd/
458 int pos = text.indexOf(' ');
461 QStringList items = text.mid(pos + 1).split('|');
462 if (items.size() < 2)
465 QStandardItem *item = find_uuid(items[0]);
469 item = new QStandardItem(*ap_icon, items[1]);
471 item->setData(items[0], peer_role_uuid);
472 item->setData(PEER_TYPE_WPS_ER_AP, peer_role_type);
473 item->setToolTip(items.join(QString("\n")));
474 model.appendRow(item);
480 if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) {
481 /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */
482 QStringList items = text.split(' ');
483 if (items.size() < 2)
485 if (model.rowCount() == 0)
488 QModelIndexList lst = model.match(model.index(0, 0),
489 peer_role_uuid, items[1]);
490 for (int i = 0; i < lst.size(); i++) {
491 QStandardItem *item = model.itemFromIndex(lst[i]);
492 if (item && item->data(peer_role_type).toInt() ==
494 model.removeRow(lst[i].row());
499 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) {
501 * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333
502 * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0
503 * pri_dev_type=1-0050F204-1
504 * |Wireless Client|Company|cmodel|123|12345|
506 QStringList items = text.split(' ');
507 if (items.size() < 3)
509 QString uuid = items[1];
510 QString addr = items[2];
512 int pos = text.indexOf('|');
515 items = text.mid(pos + 1).split('|');
516 if (items.size() < 1)
518 QString name = items[0];
519 if (name.length() == 0)
522 remove_enrollee_uuid(uuid);
525 item = new QStandardItem(*laptop_icon, name);
527 item->setData(uuid, peer_role_uuid);
528 item->setData(addr, peer_role_address);
529 item->setData(PEER_TYPE_WPS_ER_ENROLLEE,
531 item->setToolTip(items.join(QString("\n")));
532 model.appendRow(item);
538 if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) {
540 * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333
543 QStringList items = text.split(' ');
544 if (items.size() < 2)
546 remove_enrollee_uuid(items[1]);
552 void Peers::closeEvent(QCloseEvent *)
556 size_t replylen = sizeof(reply) - 1;
557 wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen);
562 void Peers::done(int r)
569 void Peers::remove_enrollee_uuid(QString uuid)
571 if (model.rowCount() == 0)
574 QModelIndexList lst = model.match(model.index(0, 0),
575 peer_role_uuid, uuid);
576 for (int i = 0; i < lst.size(); i++) {
577 QStandardItem *item = model.itemFromIndex(lst[i]);
578 if (item && item->data(peer_role_type).toInt() ==
579 PEER_TYPE_WPS_ER_ENROLLEE)
580 model.removeRow(lst[i].row());