d1439e234d58dd425a760ed7ae1d52eca3216872
[mech_eap.git] / wpa_supplicant / wpa_gui-qt4 / peers.cpp
1 /*
2  * wpa_gui - Peers class
3  * Copyright (c) 2009, Atheros Communications
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include <cstdio>
16 #include <QImageReader>
17 #include <QMessageBox>
18
19 #include "common/wpa_ctrl.h"
20 #include "wpagui.h"
21 #include "stringquery.h"
22 #include "peers.h"
23
24
25 enum {
26         peer_role_address = Qt::UserRole + 1,
27         peer_role_type,
28         peer_role_uuid,
29         peer_role_details,
30         peer_role_pri_dev_type,
31         peer_role_ssid,
32         peer_role_config_methods,
33         peer_role_dev_passwd_id
34 };
35
36 /*
37  * TODO:
38  * - add current AP info (e.g., from WPS) in station mode
39  */
40
41 enum peer_type {
42         PEER_TYPE_ASSOCIATED_STATION,
43         PEER_TYPE_AP,
44         PEER_TYPE_AP_WPS,
45         PEER_TYPE_WPS_PIN_NEEDED,
46         PEER_TYPE_WPS_ER_AP,
47         PEER_TYPE_WPS_ER_AP_UNCONFIGURED,
48         PEER_TYPE_WPS_ER_ENROLLEE
49 };
50
51
52 Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags)
53         : QDialog(parent)
54 {
55         setupUi(this);
56
57         if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
58         {
59                 default_icon = new QIcon(":/icons/wpa_gui.svg");
60                 ap_icon = new QIcon(":/icons/ap.svg");
61                 laptop_icon = new QIcon(":/icons/laptop.svg");
62         } else {
63                 default_icon = new QIcon(":/icons/wpa_gui.png");
64                 ap_icon = new QIcon(":/icons/ap.png");
65                 laptop_icon = new QIcon(":/icons/laptop.png");
66         }
67
68         peers->setModel(&model);
69         peers->setResizeMode(QListView::Adjust);
70
71         peers->setContextMenuPolicy(Qt::CustomContextMenu);
72         connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)),
73                 this, SLOT(context_menu(const QPoint &)));
74
75         wpagui = NULL;
76 }
77
78
79 void Peers::setWpaGui(WpaGui *_wpagui)
80 {
81         wpagui = _wpagui;
82         update_peers();
83 }
84
85
86 Peers::~Peers()
87 {
88         delete default_icon;
89         delete ap_icon;
90         delete laptop_icon;
91 }
92
93
94 void Peers::languageChange()
95 {
96         retranslateUi(this);
97 }
98
99
100 QString Peers::ItemType(int type)
101 {
102         QString title;
103         switch (type) {
104         case PEER_TYPE_ASSOCIATED_STATION:
105                 title = tr("Associated station");
106                 break;
107         case PEER_TYPE_AP:
108                 title = tr("AP");
109                 break;
110         case PEER_TYPE_AP_WPS:
111                 title = tr("WPS AP");
112                 break;
113         case PEER_TYPE_WPS_PIN_NEEDED:
114                 title = tr("WPS PIN needed");
115                 break;
116         case PEER_TYPE_WPS_ER_AP:
117                 title = tr("ER: WPS AP");
118                 break;
119         case PEER_TYPE_WPS_ER_AP_UNCONFIGURED:
120                 title = tr("ER: WPS AP (Unconfigured)");
121                 break;
122         case PEER_TYPE_WPS_ER_ENROLLEE:
123                 title = tr("ER: WPS Enrollee");
124                 break;
125         }
126         return title;
127 }
128
129
130 void Peers::context_menu(const QPoint &pos)
131 {
132         QMenu *menu = new QMenu;
133         if (menu == NULL)
134                 return;
135
136         QModelIndex idx = peers->indexAt(pos);
137         if (idx.isValid()) {
138                 ctx_item = model.itemFromIndex(idx);
139                 int type = ctx_item->data(peer_role_type).toInt();
140                 menu->addAction(Peers::ItemType(type))->setEnabled(false);
141                 menu->addSeparator();
142
143                 int config_methods = -1;
144                 QVariant var = ctx_item->data(peer_role_config_methods);
145                 if (var.isValid())
146                         config_methods = var.toInt();
147
148                 if ((type == PEER_TYPE_ASSOCIATED_STATION ||
149                      type == PEER_TYPE_AP_WPS ||
150                      type == PEER_TYPE_WPS_PIN_NEEDED ||
151                      type == PEER_TYPE_WPS_ER_ENROLLEE) &&
152                     (config_methods == -1 || (config_methods & 0x010c))) {
153                         menu->addAction(tr("Enter WPS PIN"), this,
154                                         SLOT(enter_pin()));
155                 }
156
157                 if (type == PEER_TYPE_AP_WPS) {
158                         menu->addAction(tr("Connect (PBC)"), this,
159                                         SLOT(connect_pbc()));
160                 }
161
162                 if ((type == PEER_TYPE_ASSOCIATED_STATION ||
163                      type == PEER_TYPE_WPS_ER_ENROLLEE) &&
164                     config_methods >= 0 && (config_methods & 0x0080)) {
165                         menu->addAction(tr("Enroll (PBC)"), this,
166                                         SLOT(connect_pbc()));
167                 }
168
169                 if (type == PEER_TYPE_WPS_ER_AP) {
170                         menu->addAction(tr("Learn Configuration"), this,
171                                         SLOT(learn_ap_config()));
172                 }
173
174                 menu->addAction(tr("Properties"), this, SLOT(properties()));
175         } else {
176                 ctx_item = NULL;
177                 menu->addAction(QString("Refresh"), this, SLOT(ctx_refresh()));
178         }
179
180         menu->exec(peers->mapToGlobal(pos));
181 }
182
183
184 void Peers::enter_pin()
185 {
186         if (ctx_item == NULL)
187                 return;
188
189         int peer_type = ctx_item->data(peer_role_type).toInt();
190         QString uuid;
191         QString addr;
192         if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE)
193                 uuid = ctx_item->data(peer_role_uuid).toString();
194         else
195                 addr = ctx_item->data(peer_role_address).toString();
196
197         StringQuery input(tr("PIN:"));
198         input.setWindowTitle(tr("PIN for ") + ctx_item->text());
199         if (input.exec() != QDialog::Accepted)
200                 return;
201
202         char cmd[100];
203         char reply[100];
204         size_t reply_len;
205
206         if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
207                 snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
208                          uuid.toAscii().constData(),
209                          input.get_string().toAscii().constData());
210         } else {
211                 snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
212                          addr.toAscii().constData(),
213                          input.get_string().toAscii().constData());
214         }
215         reply_len = sizeof(reply) - 1;
216         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
217                 QMessageBox msg;
218                 msg.setIcon(QMessageBox::Warning);
219                 msg.setText("Failed to set the WPS PIN.");
220                 msg.exec();
221         }
222 }
223
224
225 void Peers::ctx_refresh()
226 {
227         update_peers();
228 }
229
230
231 void Peers::add_station(QString info)
232 {
233         QStringList lines = info.split(QRegExp("\\n"));
234         QString name;
235
236         for (QStringList::Iterator it = lines.begin();
237              it != lines.end(); it++) {
238                 int pos = (*it).indexOf('=') + 1;
239                 if (pos < 1)
240                         continue;
241
242                 if ((*it).startsWith("wpsDeviceName="))
243                         name = (*it).mid(pos);
244         }
245
246         if (name.isEmpty())
247                 name = lines[0];
248
249         QStandardItem *item = new QStandardItem(*laptop_icon, name);
250         if (item) {
251                 item->setData(lines[0], peer_role_address);
252                 item->setData(PEER_TYPE_ASSOCIATED_STATION,
253                               peer_role_type);
254                 item->setData(info, peer_role_details);
255                 item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION));
256                 model.appendRow(item);
257         }
258 }
259
260
261 void Peers::add_stations()
262 {
263         char reply[2048];
264         size_t reply_len;
265         char cmd[30];
266         int res;
267
268         reply_len = sizeof(reply) - 1;
269         if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0)
270                 return;
271
272         do {
273                 reply[reply_len] = '\0';
274                 QString info(reply);
275                 char *txt = reply;
276                 while (*txt != '\0' && *txt != '\n')
277                         txt++;
278                 *txt++ = '\0';
279                 if (strncmp(reply, "FAIL", 4) == 0 ||
280                     strncmp(reply, "UNKNOWN", 7) == 0)
281                         break;
282
283                 add_station(info);
284
285                 reply_len = sizeof(reply) - 1;
286                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
287                 res = wpagui->ctrlRequest(cmd, reply, &reply_len);
288         } while (res >= 0);
289 }
290
291
292 void Peers::add_single_station(const char *addr)
293 {
294         char reply[2048];
295         size_t reply_len;
296         char cmd[30];
297
298         reply_len = sizeof(reply) - 1;
299         snprintf(cmd, sizeof(cmd), "STA %s", addr);
300         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
301                 return;
302
303         reply[reply_len] = '\0';
304         QString info(reply);
305         char *txt = reply;
306         while (*txt != '\0' && *txt != '\n')
307                 txt++;
308         *txt++ = '\0';
309         if (strncmp(reply, "FAIL", 4) == 0 ||
310             strncmp(reply, "UNKNOWN", 7) == 0)
311                 return;
312
313         add_station(info);
314 }
315
316
317 void Peers::add_scan_results()
318 {
319         char reply[2048];
320         size_t reply_len;
321         int index;
322         char cmd[20];
323
324         index = 0;
325         while (wpagui) {
326                 snprintf(cmd, sizeof(cmd), "BSS %d", index++);
327                 if (index > 1000)
328                         break;
329
330                 reply_len = sizeof(reply) - 1;
331                 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
332                         break;
333                 reply[reply_len] = '\0';
334
335                 QString bss(reply);
336                 if (bss.isEmpty() || bss.startsWith("FAIL"))
337                         break;
338
339                 QString ssid, bssid, flags, wps_name, pri_dev_type;
340
341                 QStringList lines = bss.split(QRegExp("\\n"));
342                 for (QStringList::Iterator it = lines.begin();
343                      it != lines.end(); it++) {
344                         int pos = (*it).indexOf('=') + 1;
345                         if (pos < 1)
346                                 continue;
347
348                         if ((*it).startsWith("bssid="))
349                                 bssid = (*it).mid(pos);
350                         else if ((*it).startsWith("flags="))
351                                 flags = (*it).mid(pos);
352                         else if ((*it).startsWith("ssid="))
353                                 ssid = (*it).mid(pos);
354                         else if ((*it).startsWith("wps_device_name="))
355                                 wps_name = (*it).mid(pos);
356                         else if ((*it).startsWith("wps_primary_device_type="))
357                                 pri_dev_type = (*it).mid(pos);
358                 }
359
360                 QString name = wps_name;
361                 if (name.isEmpty())
362                         name = ssid + "\n" + bssid;
363
364                 QStandardItem *item = new QStandardItem(*ap_icon, name);
365                 if (item) {
366                         item->setData(bssid, peer_role_address);
367                         int type;
368                         if (flags.contains("[WPS"))
369                                 type = PEER_TYPE_AP_WPS;
370                         else
371                                 type = PEER_TYPE_AP;
372                         item->setData(type, peer_role_type);
373
374                         for (int i = 0; i < lines.size(); i++) {
375                                 if (lines[i].length() > 60) {
376                                         lines[i].remove(
377                                                 60, lines[i].length());
378                                         lines[i] += "..";
379                                 }
380                         }
381                         item->setToolTip(ItemType(type));
382                         item->setData(lines.join("\n"), peer_role_details);
383                         if (!pri_dev_type.isEmpty())
384                                 item->setData(pri_dev_type,
385                                               peer_role_pri_dev_type);
386                         if (!ssid.isEmpty())
387                                 item->setData(ssid, peer_role_ssid);
388                         model.appendRow(item);
389                 }
390         }
391 }
392
393
394 void Peers::update_peers()
395 {
396         model.clear();
397         if (wpagui == NULL)
398                 return;
399
400         char reply[20];
401         size_t replylen = sizeof(reply) - 1;
402         wpagui->ctrlRequest("WPS_ER_START", reply, &replylen);
403
404         add_stations();
405         add_scan_results();
406 }
407
408
409 QStandardItem * Peers::find_addr(QString addr)
410 {
411         if (model.rowCount() == 0)
412                 return NULL;
413
414         QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
415                                           addr);
416         if (lst.size() == 0)
417                 return NULL;
418         return model.itemFromIndex(lst[0]);
419 }
420
421
422 QStandardItem * Peers::find_uuid(QString uuid)
423 {
424         if (model.rowCount() == 0)
425                 return NULL;
426
427         QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid,
428                                           uuid);
429         if (lst.size() == 0)
430                 return NULL;
431         return model.itemFromIndex(lst[0]);
432 }
433
434
435 void Peers::event_notify(WpaMsg msg)
436 {
437         QString text = msg.getMsg();
438
439         if (text.startsWith(WPS_EVENT_PIN_NEEDED)) {
440                 /*
441                  * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7
442                  * 02:2a:c4:18:5b:f3
443                  * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
444                  */
445                 QStringList items = text.split(' ');
446                 QString uuid = items[1];
447                 QString addr = items[2];
448                 QString name = "";
449
450                 QStandardItem *item = find_addr(addr);
451                 if (item)
452                         return;
453
454                 int pos = text.indexOf('[');
455                 if (pos >= 0) {
456                         int pos2 = text.lastIndexOf(']');
457                         if (pos2 >= pos) {
458                                 items = text.mid(pos + 1, pos2 - pos - 1).
459                                         split('|');
460                                 name = items[0];
461                                 items.append(addr);
462                         }
463                 }
464
465                 item = new QStandardItem(*laptop_icon, name);
466                 if (item) {
467                         item->setData(addr, peer_role_address);
468                         item->setData(PEER_TYPE_WPS_PIN_NEEDED,
469                                       peer_role_type);
470                         item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED));
471                         item->setData(items.join("\n"), peer_role_details);
472                         item->setData(items[5], peer_role_pri_dev_type);
473                         model.appendRow(item);
474                 }
475                 return;
476         }
477
478         if (text.startsWith(AP_STA_CONNECTED)) {
479                 /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */
480                 QStringList items = text.split(' ');
481                 QString addr = items[1];
482                 QStandardItem *item = find_addr(addr);
483                 if (item == NULL || item->data(peer_role_type).toInt() !=
484                     PEER_TYPE_ASSOCIATED_STATION)
485                         add_single_station(addr.toAscii().constData());
486                 return;
487         }
488
489         if (text.startsWith(AP_STA_DISCONNECTED)) {
490                 /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */
491                 QStringList items = text.split(' ');
492                 QString addr = items[1];
493
494                 if (model.rowCount() == 0)
495                         return;
496
497                 QModelIndexList lst = model.match(model.index(0, 0),
498                                                   peer_role_address, addr);
499                 for (int i = 0; i < lst.size(); i++) {
500                         QStandardItem *item = model.itemFromIndex(lst[i]);
501                         if (item && item->data(peer_role_type).toInt() ==
502                             PEER_TYPE_ASSOCIATED_STATION)
503                                 model.removeRow(lst[i].row());
504                 }
505                 return;
506         }
507
508         if (text.startsWith(WPS_EVENT_ER_AP_ADD)) {
509                 /*
510                  * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002
511                  * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1
512                  * |Very friendly name|Company|Long description of the model|
513                  * WAP|http://w1.fi/|http://w1.fi/hostapd/
514                  */
515                 QStringList items = text.split(' ');
516                 if (items.size() < 5)
517                         return;
518                 QString uuid = items[1];
519                 QString addr = items[2];
520                 QString pri_dev_type = items[3].mid(13);
521                 int wps_state = items[4].mid(10).toInt();
522
523                 int pos = text.indexOf('|');
524                 if (pos < 0)
525                         return;
526                 items = text.mid(pos + 1).split('|');
527                 if (items.size() < 1)
528                         return;
529
530                 QStandardItem *item = find_uuid(uuid);
531                 if (item)
532                         return;
533
534                 item = new QStandardItem(*ap_icon, items[0]);
535                 if (item) {
536                         item->setData(uuid, peer_role_uuid);
537                         item->setData(addr, peer_role_address);
538                         int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP:
539                                 PEER_TYPE_WPS_ER_AP_UNCONFIGURED;
540                         item->setData(type, peer_role_type);
541                         item->setToolTip(ItemType(type));
542                         item->setData(pri_dev_type, peer_role_pri_dev_type);
543                         item->setData(items.join(QString("\n")),
544                                       peer_role_details);
545                         model.appendRow(item);
546                 }
547
548                 return;
549         }
550
551         if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) {
552                 /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */
553                 QStringList items = text.split(' ');
554                 if (items.size() < 2)
555                         return;
556                 if (model.rowCount() == 0)
557                         return;
558
559                 QModelIndexList lst = model.match(model.index(0, 0),
560                                                   peer_role_uuid, items[1]);
561                 for (int i = 0; i < lst.size(); i++) {
562                         QStandardItem *item = model.itemFromIndex(lst[i]);
563                         if (item &&
564                             (item->data(peer_role_type).toInt() ==
565                              PEER_TYPE_WPS_ER_AP ||
566                              item->data(peer_role_type).toInt() ==
567                              PEER_TYPE_WPS_ER_AP_UNCONFIGURED))
568                                 model.removeRow(lst[i].row());
569                 }
570                 return;
571         }
572
573         if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) {
574                 /*
575                  * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333
576                  * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0
577                  * pri_dev_type=1-0050F204-1
578                  * |Wireless Client|Company|cmodel|123|12345|
579                  */
580                 QStringList items = text.split(' ');
581                 if (items.size() < 3)
582                         return;
583                 QString uuid = items[1];
584                 QString addr = items[2];
585                 QString pri_dev_type = items[6].mid(13);
586                 int config_methods = -1;
587                 int dev_passwd_id = -1;
588
589                 for (int i = 3; i < items.size(); i++) {
590                         int pos = items[i].indexOf('=') + 1;
591                         if (pos < 1)
592                                 continue;
593                         QString val = items[i].mid(pos);
594                         if (items[i].startsWith("config_methods=")) {
595                                 config_methods = val.toInt(0, 0);
596                         } else if (items[i].startsWith("dev_passwd_id=")) {
597                                 dev_passwd_id = val.toInt();
598                         }
599                 }
600
601                 int pos = text.indexOf('|');
602                 if (pos < 0)
603                         return;
604                 items = text.mid(pos + 1).split('|');
605                 if (items.size() < 1)
606                         return;
607                 QString name = items[0];
608                 if (name.length() == 0)
609                         name = addr;
610
611                 remove_enrollee_uuid(uuid);
612
613                 QStandardItem *item;
614                 item = new QStandardItem(*laptop_icon, name);
615                 if (item) {
616                         item->setData(uuid, peer_role_uuid);
617                         item->setData(addr, peer_role_address);
618                         item->setData(PEER_TYPE_WPS_ER_ENROLLEE,
619                                       peer_role_type);
620                         item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE));
621                         item->setData(items.join(QString("\n")),
622                                       peer_role_details);
623                         item->setData(pri_dev_type, peer_role_pri_dev_type);
624                         if (config_methods >= 0)
625                                 item->setData(config_methods,
626                                               peer_role_config_methods);
627                         if (dev_passwd_id >= 0)
628                                 item->setData(dev_passwd_id,
629                                               peer_role_dev_passwd_id);
630                         model.appendRow(item);
631                 }
632
633                 return;
634         }
635
636         if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) {
637                 /*
638                  * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333
639                  * 02:66:a0:ee:17:27
640                  */
641                 QStringList items = text.split(' ');
642                 if (items.size() < 2)
643                         return;
644                 remove_enrollee_uuid(items[1]);
645                 return;
646         }
647 }
648
649
650 void Peers::closeEvent(QCloseEvent *)
651 {
652         if (wpagui) {
653                 char reply[20];
654                 size_t replylen = sizeof(reply) - 1;
655                 wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen);
656         }
657 }
658
659
660 void Peers::done(int r)
661 {
662         QDialog::done(r);
663         close();
664 }
665
666
667 void Peers::remove_enrollee_uuid(QString uuid)
668 {
669         if (model.rowCount() == 0)
670                 return;
671
672         QModelIndexList lst = model.match(model.index(0, 0),
673                                           peer_role_uuid, uuid);
674         for (int i = 0; i < lst.size(); i++) {
675                 QStandardItem *item = model.itemFromIndex(lst[i]);
676                 if (item && item->data(peer_role_type).toInt() ==
677                     PEER_TYPE_WPS_ER_ENROLLEE)
678                         model.removeRow(lst[i].row());
679         }
680 }
681
682
683 void Peers::properties()
684 {
685         if (ctx_item == NULL)
686                 return;
687
688         QMessageBox msg(this);
689         msg.setStandardButtons(QMessageBox::Ok);
690         msg.setDefaultButton(QMessageBox::Ok);
691         msg.setEscapeButton(QMessageBox::Ok);
692         msg.setWindowTitle(tr("Peer Properties"));
693
694         int type = ctx_item->data(peer_role_type).toInt();
695         QString title = Peers::ItemType(type);
696
697         msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text());
698
699         QVariant var;
700         QString info;
701
702         var = ctx_item->data(peer_role_address);
703         if (var.isValid())
704                 info += tr("Address: ") + var.toString() + QString("\n");
705
706         var = ctx_item->data(peer_role_uuid);
707         if (var.isValid())
708                 info += tr("UUID: ") + var.toString() + QString("\n");
709
710         var = ctx_item->data(peer_role_pri_dev_type);
711         if (var.isValid())
712                 info += tr("Primary Device Type: ") + var.toString() +
713                         QString("\n");
714
715         var = ctx_item->data(peer_role_ssid);
716         if (var.isValid())
717                 info += tr("SSID: ") + var.toString() + QString("\n");
718
719         var = ctx_item->data(peer_role_config_methods);
720         if (var.isValid()) {
721                 int methods = var.toInt();
722                 info += tr("Configuration Methods: ");
723                 if (methods & 0x0001)
724                         info += tr("[USBA]");
725                 if (methods & 0x0002)
726                         info += tr("[Ethernet]");
727                 if (methods & 0x0004)
728                         info += tr("[Label]");
729                 if (methods & 0x0008)
730                         info += tr("[Display]");
731                 if (methods & 0x0010)
732                         info += tr("[Ext. NFC Token]");
733                 if (methods & 0x0020)
734                         info += tr("[Int. NFC Token]");
735                 if (methods & 0x0040)
736                         info += tr("[NFC Interface]");
737                 if (methods & 0x0080)
738                         info += tr("[Push Button]");
739                 if (methods & 0x0100)
740                         info += tr("[Keypad]");
741                 info += "\n";
742         }
743
744         var = ctx_item->data(peer_role_dev_passwd_id);
745         if (var.isValid()) {
746                 info += tr("Device Password ID: ") + var.toString();
747                 switch (var.toInt()) {
748                 case 0:
749                         info += tr(" (Default PIN)");
750                         break;
751                 case 1:
752                         info += tr(" (User-specified PIN)");
753                         break;
754                 case 2:
755                         info += tr(" (Machine-specified PIN)");
756                         break;
757                 case 3:
758                         info += tr(" (Rekey)");
759                         break;
760                 case 4:
761                         info += tr(" (Push Button)");
762                         break;
763                 case 5:
764                         info += tr(" (Registrar-specified)");
765                         break;
766                 }
767                 info += "\n";
768         }
769
770         msg.setInformativeText(info);
771
772         var = ctx_item->data(peer_role_details);
773         if (var.isValid())
774                 msg.setDetailedText(var.toString());
775
776         msg.exec();
777 }
778
779
780 void Peers::connect_pbc()
781 {
782         if (ctx_item == NULL)
783                 return;
784
785         char cmd[100];
786         char reply[100];
787         size_t reply_len;
788
789         int peer_type = ctx_item->data(peer_role_type).toInt();
790         if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
791                 snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
792                          ctx_item->data(peer_role_uuid).toString().toAscii().
793                          constData());
794         } else {
795                 snprintf(cmd, sizeof(cmd), "WPS_PBC");
796         }
797         reply_len = sizeof(reply) - 1;
798         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
799                 QMessageBox msg;
800                 msg.setIcon(QMessageBox::Warning);
801                 msg.setText("Failed to start WPS PBC.");
802                 msg.exec();
803         }
804 }
805
806
807 void Peers::learn_ap_config()
808 {
809         if (ctx_item == NULL)
810                 return;
811
812         QString uuid = ctx_item->data(peer_role_uuid).toString();
813
814         StringQuery input(tr("AP PIN:"));
815         input.setWindowTitle(tr("AP PIN for ") + ctx_item->text());
816         if (input.exec() != QDialog::Accepted)
817                 return;
818
819         char cmd[100];
820         char reply[100];
821         size_t reply_len;
822
823         snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
824                  uuid.toAscii().constData(),
825                  input.get_string().toAscii().constData());
826         reply_len = sizeof(reply) - 1;
827         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
828                 QMessageBox msg;
829                 msg.setIcon(QMessageBox::Warning);
830                 msg.setText(tr("Failed to start learning AP configuration."));
831                 msg.exec();
832         }
833 }