Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / wpa_supplicant / wpa_gui-qt4 / peers.cpp
1 /*
2  * wpa_gui - Peers class
3  * Copyright (c) 2009-2010, Atheros Communications
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include <cstdio>
10 #include <QImageReader>
11 #include <QMessageBox>
12
13 #include "common/wpa_ctrl.h"
14 #include "wpagui.h"
15 #include "stringquery.h"
16 #include "peers.h"
17
18
19 enum {
20         peer_role_address = Qt::UserRole + 1,
21         peer_role_type,
22         peer_role_uuid,
23         peer_role_details,
24         peer_role_ifname,
25         peer_role_pri_dev_type,
26         peer_role_ssid,
27         peer_role_config_methods,
28         peer_role_dev_passwd_id,
29         peer_role_bss_id,
30         peer_role_selected_method,
31         peer_role_selected_pin,
32         peer_role_requested_method,
33         peer_role_network_id
34 };
35
36 enum selected_method {
37         SEL_METHOD_NONE,
38         SEL_METHOD_PIN_PEER_DISPLAY,
39         SEL_METHOD_PIN_LOCAL_DISPLAY
40 };
41
42 /*
43  * TODO:
44  * - add current AP info (e.g., from WPS) in station mode
45  */
46
47 enum peer_type {
48         PEER_TYPE_ASSOCIATED_STATION,
49         PEER_TYPE_AP,
50         PEER_TYPE_AP_WPS,
51         PEER_TYPE_WPS_PIN_NEEDED,
52         PEER_TYPE_P2P,
53         PEER_TYPE_P2P_CLIENT,
54         PEER_TYPE_P2P_GROUP,
55         PEER_TYPE_P2P_PERSISTENT_GROUP_GO,
56         PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT,
57         PEER_TYPE_P2P_INVITATION,
58         PEER_TYPE_WPS_ER_AP,
59         PEER_TYPE_WPS_ER_AP_UNCONFIGURED,
60         PEER_TYPE_WPS_ER_ENROLLEE,
61         PEER_TYPE_WPS_ENROLLEE
62 };
63
64
65 Peers::Peers(QWidget *parent, const char *, bool, Qt::WindowFlags)
66         : QDialog(parent)
67 {
68         setupUi(this);
69
70         if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
71         {
72                 default_icon = new QIcon(":/icons/wpa_gui.svg");
73                 ap_icon = new QIcon(":/icons/ap.svg");
74                 laptop_icon = new QIcon(":/icons/laptop.svg");
75                 group_icon = new QIcon(":/icons/group.svg");
76                 invitation_icon = new QIcon(":/icons/invitation.svg");
77         } else {
78                 default_icon = new QIcon(":/icons/wpa_gui.png");
79                 ap_icon = new QIcon(":/icons/ap.png");
80                 laptop_icon = new QIcon(":/icons/laptop.png");
81                 group_icon = new QIcon(":/icons/group.png");
82                 invitation_icon = new QIcon(":/icons/invitation.png");
83         }
84
85         peers->setModel(&model);
86         peers->setResizeMode(QListView::Adjust);
87         peers->setDragEnabled(false);
88         peers->setSelectionMode(QAbstractItemView::NoSelection);
89
90         peers->setContextMenuPolicy(Qt::CustomContextMenu);
91         connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)),
92                 this, SLOT(context_menu(const QPoint &)));
93
94         wpagui = NULL;
95         hide_ap = false;
96 }
97
98
99 void Peers::setWpaGui(WpaGui *_wpagui)
100 {
101         wpagui = _wpagui;
102         update_peers();
103 }
104
105
106 Peers::~Peers()
107 {
108         delete default_icon;
109         delete ap_icon;
110         delete laptop_icon;
111         delete group_icon;
112         delete invitation_icon;
113 }
114
115
116 void Peers::languageChange()
117 {
118         retranslateUi(this);
119 }
120
121
122 QString Peers::ItemType(int type)
123 {
124         QString title;
125         switch (type) {
126         case PEER_TYPE_ASSOCIATED_STATION:
127                 title = tr("Associated station");
128                 break;
129         case PEER_TYPE_AP:
130                 title = tr("AP");
131                 break;
132         case PEER_TYPE_AP_WPS:
133                 title = tr("WPS AP");
134                 break;
135         case PEER_TYPE_WPS_PIN_NEEDED:
136                 title = tr("WPS PIN needed");
137                 break;
138         case PEER_TYPE_P2P:
139                 title = tr("P2P Device");
140                 break;
141         case PEER_TYPE_P2P_CLIENT:
142                 title = tr("P2P Device (group client)");
143                 break;
144         case PEER_TYPE_P2P_GROUP:
145                 title = tr("P2P Group");
146                 break;
147         case PEER_TYPE_P2P_PERSISTENT_GROUP_GO:
148                 title = tr("P2P Persistent Group (GO)");
149                 break;
150         case PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT:
151                 title = tr("P2P Persistent Group (client)");
152                 break;
153         case PEER_TYPE_P2P_INVITATION:
154                 title = tr("P2P Invitation");
155                 break;
156         case PEER_TYPE_WPS_ER_AP:
157                 title = tr("ER: WPS AP");
158                 break;
159         case PEER_TYPE_WPS_ER_AP_UNCONFIGURED:
160                 title = tr("ER: WPS AP (Unconfigured)");
161                 break;
162         case PEER_TYPE_WPS_ER_ENROLLEE:
163                 title = tr("ER: WPS Enrollee");
164                 break;
165         case PEER_TYPE_WPS_ENROLLEE:
166                 title = tr("WPS Enrollee");
167                 break;
168         }
169         return title;
170 }
171
172
173 void Peers::context_menu(const QPoint &pos)
174 {
175         QMenu *menu = new QMenu;
176         if (menu == NULL)
177                 return;
178
179         QModelIndex idx = peers->indexAt(pos);
180         if (idx.isValid()) {
181                 ctx_item = model.itemFromIndex(idx);
182                 int type = ctx_item->data(peer_role_type).toInt();
183                 menu->addAction(Peers::ItemType(type))->setEnabled(false);
184                 menu->addSeparator();
185
186                 int config_methods = -1;
187                 QVariant var = ctx_item->data(peer_role_config_methods);
188                 if (var.isValid())
189                         config_methods = var.toInt();
190
191                 enum selected_method method = SEL_METHOD_NONE;
192                 var = ctx_item->data(peer_role_selected_method);
193                 if (var.isValid())
194                         method = (enum selected_method) var.toInt();
195
196                 if ((type == PEER_TYPE_ASSOCIATED_STATION ||
197                      type == PEER_TYPE_AP_WPS ||
198                      type == PEER_TYPE_WPS_PIN_NEEDED ||
199                      type == PEER_TYPE_WPS_ER_ENROLLEE ||
200                      type == PEER_TYPE_WPS_ENROLLEE) &&
201                     (config_methods == -1 || (config_methods & 0x010c))) {
202                         menu->addAction(tr("Enter WPS PIN"), this,
203                                         SLOT(enter_pin()));
204                 }
205
206                 if (type == PEER_TYPE_P2P || type == PEER_TYPE_P2P_CLIENT) {
207                         menu->addAction(tr("P2P Connect"), this,
208                                         SLOT(ctx_p2p_connect()));
209                         if (method == SEL_METHOD_NONE &&
210                             config_methods > -1 &&
211                             config_methods & 0x0080 /* PBC */ &&
212                             config_methods != 0x0080)
213                                 menu->addAction(tr("P2P Connect (PBC)"), this,
214                                                 SLOT(connect_pbc()));
215                         if (method == SEL_METHOD_NONE) {
216                                 menu->addAction(tr("P2P Request PIN"), this,
217                                                 SLOT(ctx_p2p_req_pin()));
218                                 menu->addAction(tr("P2P Show PIN"), this,
219                                                 SLOT(ctx_p2p_show_pin()));
220                         }
221
222                         if (config_methods > -1 && (config_methods & 0x0100)) {
223                                 /* Peer has Keypad */
224                                 menu->addAction(tr("P2P Display PIN"), this,
225                                                 SLOT(ctx_p2p_display_pin()));
226                         }
227
228                         if (config_methods > -1 && (config_methods & 0x000c)) {
229                                 /* Peer has Label or Display */
230                                 menu->addAction(tr("P2P Enter PIN"), this,
231                                                 SLOT(ctx_p2p_enter_pin()));
232                         }
233                 }
234
235                 if (type == PEER_TYPE_P2P_GROUP) {
236                         menu->addAction(tr("Show passphrase"), this,
237                                         SLOT(ctx_p2p_show_passphrase()));
238                         menu->addAction(tr("Remove P2P Group"), this,
239                                         SLOT(ctx_p2p_remove_group()));
240                 }
241
242                 if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
243                     type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT ||
244                     type == PEER_TYPE_P2P_INVITATION) {
245                         menu->addAction(tr("Start group"), this,
246                                         SLOT(ctx_p2p_start_persistent()));
247                 }
248
249                 if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
250                     type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) {
251                         menu->addAction(tr("Invite"), this,
252                                         SLOT(ctx_p2p_invite()));
253                 }
254
255                 if (type == PEER_TYPE_P2P_INVITATION) {
256                         menu->addAction(tr("Ignore"), this,
257                                         SLOT(ctx_p2p_delete()));
258                 }
259
260                 if (type == PEER_TYPE_AP_WPS) {
261                         menu->addAction(tr("Connect (PBC)"), this,
262                                         SLOT(connect_pbc()));
263                 }
264
265                 if ((type == PEER_TYPE_ASSOCIATED_STATION ||
266                      type == PEER_TYPE_WPS_ER_ENROLLEE ||
267                      type == PEER_TYPE_WPS_ENROLLEE) &&
268                     config_methods >= 0 && (config_methods & 0x0080)) {
269                         menu->addAction(tr("Enroll (PBC)"), this,
270                                         SLOT(connect_pbc()));
271                 }
272
273                 if (type == PEER_TYPE_WPS_ER_AP) {
274                         menu->addAction(tr("Learn Configuration"), this,
275                                         SLOT(learn_ap_config()));
276                 }
277
278                 menu->addAction(tr("Properties"), this, SLOT(properties()));
279         } else {
280                 ctx_item = NULL;
281                 menu->addAction(QString(tr("Refresh")), this,
282                                 SLOT(ctx_refresh()));
283                 menu->addAction(tr("Start P2P discovery"), this,
284                                 SLOT(ctx_p2p_start()));
285                 menu->addAction(tr("Stop P2P discovery"), this,
286                                 SLOT(ctx_p2p_stop()));
287                 menu->addAction(tr("P2P listen only"), this,
288                                 SLOT(ctx_p2p_listen()));
289                 menu->addAction(tr("Start P2P group"), this,
290                                 SLOT(ctx_p2p_start_group()));
291                 if (hide_ap)
292                         menu->addAction(tr("Show AP entries"), this,
293                                         SLOT(ctx_show_ap()));
294                 else
295                         menu->addAction(tr("Hide AP entries"), this,
296                                         SLOT(ctx_hide_ap()));
297         }
298
299         menu->exec(peers->mapToGlobal(pos));
300 }
301
302
303 void Peers::enter_pin()
304 {
305         if (ctx_item == NULL)
306                 return;
307
308         int peer_type = ctx_item->data(peer_role_type).toInt();
309         QString uuid;
310         QString addr;
311         addr = ctx_item->data(peer_role_address).toString();
312         if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE)
313                 uuid = ctx_item->data(peer_role_uuid).toString();
314
315         StringQuery input(tr("PIN:"));
316         input.setWindowTitle(tr("PIN for ") + ctx_item->text());
317         if (input.exec() != QDialog::Accepted)
318                 return;
319
320         char cmd[100];
321         char reply[100];
322         size_t reply_len;
323
324         if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
325                 snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
326                          uuid.toLocal8Bit().constData(),
327                          input.get_string().toLocal8Bit().constData(),
328                          addr.toLocal8Bit().constData());
329         } else {
330                 snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
331                          addr.toLocal8Bit().constData(),
332                          input.get_string().toLocal8Bit().constData());
333         }
334         reply_len = sizeof(reply) - 1;
335         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
336                 QMessageBox msg;
337                 msg.setIcon(QMessageBox::Warning);
338                 msg.setText(tr("Failed to set the WPS PIN."));
339                 msg.exec();
340         }
341 }
342
343
344 void Peers::ctx_refresh()
345 {
346         update_peers();
347 }
348
349
350 void Peers::ctx_p2p_start()
351 {
352         char reply[20];
353         size_t reply_len;
354         reply_len = sizeof(reply) - 1;
355         if (wpagui->ctrlRequest("P2P_FIND", reply, &reply_len) < 0 ||
356             memcmp(reply, "FAIL", 4) == 0) {
357                 QMessageBox msg;
358                 msg.setIcon(QMessageBox::Warning);
359                 msg.setText("Failed to start P2P discovery.");
360                 msg.exec();
361         }
362 }
363
364
365 void Peers::ctx_p2p_stop()
366 {
367         char reply[20];
368         size_t reply_len;
369         reply_len = sizeof(reply) - 1;
370         wpagui->ctrlRequest("P2P_STOP_FIND", reply, &reply_len);
371 }
372
373
374 void Peers::ctx_p2p_listen()
375 {
376         char reply[20];
377         size_t reply_len;
378         reply_len = sizeof(reply) - 1;
379         if (wpagui->ctrlRequest("P2P_LISTEN 3600", reply, &reply_len) < 0 ||
380             memcmp(reply, "FAIL", 4) == 0) {
381                 QMessageBox msg;
382                 msg.setIcon(QMessageBox::Warning);
383                 msg.setText("Failed to start P2P listen.");
384                 msg.exec();
385         }
386 }
387
388
389 void Peers::ctx_p2p_start_group()
390 {
391         char reply[20];
392         size_t reply_len;
393         reply_len = sizeof(reply) - 1;
394         if (wpagui->ctrlRequest("P2P_GROUP_ADD", reply, &reply_len) < 0 ||
395             memcmp(reply, "FAIL", 4) == 0) {
396                 QMessageBox msg;
397                 msg.setIcon(QMessageBox::Warning);
398                 msg.setText("Failed to start P2P group.");
399                 msg.exec();
400         }
401 }
402
403
404 void Peers::add_station(QString info)
405 {
406         QStringList lines = info.split(QRegExp("\\n"));
407         QString name;
408
409         for (QStringList::Iterator it = lines.begin();
410              it != lines.end(); it++) {
411                 int pos = (*it).indexOf('=') + 1;
412                 if (pos < 1)
413                         continue;
414
415                 if ((*it).startsWith("wpsDeviceName="))
416                         name = (*it).mid(pos);
417                 else if ((*it).startsWith("p2p_device_name="))
418                         name = (*it).mid(pos);
419         }
420
421         if (name.isEmpty())
422                 name = lines[0];
423
424         QStandardItem *item = new QStandardItem(*laptop_icon, name);
425         if (item) {
426                 /* Remove WPS enrollee entry if one is still pending */
427                 if (model.rowCount() > 0) {
428                         QModelIndexList lst = model.match(model.index(0, 0),
429                                                           peer_role_address,
430                                                           lines[0]);
431                         for (int i = 0; i < lst.size(); i++) {
432                                 QStandardItem *item;
433                                 item = model.itemFromIndex(lst[i]);
434                                 if (item == NULL)
435                                         continue;
436                                 int type = item->data(peer_role_type).toInt();
437                                 if (type == PEER_TYPE_WPS_ENROLLEE) {
438                                         model.removeRow(lst[i].row());
439                                         break;
440                                 }
441                         }
442                 }
443
444                 item->setData(lines[0], peer_role_address);
445                 item->setData(PEER_TYPE_ASSOCIATED_STATION,
446                               peer_role_type);
447                 item->setData(info, peer_role_details);
448                 item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION));
449                 model.appendRow(item);
450         }
451 }
452
453
454 void Peers::add_stations()
455 {
456         char reply[2048];
457         size_t reply_len;
458         char cmd[30];
459         int res;
460
461         reply_len = sizeof(reply) - 1;
462         if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0)
463                 return;
464
465         do {
466                 reply[reply_len] = '\0';
467                 QString info(reply);
468                 char *txt = reply;
469                 while (*txt != '\0' && *txt != '\n')
470                         txt++;
471                 *txt++ = '\0';
472                 if (strncmp(reply, "FAIL", 4) == 0 ||
473                     strncmp(reply, "UNKNOWN", 7) == 0)
474                         break;
475
476                 add_station(info);
477
478                 reply_len = sizeof(reply) - 1;
479                 snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
480                 res = wpagui->ctrlRequest(cmd, reply, &reply_len);
481         } while (res >= 0);
482 }
483
484
485 void Peers::add_single_station(const char *addr)
486 {
487         char reply[2048];
488         size_t reply_len;
489         char cmd[30];
490
491         reply_len = sizeof(reply) - 1;
492         snprintf(cmd, sizeof(cmd), "STA %s", addr);
493         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
494                 return;
495
496         reply[reply_len] = '\0';
497         QString info(reply);
498         char *txt = reply;
499         while (*txt != '\0' && *txt != '\n')
500                 txt++;
501         *txt++ = '\0';
502         if (strncmp(reply, "FAIL", 4) == 0 ||
503             strncmp(reply, "UNKNOWN", 7) == 0)
504                 return;
505
506         add_station(info);
507 }
508
509
510 void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params)
511 {
512         /*
513          * dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0
514          * dev_type=1-0050f204-1 dev_name='Wireless Client'
515          * config_methods=0x8c
516          */
517
518         QStringList items =
519                 params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
520         QString addr = "";
521         QString name = "";
522         int config_methods = 0;
523         QString dev_type;
524
525         for (int i = 0; i < items.size(); i++) {
526                 QString str = items.at(i);
527                 int pos = str.indexOf('=') + 1;
528                 if (str.startsWith("dev_name='"))
529                         name = str.section('\'', 1, -2);
530                 else if (str.startsWith("config_methods="))
531                         config_methods =
532                                 str.section('=', 1).toInt(0, 0);
533                 else if (str.startsWith("dev="))
534                         addr = str.mid(pos);
535                 else if (str.startsWith("dev_type=") && dev_type.isEmpty())
536                         dev_type = str.mid(pos);
537         }
538
539         QStandardItem *item = find_addr(addr);
540         if (item)
541                 return;
542
543         item = new QStandardItem(*default_icon, name);
544         if (item) {
545                 /* TODO: indicate somehow the relationship to the group owner
546                  * (parent) */
547                 item->setData(addr, peer_role_address);
548                 item->setData(config_methods, peer_role_config_methods);
549                 item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type);
550                 if (!dev_type.isEmpty())
551                         item->setData(dev_type, peer_role_pri_dev_type);
552                 item->setData(items.join(QString("\n")), peer_role_details);
553                 item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT));
554                 model.appendRow(item);
555         }
556 }
557
558
559 void Peers::remove_bss(int id)
560 {
561         if (model.rowCount() == 0)
562                 return;
563
564         QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id,
565                                           id);
566         if (lst.size() == 0)
567                 return;
568         model.removeRow(lst[0].row());
569 }
570
571
572 bool Peers::add_bss(const char *cmd)
573 {
574         char reply[2048];
575         size_t reply_len;
576
577         if (hide_ap)
578                 return false;
579
580         reply_len = sizeof(reply) - 1;
581         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
582                 return false;
583         reply[reply_len] = '\0';
584
585         QString bss(reply);
586         if (bss.isEmpty() || bss.startsWith("FAIL"))
587                 return false;
588
589         QString ssid, bssid, flags, wps_name, pri_dev_type;
590         int id = -1;
591
592         QStringList lines = bss.split(QRegExp("\\n"));
593         for (QStringList::Iterator it = lines.begin();
594              it != lines.end(); it++) {
595                 int pos = (*it).indexOf('=') + 1;
596                 if (pos < 1)
597                         continue;
598
599                 if ((*it).startsWith("bssid="))
600                         bssid = (*it).mid(pos);
601                 else if ((*it).startsWith("id="))
602                         id = (*it).mid(pos).toInt();
603                 else if ((*it).startsWith("flags="))
604                         flags = (*it).mid(pos);
605                 else if ((*it).startsWith("ssid="))
606                         ssid = (*it).mid(pos);
607                 else if ((*it).startsWith("wps_device_name="))
608                         wps_name = (*it).mid(pos);
609                 else if ((*it).startsWith("wps_primary_device_type="))
610                         pri_dev_type = (*it).mid(pos);
611         }
612
613         QString name = wps_name;
614         if (name.isEmpty())
615                 name = ssid + "\n" + bssid;
616
617         QStandardItem *item = new QStandardItem(*ap_icon, name);
618         if (item) {
619                 item->setData(bssid, peer_role_address);
620                 if (id >= 0)
621                         item->setData(id, peer_role_bss_id);
622                 int type;
623                 if (flags.contains("[WPS"))
624                         type = PEER_TYPE_AP_WPS;
625                 else
626                         type = PEER_TYPE_AP;
627                 item->setData(type, peer_role_type);
628
629                 for (int i = 0; i < lines.size(); i++) {
630                         if (lines[i].length() > 60) {
631                                 lines[i].remove(60, lines[i].length());
632                                 lines[i] += "..";
633                         }
634                 }
635                 item->setToolTip(ItemType(type));
636                 item->setData(lines.join("\n"), peer_role_details);
637                 if (!pri_dev_type.isEmpty())
638                         item->setData(pri_dev_type,
639                                       peer_role_pri_dev_type);
640                 if (!ssid.isEmpty())
641                         item->setData(ssid, peer_role_ssid);
642                 model.appendRow(item);
643
644                 lines = bss.split(QRegExp("\\n"));
645                 for (QStringList::Iterator it = lines.begin();
646                      it != lines.end(); it++) {
647                         if ((*it).startsWith("p2p_group_client:"))
648                                 add_p2p_group_client(item,
649                                                      (*it).mid(18));
650                 }
651         }
652
653         return true;
654 }
655
656
657 void Peers::add_scan_results()
658 {
659         int index;
660         char cmd[20];
661
662         index = 0;
663         while (wpagui) {
664                 snprintf(cmd, sizeof(cmd), "BSS %d", index++);
665                 if (index > 1000)
666                         break;
667
668                 if (!add_bss(cmd))
669                         break;
670         }
671 }
672
673
674 void Peers::add_persistent(int id, const char *ssid, const char *bssid)
675 {
676         char cmd[100];
677         char reply[100];
678         size_t reply_len;
679         int mode;
680
681         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id);
682         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
683                 return;
684         reply[reply_len] = '\0';
685         mode = atoi(reply);
686
687         QString name = ssid;
688         name = '[' + name + ']';
689
690         QStandardItem *item = new QStandardItem(*group_icon, name);
691         if (!item)
692                 return;
693
694         int type;
695         if (mode == 3)
696                 type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO;
697         else
698                 type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT;
699         item->setData(type, peer_role_type);
700         item->setToolTip(ItemType(type));
701         item->setData(ssid, peer_role_ssid);
702         if (bssid && strcmp(bssid, "any") == 0)
703                 bssid = NULL;
704         if (bssid)
705                 item->setData(bssid, peer_role_address);
706         item->setData(id, peer_role_network_id);
707         item->setBackground(Qt::BDiagPattern);
708
709         model.appendRow(item);
710 }
711
712
713 void Peers::add_persistent_groups()
714 {
715         char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
716         size_t len;
717
718         len = sizeof(buf) - 1;
719         if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
720                 return;
721
722         buf[len] = '\0';
723         start = strchr(buf, '\n');
724         if (start == NULL)
725                 return;
726         start++;
727
728         while (*start) {
729                 bool last = false;
730                 end = strchr(start, '\n');
731                 if (end == NULL) {
732                         last = true;
733                         end = start;
734                         while (end[0] && end[1])
735                                 end++;
736                 }
737                 *end = '\0';
738
739                 id = start;
740                 ssid = strchr(id, '\t');
741                 if (ssid == NULL)
742                         break;
743                 *ssid++ = '\0';
744                 bssid = strchr(ssid, '\t');
745                 if (bssid == NULL)
746                         break;
747                 *bssid++ = '\0';
748                 flags = strchr(bssid, '\t');
749                 if (flags == NULL)
750                         break;
751                 *flags++ = '\0';
752
753                 if (strstr(flags, "[DISABLED][P2P-PERSISTENT]"))
754                         add_persistent(atoi(id), ssid, bssid);
755
756                 if (last)
757                         break;
758                 start = end + 1;
759         }
760 }
761
762
763 void Peers::update_peers()
764 {
765         model.clear();
766         if (wpagui == NULL)
767                 return;
768
769         char reply[20];
770         size_t replylen = sizeof(reply) - 1;
771         wpagui->ctrlRequest("WPS_ER_START", reply, &replylen);
772
773         add_stations();
774         add_scan_results();
775         add_persistent_groups();
776 }
777
778
779 QStandardItem * Peers::find_addr(QString addr)
780 {
781         if (model.rowCount() == 0)
782                 return NULL;
783
784         QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
785                                           addr);
786         if (lst.size() == 0)
787                 return NULL;
788         return model.itemFromIndex(lst[0]);
789 }
790
791
792 QStandardItem * Peers::find_addr_type(QString addr, int type)
793 {
794         if (model.rowCount() == 0)
795                 return NULL;
796
797         QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
798                                           addr);
799         for (int i = 0; i < lst.size(); i++) {
800                 QStandardItem *item = model.itemFromIndex(lst[i]);
801                 if (item->data(peer_role_type).toInt() == type)
802                         return item;
803         }
804         return NULL;
805 }
806
807
808 QStandardItem * Peers::find_uuid(QString uuid)
809 {
810         if (model.rowCount() == 0)
811                 return NULL;
812
813         QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid,
814                                           uuid);
815         if (lst.size() == 0)
816                 return NULL;
817         return model.itemFromIndex(lst[0]);
818 }
819
820
821 void Peers::event_notify(WpaMsg msg)
822 {
823         QString text = msg.getMsg();
824
825         if (text.startsWith(WPS_EVENT_PIN_NEEDED)) {
826                 /*
827                  * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7
828                  * 02:2a:c4:18:5b:f3
829                  * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
830                  */
831                 QStringList items = text.split(' ');
832                 QString uuid = items[1];
833                 QString addr = items[2];
834                 QString name = "";
835
836                 QStandardItem *item = find_addr(addr);
837                 if (item)
838                         return;
839
840                 int pos = text.indexOf('[');
841                 if (pos >= 0) {
842                         int pos2 = text.lastIndexOf(']');
843                         if (pos2 >= pos) {
844                                 items = text.mid(pos + 1, pos2 - pos - 1).
845                                         split('|');
846                                 name = items[0];
847                                 items.append(addr);
848                         }
849                 }
850
851                 item = new QStandardItem(*laptop_icon, name);
852                 if (item) {
853                         item->setData(addr, peer_role_address);
854                         item->setData(PEER_TYPE_WPS_PIN_NEEDED,
855                                       peer_role_type);
856                         item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED));
857                         item->setData(items.join("\n"), peer_role_details);
858                         item->setData(items[5], peer_role_pri_dev_type);
859                         model.appendRow(item);
860                 }
861                 return;
862         }
863
864         if (text.startsWith(AP_STA_CONNECTED)) {
865                 /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */
866                 QStringList items = text.split(' ');
867                 QString addr = items[1];
868                 QStandardItem *item = find_addr(addr);
869                 if (item == NULL || item->data(peer_role_type).toInt() !=
870                     PEER_TYPE_ASSOCIATED_STATION)
871                         add_single_station(addr.toLocal8Bit().constData());
872                 return;
873         }
874
875         if (text.startsWith(AP_STA_DISCONNECTED)) {
876                 /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */
877                 QStringList items = text.split(' ');
878                 QString addr = items[1];
879
880                 if (model.rowCount() == 0)
881                         return;
882
883                 QModelIndexList lst = model.match(model.index(0, 0),
884                                                   peer_role_address, addr, -1);
885                 for (int i = 0; i < lst.size(); i++) {
886                         QStandardItem *item = model.itemFromIndex(lst[i]);
887                         if (item && item->data(peer_role_type).toInt() ==
888                             PEER_TYPE_ASSOCIATED_STATION) {
889                                 model.removeRow(lst[i].row());
890                                 break;
891                         }
892                 }
893                 return;
894         }
895
896         if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) {
897                 /*
898                  * P2P-DEVICE-FOUND 02:b5:64:63:30:63
899                  * p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1
900                  * name='Wireless Client' config_methods=0x84 dev_capab=0x21
901                  * group_capab=0x0
902                  */
903                 QStringList items =
904                         text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
905                 QString addr = items[1];
906                 QString name = "";
907                 QString pri_dev_type;
908                 int config_methods = 0;
909                 for (int i = 0; i < items.size(); i++) {
910                         QString str = items.at(i);
911                         if (str.startsWith("name='"))
912                                 name = str.section('\'', 1, -2);
913                         else if (str.startsWith("config_methods="))
914                                 config_methods =
915                                         str.section('=', 1).toInt(0, 0);
916                         else if (str.startsWith("pri_dev_type="))
917                                 pri_dev_type = str.section('=', 1);
918                 }
919
920                 QStandardItem *item = find_addr(addr);
921                 if (item) {
922                         int type = item->data(peer_role_type).toInt();
923                         if (type == PEER_TYPE_P2P)
924                                 return;
925                 }
926
927                 item = new QStandardItem(*default_icon, name);
928                 if (item) {
929                         item->setData(addr, peer_role_address);
930                         item->setData(config_methods,
931                                       peer_role_config_methods);
932                         item->setData(PEER_TYPE_P2P, peer_role_type);
933                         if (!pri_dev_type.isEmpty())
934                                 item->setData(pri_dev_type,
935                                               peer_role_pri_dev_type);
936                         item->setData(items.join(QString("\n")),
937                                       peer_role_details);
938                         item->setToolTip(ItemType(PEER_TYPE_P2P));
939                         model.appendRow(item);
940                 }
941
942                 item = find_addr_type(addr,
943                                       PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT);
944                 if (item)
945                         item->setBackground(Qt::NoBrush);
946         }
947
948         if (text.startsWith(P2P_EVENT_GROUP_STARTED)) {
949                 /* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F"
950                  * passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7
951                  * [PERSISTENT] */
952                 QStringList items = text.split(' ');
953                 if (items.size() < 4)
954                         return;
955
956                 int pos = text.indexOf(" ssid=\"");
957                 if (pos < 0)
958                         return;
959                 QString ssid = text.mid(pos + 7);
960                 pos = ssid.indexOf(" passphrase=\"");
961                 if (pos < 0)
962                         pos = ssid.indexOf(" psk=");
963                 if (pos >= 0)
964                         ssid.truncate(pos);
965                 pos = ssid.lastIndexOf('"');
966                 if (pos >= 0)
967                         ssid.truncate(pos);
968
969                 QStandardItem *item = new QStandardItem(*group_icon, ssid);
970                 if (item) {
971                         item->setData(PEER_TYPE_P2P_GROUP, peer_role_type);
972                         item->setData(items[1], peer_role_ifname);
973                         QString details;
974                         if (items[2] == "GO") {
975                                 details = tr("P2P GO for interface ") +
976                                         items[1];
977                         } else {
978                                 details = tr("P2P client for interface ") +
979                                         items[1];
980                         }
981                         if (text.contains(" [PERSISTENT]"))
982                                 details += "\nPersistent group";
983                         item->setData(details, peer_role_details);
984                         item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP));
985                         model.appendRow(item);
986                 }
987         }
988
989         if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) {
990                 /* P2P-GROUP-REMOVED wlan0-p2p-0 GO */
991                 QStringList items = text.split(' ');
992                 if (items.size() < 2)
993                         return;
994
995                 if (model.rowCount() == 0)
996                         return;
997
998                 QModelIndexList lst = model.match(model.index(0, 0),
999                                                   peer_role_ifname, items[1]);
1000                 for (int i = 0; i < lst.size(); i++)
1001                         model.removeRow(lst[i].row());
1002                 return;
1003         }
1004
1005         if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) {
1006                 /* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */
1007                 QStringList items = text.split(' ');
1008                 if (items.size() < 3)
1009                         return;
1010                 QString addr = items[1];
1011                 QString pin = items[2];
1012
1013                 QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P);
1014                 if (item == NULL)
1015                         return;
1016                 item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY,
1017                               peer_role_selected_method);
1018                 item->setData(pin, peer_role_selected_pin);
1019                 QVariant var = item->data(peer_role_requested_method);
1020                 if (var.isValid() &&
1021                     var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) {
1022                         ctx_item = item;
1023                         ctx_p2p_display_pin_pd();
1024                 }
1025                 return;
1026         }
1027
1028         if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) {
1029                 /* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */
1030                 QStringList items = text.split(' ');
1031                 if (items.size() < 2)
1032                         return;
1033                 QString addr = items[1];
1034
1035                 QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P);
1036                 if (item == NULL)
1037                         return;
1038                 item->setData(SEL_METHOD_PIN_PEER_DISPLAY,
1039                               peer_role_selected_method);
1040                 QVariant var = item->data(peer_role_requested_method);
1041                 if (var.isValid() &&
1042                     var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) {
1043                         ctx_item = item;
1044                         ctx_p2p_connect();
1045                 }
1046                 return;
1047         }
1048
1049         if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) {
1050                 /* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */
1051                 QStringList items = text.split(' ');
1052                 if (items.size() < 3)
1053                         return;
1054                 if (!items[1].startsWith("sa=") ||
1055                     !items[2].startsWith("persistent="))
1056                         return;
1057                 QString addr = items[1].mid(3);
1058                 int id = items[2].mid(11).toInt();
1059
1060                 char cmd[100];
1061                 char reply[100];
1062                 size_t reply_len;
1063
1064                 snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id);
1065                 reply_len = sizeof(reply) - 1;
1066                 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
1067                         return;
1068                 reply[reply_len] = '\0';
1069                 QString name;
1070                 char *pos = strrchr(reply, '"');
1071                 if (pos && reply[0] == '"') {
1072                         *pos = '\0';
1073                         name = reply + 1;
1074                 } else
1075                         name = reply;
1076
1077                 QStandardItem *item;
1078                 item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION);
1079                 if (item)
1080                         model.removeRow(item->row());
1081
1082                 item = new QStandardItem(*invitation_icon, name);
1083                 if (!item)
1084                         return;
1085                 item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type);
1086                 item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION));
1087                 item->setData(addr, peer_role_address);
1088                 item->setData(id, peer_role_network_id);
1089
1090                 model.appendRow(item);
1091
1092                 enable_persistent(id);
1093
1094                 return;
1095         }
1096
1097         if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) {
1098                 /* P2P-INVITATION-RESULT status=1 */
1099                 /* TODO */
1100                 return;
1101         }
1102
1103         if (text.startsWith(WPS_EVENT_ER_AP_ADD)) {
1104                 /*
1105                  * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002
1106                  * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1
1107                  * |Very friendly name|Company|Long description of the model|
1108                  * WAP|http://w1.fi/|http://w1.fi/hostapd/
1109                  */
1110                 QStringList items = text.split(' ');
1111                 if (items.size() < 5)
1112                         return;
1113                 QString uuid = items[1];
1114                 QString addr = items[2];
1115                 QString pri_dev_type = items[3].mid(13);
1116                 int wps_state = items[4].mid(10).toInt();
1117
1118                 int pos = text.indexOf('|');
1119                 if (pos < 0)
1120                         return;
1121                 items = text.mid(pos + 1).split('|');
1122                 if (items.size() < 1)
1123                         return;
1124
1125                 QStandardItem *item = find_uuid(uuid);
1126                 if (item)
1127                         return;
1128
1129                 item = new QStandardItem(*ap_icon, items[0]);
1130                 if (item) {
1131                         item->setData(uuid, peer_role_uuid);
1132                         item->setData(addr, peer_role_address);
1133                         int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP:
1134                                 PEER_TYPE_WPS_ER_AP_UNCONFIGURED;
1135                         item->setData(type, peer_role_type);
1136                         item->setToolTip(ItemType(type));
1137                         item->setData(pri_dev_type, peer_role_pri_dev_type);
1138                         item->setData(items.join(QString("\n")),
1139                                       peer_role_details);
1140                         model.appendRow(item);
1141                 }
1142
1143                 return;
1144         }
1145
1146         if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) {
1147                 /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */
1148                 QStringList items = text.split(' ');
1149                 if (items.size() < 2)
1150                         return;
1151                 if (model.rowCount() == 0)
1152                         return;
1153
1154                 QModelIndexList lst = model.match(model.index(0, 0),
1155                                                   peer_role_uuid, items[1]);
1156                 for (int i = 0; i < lst.size(); i++) {
1157                         QStandardItem *item = model.itemFromIndex(lst[i]);
1158                         if (item &&
1159                             (item->data(peer_role_type).toInt() ==
1160                              PEER_TYPE_WPS_ER_AP ||
1161                              item->data(peer_role_type).toInt() ==
1162                              PEER_TYPE_WPS_ER_AP_UNCONFIGURED))
1163                                 model.removeRow(lst[i].row());
1164                 }
1165                 return;
1166         }
1167
1168         if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) {
1169                 /*
1170                  * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333
1171                  * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0
1172                  * pri_dev_type=1-0050F204-1
1173                  * |Wireless Client|Company|cmodel|123|12345|
1174                  */
1175                 QStringList items = text.split(' ');
1176                 if (items.size() < 3)
1177                         return;
1178                 QString uuid = items[1];
1179                 QString addr = items[2];
1180                 QString pri_dev_type = items[6].mid(13);
1181                 int config_methods = -1;
1182                 int dev_passwd_id = -1;
1183
1184                 for (int i = 3; i < items.size(); i++) {
1185                         int pos = items[i].indexOf('=') + 1;
1186                         if (pos < 1)
1187                                 continue;
1188                         QString val = items[i].mid(pos);
1189                         if (items[i].startsWith("config_methods=")) {
1190                                 config_methods = val.toInt(0, 0);
1191                         } else if (items[i].startsWith("dev_passwd_id=")) {
1192                                 dev_passwd_id = val.toInt();
1193                         }
1194                 }
1195
1196                 int pos = text.indexOf('|');
1197                 if (pos < 0)
1198                         return;
1199                 items = text.mid(pos + 1).split('|');
1200                 if (items.size() < 1)
1201                         return;
1202                 QString name = items[0];
1203                 if (name.length() == 0)
1204                         name = addr;
1205
1206                 remove_enrollee_uuid(uuid);
1207
1208                 QStandardItem *item;
1209                 item = new QStandardItem(*laptop_icon, name);
1210                 if (item) {
1211                         item->setData(uuid, peer_role_uuid);
1212                         item->setData(addr, peer_role_address);
1213                         item->setData(PEER_TYPE_WPS_ER_ENROLLEE,
1214                                       peer_role_type);
1215                         item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE));
1216                         item->setData(items.join(QString("\n")),
1217                                       peer_role_details);
1218                         item->setData(pri_dev_type, peer_role_pri_dev_type);
1219                         if (config_methods >= 0)
1220                                 item->setData(config_methods,
1221                                               peer_role_config_methods);
1222                         if (dev_passwd_id >= 0)
1223                                 item->setData(dev_passwd_id,
1224                                               peer_role_dev_passwd_id);
1225                         model.appendRow(item);
1226                 }
1227
1228                 return;
1229         }
1230
1231         if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) {
1232                 /*
1233                  * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333
1234                  * 02:66:a0:ee:17:27
1235                  */
1236                 QStringList items = text.split(' ');
1237                 if (items.size() < 2)
1238                         return;
1239                 remove_enrollee_uuid(items[1]);
1240                 return;
1241         }
1242
1243         if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) {
1244                 /* TODO: need to time out this somehow or remove on successful
1245                  * WPS run, etc. */
1246                 /*
1247                  * WPS-ENROLLEE-SEEN 02:00:00:00:01:00
1248                  * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1
1249                  * [Wireless Client]
1250                  * (MAC addr, UUID-E, pri dev type, config methods,
1251                  * dev passwd id, request type, [dev name])
1252                  */
1253                 QStringList items = text.split(' ');
1254                 if (items.size() < 7)
1255                         return;
1256                 QString addr = items[1];
1257                 QString uuid = items[2];
1258                 QString pri_dev_type = items[3];
1259                 int config_methods = items[4].toInt(0, 0);
1260                 int dev_passwd_id = items[5].toInt();
1261                 QString name;
1262
1263                 QStandardItem *item = find_addr(addr);
1264                 if (item) {
1265                         int type = item->data(peer_role_type).toInt();
1266                         if (type == PEER_TYPE_ASSOCIATED_STATION)
1267                                 return; /* already associated */
1268                 }
1269
1270                 int pos = text.indexOf('[');
1271                 if (pos >= 0) {
1272                         int pos2 = text.lastIndexOf(']');
1273                         if (pos2 >= pos) {
1274                                 QStringList items2 =
1275                                         text.mid(pos + 1, pos2 - pos - 1).
1276                                         split('|');
1277                                 name = items2[0];
1278                         }
1279                 }
1280                 if (name.isEmpty())
1281                         name = addr;
1282
1283                 item = find_uuid(uuid);
1284                 if (item) {
1285                         QVariant var = item->data(peer_role_config_methods);
1286                         QVariant var2 = item->data(peer_role_dev_passwd_id);
1287                         if ((var.isValid() && config_methods != var.toInt()) ||
1288                             (var2.isValid() && dev_passwd_id != var2.toInt()))
1289                                 remove_enrollee_uuid(uuid);
1290                         else
1291                                 return;
1292                 }
1293
1294                 item = new QStandardItem(*laptop_icon, name);
1295                 if (item) {
1296                         item->setData(uuid, peer_role_uuid);
1297                         item->setData(addr, peer_role_address);
1298                         item->setData(PEER_TYPE_WPS_ENROLLEE,
1299                                       peer_role_type);
1300                         item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE));
1301                         item->setData(items.join(QString("\n")),
1302                                       peer_role_details);
1303                         item->setData(pri_dev_type, peer_role_pri_dev_type);
1304                         item->setData(config_methods,
1305                                       peer_role_config_methods);
1306                         item->setData(dev_passwd_id, peer_role_dev_passwd_id);
1307                         model.appendRow(item);
1308                 }
1309
1310                 return;
1311         }
1312
1313         if (text.startsWith(WPA_EVENT_BSS_ADDED)) {
1314                 /* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */
1315                 QStringList items = text.split(' ');
1316                 if (items.size() < 2)
1317                         return;
1318                 char cmd[20];
1319                 snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt());
1320                 add_bss(cmd);
1321                 return;
1322         }
1323
1324         if (text.startsWith(WPA_EVENT_BSS_REMOVED)) {
1325                 /* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */
1326                 QStringList items = text.split(' ');
1327                 if (items.size() < 2)
1328                         return;
1329                 remove_bss(items[1].toInt());
1330                 return;
1331         }
1332 }
1333
1334
1335 void Peers::ctx_p2p_connect()
1336 {
1337         if (ctx_item == NULL)
1338                 return;
1339         QString addr = ctx_item->data(peer_role_address).toString();
1340         QString arg;
1341         int config_methods =
1342                 ctx_item->data(peer_role_config_methods).toInt();
1343         enum selected_method method = SEL_METHOD_NONE;
1344         QVariant var = ctx_item->data(peer_role_selected_method);
1345         if (var.isValid())
1346                 method = (enum selected_method) var.toInt();
1347         if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) {
1348                 arg = ctx_item->data(peer_role_selected_pin).toString();
1349                 char cmd[100];
1350                 char reply[100];
1351                 size_t reply_len;
1352                 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display",
1353                          addr.toLocal8Bit().constData(),
1354                          arg.toLocal8Bit().constData());
1355                 reply_len = sizeof(reply) - 1;
1356                 if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1357                         QMessageBox msg;
1358                         msg.setIcon(QMessageBox::Warning);
1359                         msg.setText("Failed to initiate P2P connect.");
1360                         msg.exec();
1361                         return;
1362                 }
1363                 QMessageBox::information(this,
1364                                          tr("PIN for ") + ctx_item->text(),
1365                                          tr("Enter the following PIN on the\n"
1366                                             "peer device: ") + arg);
1367         } else if (method == SEL_METHOD_PIN_PEER_DISPLAY) {
1368                 StringQuery input(tr("PIN from peer display:"));
1369                 input.setWindowTitle(tr("PIN for ") + ctx_item->text());
1370                 if (input.exec() != QDialog::Accepted)
1371                         return;
1372                 arg = input.get_string();
1373         } else if (config_methods == 0x0080 /* PBC */) {
1374                 arg = "pbc";
1375         } else {
1376                 StringQuery input(tr("PIN:"));
1377                 input.setWindowTitle(tr("PIN for ") + ctx_item->text());
1378                 if (input.exec() != QDialog::Accepted)
1379                         return;
1380                 arg = input.get_string();
1381         }
1382
1383         char cmd[100];
1384         char reply[100];
1385         size_t reply_len;
1386         snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s",
1387                  addr.toLocal8Bit().constData(),
1388                  arg.toLocal8Bit().constData());
1389         reply_len = sizeof(reply) - 1;
1390         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1391                 QMessageBox msg;
1392                 msg.setIcon(QMessageBox::Warning);
1393                 msg.setText("Failed to initiate P2P connect.");
1394                 msg.exec();
1395         }
1396 }
1397
1398
1399 void Peers::ctx_p2p_req_pin()
1400 {
1401         if (ctx_item == NULL)
1402                 return;
1403         QString addr = ctx_item->data(peer_role_address).toString();
1404         ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY,
1405                           peer_role_requested_method);
1406
1407         char cmd[100];
1408         char reply[100];
1409         size_t reply_len;
1410         snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display",
1411                  addr.toLocal8Bit().constData());
1412         reply_len = sizeof(reply) - 1;
1413         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1414                 QMessageBox msg;
1415                 msg.setIcon(QMessageBox::Warning);
1416                 msg.setText(tr("Failed to request PIN from peer."));
1417                 msg.exec();
1418         }
1419 }
1420
1421
1422 void Peers::ctx_p2p_show_pin()
1423 {
1424         if (ctx_item == NULL)
1425                 return;
1426         QString addr = ctx_item->data(peer_role_address).toString();
1427         ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY,
1428                           peer_role_requested_method);
1429
1430         char cmd[100];
1431         char reply[100];
1432         size_t reply_len;
1433         snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad",
1434                  addr.toLocal8Bit().constData());
1435         reply_len = sizeof(reply) - 1;
1436         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1437                 QMessageBox msg;
1438                 msg.setIcon(QMessageBox::Warning);
1439                 msg.setText(tr("Failed to request peer to enter PIN."));
1440                 msg.exec();
1441         }
1442 }
1443
1444
1445 void Peers::ctx_p2p_display_pin()
1446 {
1447         if (ctx_item == NULL)
1448                 return;
1449         QString addr = ctx_item->data(peer_role_address).toString();
1450
1451         char cmd[100];
1452         char reply[100];
1453         size_t reply_len;
1454         snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin",
1455                  addr.toLocal8Bit().constData());
1456         reply_len = sizeof(reply) - 1;
1457         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1458                 QMessageBox msg;
1459                 msg.setIcon(QMessageBox::Warning);
1460                 msg.setText("Failed to initiate P2P connect.");
1461                 msg.exec();
1462                 return;
1463         }
1464         reply[reply_len] = '\0';
1465         QMessageBox::information(this,
1466                                  tr("PIN for ") + ctx_item->text(),
1467                                  tr("Enter the following PIN on the\n"
1468                                     "peer device: ") + reply);
1469 }
1470
1471
1472 void Peers::ctx_p2p_display_pin_pd()
1473 {
1474         if (ctx_item == NULL)
1475                 return;
1476         QString addr = ctx_item->data(peer_role_address).toString();
1477         QString arg = ctx_item->data(peer_role_selected_pin).toString();
1478
1479         char cmd[100];
1480         char reply[100];
1481         size_t reply_len;
1482         snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display",
1483                  addr.toLocal8Bit().constData(),
1484                  arg.toLocal8Bit().constData());
1485         reply_len = sizeof(reply) - 1;
1486         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1487                 QMessageBox msg;
1488                 msg.setIcon(QMessageBox::Warning);
1489                 msg.setText("Failed to initiate P2P connect.");
1490                 msg.exec();
1491                 return;
1492         }
1493         reply[reply_len] = '\0';
1494         QMessageBox::information(this,
1495                                  tr("PIN for ") + ctx_item->text(),
1496                                  tr("Enter the following PIN on the\n"
1497                                     "peer device: ") + arg);
1498 }
1499
1500
1501 void Peers::ctx_p2p_enter_pin()
1502 {
1503         if (ctx_item == NULL)
1504                 return;
1505         QString addr = ctx_item->data(peer_role_address).toString();
1506         QString arg;
1507
1508         StringQuery input(tr("PIN from peer:"));
1509         input.setWindowTitle(tr("PIN for ") + ctx_item->text());
1510         if (input.exec() != QDialog::Accepted)
1511                 return;
1512         arg = input.get_string();
1513
1514         char cmd[100];
1515         char reply[100];
1516         size_t reply_len;
1517         snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad",
1518                  addr.toLocal8Bit().constData(),
1519                  arg.toLocal8Bit().constData());
1520         reply_len = sizeof(reply) - 1;
1521         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1522                 QMessageBox msg;
1523                 msg.setIcon(QMessageBox::Warning);
1524                 msg.setText("Failed to initiate P2P connect.");
1525                 msg.exec();
1526         }
1527 }
1528
1529
1530 void Peers::ctx_p2p_remove_group()
1531 {
1532         if (ctx_item == NULL)
1533                 return;
1534         char cmd[100];
1535         char reply[100];
1536         size_t reply_len;
1537         snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s",
1538                  ctx_item->data(peer_role_ifname).toString().toLocal8Bit().
1539                  constData());
1540         reply_len = sizeof(reply) - 1;
1541         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1542                 QMessageBox msg;
1543                 msg.setIcon(QMessageBox::Warning);
1544                 msg.setText("Failed to remove P2P Group.");
1545                 msg.exec();
1546         }
1547 }
1548
1549
1550 void Peers::closeEvent(QCloseEvent *)
1551 {
1552         if (wpagui) {
1553                 char reply[20];
1554                 size_t replylen = sizeof(reply) - 1;
1555                 wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen);
1556         }
1557 }
1558
1559
1560 void Peers::done(int r)
1561 {
1562         QDialog::done(r);
1563         close();
1564 }
1565
1566
1567 void Peers::remove_enrollee_uuid(QString uuid)
1568 {
1569         if (model.rowCount() == 0)
1570                 return;
1571
1572         QModelIndexList lst = model.match(model.index(0, 0),
1573                                           peer_role_uuid, uuid);
1574         for (int i = 0; i < lst.size(); i++) {
1575                 QStandardItem *item = model.itemFromIndex(lst[i]);
1576                 if (item == NULL)
1577                         continue;
1578                 int type = item->data(peer_role_type).toInt();
1579                 if (type == PEER_TYPE_WPS_ER_ENROLLEE ||
1580                     type == PEER_TYPE_WPS_ENROLLEE)
1581                         model.removeRow(lst[i].row());
1582         }
1583 }
1584
1585
1586 void Peers::properties()
1587 {
1588         if (ctx_item == NULL)
1589                 return;
1590
1591         QMessageBox msg(this);
1592         msg.setStandardButtons(QMessageBox::Ok);
1593         msg.setDefaultButton(QMessageBox::Ok);
1594         msg.setEscapeButton(QMessageBox::Ok);
1595         msg.setWindowTitle(tr("Peer Properties"));
1596
1597         int type = ctx_item->data(peer_role_type).toInt();
1598         QString title = Peers::ItemType(type);
1599
1600         msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text());
1601
1602         QVariant var;
1603         QString info;
1604
1605         var = ctx_item->data(peer_role_address);
1606         if (var.isValid())
1607                 info += tr("Address: ") + var.toString() + QString("\n");
1608
1609         var = ctx_item->data(peer_role_uuid);
1610         if (var.isValid())
1611                 info += tr("UUID: ") + var.toString() + QString("\n");
1612
1613         var = ctx_item->data(peer_role_pri_dev_type);
1614         if (var.isValid())
1615                 info += tr("Primary Device Type: ") + var.toString() +
1616                         QString("\n");
1617
1618         var = ctx_item->data(peer_role_ssid);
1619         if (var.isValid())
1620                 info += tr("SSID: ") + var.toString() + QString("\n");
1621
1622         var = ctx_item->data(peer_role_config_methods);
1623         if (var.isValid()) {
1624                 int methods = var.toInt();
1625                 info += tr("Configuration Methods: ");
1626                 if (methods & 0x0001)
1627                         info += tr("[USBA]");
1628                 if (methods & 0x0002)
1629                         info += tr("[Ethernet]");
1630                 if (methods & 0x0004)
1631                         info += tr("[Label]");
1632                 if (methods & 0x0008)
1633                         info += tr("[Display]");
1634                 if (methods & 0x0010)
1635                         info += tr("[Ext. NFC Token]");
1636                 if (methods & 0x0020)
1637                         info += tr("[Int. NFC Token]");
1638                 if (methods & 0x0040)
1639                         info += tr("[NFC Interface]");
1640                 if (methods & 0x0080)
1641                         info += tr("[Push Button]");
1642                 if (methods & 0x0100)
1643                         info += tr("[Keypad]");
1644                 info += "\n";
1645         }
1646
1647         var = ctx_item->data(peer_role_selected_method);
1648         if (var.isValid()) {
1649                 enum selected_method method =
1650                         (enum selected_method) var.toInt();
1651                 switch (method) {
1652                 case SEL_METHOD_NONE:
1653                         break;
1654                 case SEL_METHOD_PIN_PEER_DISPLAY:
1655                         info += tr("Selected Method: PIN on peer display\n");
1656                         break;
1657                 case SEL_METHOD_PIN_LOCAL_DISPLAY:
1658                         info += tr("Selected Method: PIN on local display\n");
1659                         break;
1660                 }
1661         }
1662
1663         var = ctx_item->data(peer_role_selected_pin);
1664         if (var.isValid()) {
1665                 info += tr("PIN to enter on peer: ") + var.toString() + "\n";
1666         }
1667
1668         var = ctx_item->data(peer_role_dev_passwd_id);
1669         if (var.isValid()) {
1670                 info += tr("Device Password ID: ") + var.toString();
1671                 switch (var.toInt()) {
1672                 case 0:
1673                         info += tr(" (Default PIN)");
1674                         break;
1675                 case 1:
1676                         info += tr(" (User-specified PIN)");
1677                         break;
1678                 case 2:
1679                         info += tr(" (Machine-specified PIN)");
1680                         break;
1681                 case 3:
1682                         info += tr(" (Rekey)");
1683                         break;
1684                 case 4:
1685                         info += tr(" (Push Button)");
1686                         break;
1687                 case 5:
1688                         info += tr(" (Registrar-specified)");
1689                         break;
1690                 }
1691                 info += "\n";
1692         }
1693
1694         msg.setInformativeText(info);
1695
1696         var = ctx_item->data(peer_role_details);
1697         if (var.isValid())
1698                 msg.setDetailedText(var.toString());
1699
1700         msg.exec();
1701 }
1702
1703
1704 void Peers::connect_pbc()
1705 {
1706         if (ctx_item == NULL)
1707                 return;
1708
1709         char cmd[100];
1710         char reply[100];
1711         size_t reply_len;
1712
1713         int peer_type = ctx_item->data(peer_role_type).toInt();
1714         if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
1715                 snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
1716                          ctx_item->data(peer_role_uuid).toString().toLocal8Bit().
1717                          constData());
1718         } else if (peer_type == PEER_TYPE_P2P ||
1719                    peer_type == PEER_TYPE_P2P_CLIENT) {
1720                 snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc",
1721                          ctx_item->data(peer_role_address).toString().
1722                          toLocal8Bit().constData());
1723         } else {
1724                 snprintf(cmd, sizeof(cmd), "WPS_PBC");
1725         }
1726         reply_len = sizeof(reply) - 1;
1727         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1728                 QMessageBox msg;
1729                 msg.setIcon(QMessageBox::Warning);
1730                 msg.setText(tr("Failed to start WPS PBC."));
1731                 msg.exec();
1732         }
1733 }
1734
1735
1736 void Peers::learn_ap_config()
1737 {
1738         if (ctx_item == NULL)
1739                 return;
1740
1741         QString uuid = ctx_item->data(peer_role_uuid).toString();
1742
1743         StringQuery input(tr("AP PIN:"));
1744         input.setWindowTitle(tr("AP PIN for ") + ctx_item->text());
1745         if (input.exec() != QDialog::Accepted)
1746                 return;
1747
1748         char cmd[100];
1749         char reply[100];
1750         size_t reply_len;
1751
1752         snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
1753                  uuid.toLocal8Bit().constData(),
1754                  input.get_string().toLocal8Bit().constData());
1755         reply_len = sizeof(reply) - 1;
1756         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
1757                 QMessageBox msg;
1758                 msg.setIcon(QMessageBox::Warning);
1759                 msg.setText(tr("Failed to start learning AP configuration."));
1760                 msg.exec();
1761         }
1762 }
1763
1764
1765 void Peers::ctx_hide_ap()
1766 {
1767         hide_ap = true;
1768
1769         if (model.rowCount() == 0)
1770                 return;
1771
1772         do {
1773                 QModelIndexList lst;
1774                 lst = model.match(model.index(0, 0),
1775                                   peer_role_type, PEER_TYPE_AP);
1776                 if (lst.size() == 0) {
1777                         lst = model.match(model.index(0, 0),
1778                                           peer_role_type, PEER_TYPE_AP_WPS);
1779                         if (lst.size() == 0)
1780                                 break;
1781                 }
1782
1783                 model.removeRow(lst[0].row());
1784         } while (1);
1785 }
1786
1787
1788 void Peers::ctx_show_ap()
1789 {
1790         hide_ap = false;
1791         add_scan_results();
1792 }
1793
1794
1795 void Peers::ctx_p2p_show_passphrase()
1796 {
1797         char reply[64];
1798         size_t reply_len;
1799
1800         reply_len = sizeof(reply) - 1;
1801         if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 ||
1802             memcmp(reply, "FAIL", 4) == 0) {
1803                 QMessageBox msg;
1804                 msg.setIcon(QMessageBox::Warning);
1805                 msg.setText("Failed to get P2P group passphrase.");
1806                 msg.exec();
1807         } else {
1808                 reply[reply_len] = '\0';
1809                 QMessageBox::information(this, tr("Passphrase"),
1810                                          tr("P2P group passphrase:\n") +
1811                                          reply);
1812         }
1813 }
1814
1815
1816 void Peers::ctx_p2p_start_persistent()
1817 {
1818         if (ctx_item == NULL)
1819                 return;
1820
1821         char cmd[100];
1822         char reply[100];
1823         size_t reply_len;
1824
1825         snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d",
1826                  ctx_item->data(peer_role_network_id).toInt());
1827         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 ||
1828             memcmp(reply, "FAIL", 4) == 0) {
1829                 QMessageBox msg;
1830                 msg.setIcon(QMessageBox::Warning);
1831                 msg.setText(tr("Failed to start persistent P2P Group."));
1832                 msg.exec();
1833         } else if (ctx_item->data(peer_role_type).toInt() ==
1834                    PEER_TYPE_P2P_INVITATION)
1835                 model.removeRow(ctx_item->row());
1836 }
1837
1838
1839 void Peers::ctx_p2p_invite()
1840 {
1841         if (ctx_item == NULL)
1842                 return;
1843
1844         char cmd[100];
1845         char reply[100];
1846         size_t reply_len;
1847
1848         snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d",
1849                  ctx_item->data(peer_role_network_id).toInt());
1850         if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 ||
1851             memcmp(reply, "FAIL", 4) == 0) {
1852                 QMessageBox msg;
1853                 msg.setIcon(QMessageBox::Warning);
1854                 msg.setText(tr("Failed to invite peer to start persistent "
1855                                "P2P Group."));
1856                 msg.exec();
1857         }
1858 }
1859
1860
1861 void Peers::ctx_p2p_delete()
1862 {
1863         if (ctx_item == NULL)
1864                 return;
1865         model.removeRow(ctx_item->row());
1866 }
1867
1868
1869 void Peers::enable_persistent(int id)
1870 {
1871         if (model.rowCount() == 0)
1872                 return;
1873
1874         QModelIndexList lst = model.match(model.index(0, 0),
1875                                           peer_role_network_id, id);
1876         for (int i = 0; i < lst.size(); i++) {
1877                 QStandardItem *item = model.itemFromIndex(lst[i]);
1878                 int type = item->data(peer_role_type).toInt();
1879                 if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO ||
1880                     type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT)
1881                         item->setBackground(Qt::NoBrush);
1882         }
1883 }