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