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