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