peers.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * wpa_gui - Peers class
  3. * Copyright (c) 2009, Atheros Communications
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include <cstdio>
  15. #include <QImageReader>
  16. #include <QMessageBox>
  17. #include "wpagui.h"
  18. #include "stringquery.h"
  19. #include "peers.h"
  20. static const int peer_role_address = Qt::UserRole + 1;
  21. static const int peer_role_type = Qt::UserRole + 2;
  22. /*
  23. * TODO:
  24. * - add pending WPS queries (from M1/PIN, PBC?)
  25. * - add current AP info (e.g., from WPS) in station mode
  26. * - different icons to indicate peer type
  27. */
  28. enum peer_type {
  29. PEER_TYPE_ASSOCIATED_STATION,
  30. PEER_TYPE_AP,
  31. PEER_TYPE_AP_WPS,
  32. };
  33. Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags)
  34. : QDialog(parent)
  35. {
  36. setupUi(this);
  37. if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
  38. default_icon = new QIcon(":/icons/wpa_gui.svg");
  39. else
  40. default_icon = new QIcon(":/icons/wpa_gui.png");
  41. peers->setModel(&model);
  42. peers->setResizeMode(QListView::Adjust);
  43. peers->setContextMenuPolicy(Qt::CustomContextMenu);
  44. connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)),
  45. this, SLOT(context_menu(const QPoint &)));
  46. wpagui = NULL;
  47. }
  48. void Peers::setWpaGui(WpaGui *_wpagui)
  49. {
  50. wpagui = _wpagui;
  51. update_peers();
  52. }
  53. Peers::~Peers()
  54. {
  55. delete default_icon;
  56. }
  57. void Peers::languageChange()
  58. {
  59. retranslateUi(this);
  60. }
  61. void Peers::context_menu(const QPoint &pos)
  62. {
  63. QMenu *menu = new QMenu;
  64. if (menu == NULL)
  65. return;
  66. QModelIndex idx = peers->indexAt(pos);
  67. if (idx.isValid()) {
  68. ctx_item = model.itemFromIndex(idx);
  69. int type = ctx_item->data(peer_role_type).toInt();
  70. QString title;
  71. switch (type) {
  72. case PEER_TYPE_ASSOCIATED_STATION:
  73. title = tr("Associated station");
  74. break;
  75. case PEER_TYPE_AP:
  76. title = tr("AP");
  77. break;
  78. case PEER_TYPE_AP_WPS:
  79. title = tr("WPS AP");
  80. break;
  81. }
  82. menu->addAction(title)->setEnabled(false);
  83. menu->addSeparator();
  84. if (type == PEER_TYPE_ASSOCIATED_STATION ||
  85. type == PEER_TYPE_AP_WPS) {
  86. /* TODO: only for peers that are requesting WPS PIN
  87. * method */
  88. menu->addAction(QString("Enter WPS PIN"), this,
  89. SLOT(enter_pin()));
  90. }
  91. } else {
  92. ctx_item = NULL;
  93. menu->addAction(QString("Refresh"), this, SLOT(ctx_refresh()));
  94. }
  95. menu->exec(peers->mapToGlobal(pos));
  96. }
  97. void Peers::enter_pin()
  98. {
  99. if (ctx_item == NULL)
  100. return;
  101. QString addr = ctx_item->data(peer_role_address).toString();
  102. StringQuery input(tr("PIN:"));
  103. input.setWindowTitle(tr("PIN for ") + ctx_item->text());
  104. if (input.exec() != QDialog::Accepted)
  105. return;
  106. char cmd[100];
  107. char reply[100];
  108. size_t reply_len;
  109. snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
  110. addr.toAscii().constData(),
  111. input.get_string().toAscii().constData());
  112. reply_len = sizeof(reply) - 1;
  113. if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
  114. QMessageBox msg;
  115. msg.setIcon(QMessageBox::Warning);
  116. msg.setText("Failed to set the WPS PIN.");
  117. msg.exec();
  118. }
  119. }
  120. void Peers::ctx_refresh()
  121. {
  122. update_peers();
  123. }
  124. void Peers::add_stations()
  125. {
  126. char reply[2048];
  127. size_t reply_len;
  128. char cmd[20];
  129. int res;
  130. reply_len = sizeof(reply) - 1;
  131. if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0)
  132. return;
  133. do {
  134. reply[reply_len] = '\0';
  135. QString info(reply);
  136. char *txt = reply;
  137. while (*txt != '\0' && *txt != '\n')
  138. txt++;
  139. *txt++ = '\0';
  140. if (strncmp(reply, "FAIL", 4) == 0 ||
  141. strncmp(reply, "UNKNOWN", 7) == 0)
  142. break;
  143. QStringList lines = info.split(QRegExp("\\n"));
  144. QString name;
  145. for (QStringList::Iterator it = lines.begin();
  146. it != lines.end(); it++) {
  147. int pos = (*it).indexOf('=') + 1;
  148. if (pos < 1)
  149. continue;
  150. if ((*it).startsWith("wpsDeviceName="))
  151. name = (*it).mid(pos);
  152. }
  153. if (name.isEmpty())
  154. name = reply;
  155. QStandardItem *item = new QStandardItem(*default_icon, name);
  156. if (item) {
  157. item->setData(QString(reply), peer_role_address);
  158. item->setData(PEER_TYPE_ASSOCIATED_STATION,
  159. peer_role_type);
  160. item->setToolTip(info);
  161. model.appendRow(item);
  162. }
  163. reply_len = sizeof(reply) - 1;
  164. snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
  165. res = wpagui->ctrlRequest(cmd, reply, &reply_len);
  166. } while (res >= 0);
  167. }
  168. void Peers::add_scan_results()
  169. {
  170. char reply[2048];
  171. size_t reply_len;
  172. int index;
  173. char cmd[20];
  174. index = 0;
  175. while (wpagui) {
  176. snprintf(cmd, sizeof(cmd), "BSS %d", index++);
  177. if (index > 1000)
  178. break;
  179. reply_len = sizeof(reply) - 1;
  180. if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
  181. break;
  182. reply[reply_len] = '\0';
  183. QString bss(reply);
  184. if (bss.isEmpty() || bss.startsWith("FAIL"))
  185. break;
  186. QString ssid, bssid, flags, wps_name;
  187. QStringList lines = bss.split(QRegExp("\\n"));
  188. for (QStringList::Iterator it = lines.begin();
  189. it != lines.end(); it++) {
  190. int pos = (*it).indexOf('=') + 1;
  191. if (pos < 1)
  192. continue;
  193. if ((*it).startsWith("bssid="))
  194. bssid = (*it).mid(pos);
  195. else if ((*it).startsWith("flags="))
  196. flags = (*it).mid(pos);
  197. else if ((*it).startsWith("ssid="))
  198. ssid = (*it).mid(pos);
  199. else if ((*it).startsWith("wps_device_name="))
  200. wps_name = (*it).mid(pos);
  201. }
  202. QString name = wps_name;
  203. if (name.isEmpty())
  204. name = ssid + "\n" + bssid;
  205. QStandardItem *item = new QStandardItem(*default_icon, name);
  206. if (item) {
  207. item->setData(QString(reply), peer_role_address);
  208. if (flags.contains("[WPS]"))
  209. item->setData(PEER_TYPE_AP_WPS,
  210. peer_role_type);
  211. else
  212. item->setData(PEER_TYPE_AP, peer_role_type);
  213. for (int i = 0; i < lines.size(); i++) {
  214. if (lines[i].length() > 60) {
  215. lines[i].remove(
  216. 60, lines[i].length());
  217. lines[i] += "..";
  218. }
  219. }
  220. item->setToolTip(lines.join("\n"));
  221. model.appendRow(item);
  222. }
  223. }
  224. }
  225. void Peers::update_peers()
  226. {
  227. model.clear();
  228. if (wpagui == NULL)
  229. return;
  230. add_stations();
  231. add_scan_results();
  232. }