peers.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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 "wpa_ctrl.h"
  18. #include "wpagui.h"
  19. #include "stringquery.h"
  20. #include "peers.h"
  21. static const int peer_role_address = Qt::UserRole + 1;
  22. static const int peer_role_type = Qt::UserRole + 2;
  23. /*
  24. * TODO:
  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. PEER_TYPE_WPS_PIN_NEEDED,
  33. };
  34. Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags)
  35. : QDialog(parent)
  36. {
  37. setupUi(this);
  38. if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
  39. default_icon = new QIcon(":/icons/wpa_gui.svg");
  40. else
  41. default_icon = new QIcon(":/icons/wpa_gui.png");
  42. peers->setModel(&model);
  43. peers->setResizeMode(QListView::Adjust);
  44. peers->setContextMenuPolicy(Qt::CustomContextMenu);
  45. connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)),
  46. this, SLOT(context_menu(const QPoint &)));
  47. wpagui = NULL;
  48. }
  49. void Peers::setWpaGui(WpaGui *_wpagui)
  50. {
  51. wpagui = _wpagui;
  52. update_peers();
  53. }
  54. Peers::~Peers()
  55. {
  56. delete default_icon;
  57. }
  58. void Peers::languageChange()
  59. {
  60. retranslateUi(this);
  61. }
  62. void Peers::context_menu(const QPoint &pos)
  63. {
  64. QMenu *menu = new QMenu;
  65. if (menu == NULL)
  66. return;
  67. QModelIndex idx = peers->indexAt(pos);
  68. if (idx.isValid()) {
  69. ctx_item = model.itemFromIndex(idx);
  70. int type = ctx_item->data(peer_role_type).toInt();
  71. QString title;
  72. switch (type) {
  73. case PEER_TYPE_ASSOCIATED_STATION:
  74. title = tr("Associated station");
  75. break;
  76. case PEER_TYPE_AP:
  77. title = tr("AP");
  78. break;
  79. case PEER_TYPE_AP_WPS:
  80. title = tr("WPS AP");
  81. break;
  82. case PEER_TYPE_WPS_PIN_NEEDED:
  83. title = tr("WPS PIN needed");
  84. break;
  85. }
  86. menu->addAction(title)->setEnabled(false);
  87. menu->addSeparator();
  88. if (type == PEER_TYPE_ASSOCIATED_STATION ||
  89. type == PEER_TYPE_AP_WPS ||
  90. type == PEER_TYPE_WPS_PIN_NEEDED) {
  91. /* TODO: only for peers that are requesting WPS PIN
  92. * method */
  93. menu->addAction(QString("Enter WPS PIN"), this,
  94. SLOT(enter_pin()));
  95. }
  96. } else {
  97. ctx_item = NULL;
  98. menu->addAction(QString("Refresh"), this, SLOT(ctx_refresh()));
  99. }
  100. menu->exec(peers->mapToGlobal(pos));
  101. }
  102. void Peers::enter_pin()
  103. {
  104. if (ctx_item == NULL)
  105. return;
  106. QString addr = ctx_item->data(peer_role_address).toString();
  107. StringQuery input(tr("PIN:"));
  108. input.setWindowTitle(tr("PIN for ") + ctx_item->text());
  109. if (input.exec() != QDialog::Accepted)
  110. return;
  111. char cmd[100];
  112. char reply[100];
  113. size_t reply_len;
  114. snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
  115. addr.toAscii().constData(),
  116. input.get_string().toAscii().constData());
  117. reply_len = sizeof(reply) - 1;
  118. if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) {
  119. QMessageBox msg;
  120. msg.setIcon(QMessageBox::Warning);
  121. msg.setText("Failed to set the WPS PIN.");
  122. msg.exec();
  123. }
  124. }
  125. void Peers::ctx_refresh()
  126. {
  127. update_peers();
  128. }
  129. void Peers::add_stations()
  130. {
  131. char reply[2048];
  132. size_t reply_len;
  133. char cmd[20];
  134. int res;
  135. reply_len = sizeof(reply) - 1;
  136. if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0)
  137. return;
  138. do {
  139. reply[reply_len] = '\0';
  140. QString info(reply);
  141. char *txt = reply;
  142. while (*txt != '\0' && *txt != '\n')
  143. txt++;
  144. *txt++ = '\0';
  145. if (strncmp(reply, "FAIL", 4) == 0 ||
  146. strncmp(reply, "UNKNOWN", 7) == 0)
  147. break;
  148. QStringList lines = info.split(QRegExp("\\n"));
  149. QString name;
  150. for (QStringList::Iterator it = lines.begin();
  151. it != lines.end(); it++) {
  152. int pos = (*it).indexOf('=') + 1;
  153. if (pos < 1)
  154. continue;
  155. if ((*it).startsWith("wpsDeviceName="))
  156. name = (*it).mid(pos);
  157. }
  158. if (name.isEmpty())
  159. name = reply;
  160. QStandardItem *item = new QStandardItem(*default_icon, name);
  161. if (item) {
  162. item->setData(QString(reply), peer_role_address);
  163. item->setData(PEER_TYPE_ASSOCIATED_STATION,
  164. peer_role_type);
  165. item->setToolTip(info);
  166. model.appendRow(item);
  167. }
  168. reply_len = sizeof(reply) - 1;
  169. snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
  170. res = wpagui->ctrlRequest(cmd, reply, &reply_len);
  171. } while (res >= 0);
  172. }
  173. void Peers::add_scan_results()
  174. {
  175. char reply[2048];
  176. size_t reply_len;
  177. int index;
  178. char cmd[20];
  179. index = 0;
  180. while (wpagui) {
  181. snprintf(cmd, sizeof(cmd), "BSS %d", index++);
  182. if (index > 1000)
  183. break;
  184. reply_len = sizeof(reply) - 1;
  185. if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
  186. break;
  187. reply[reply_len] = '\0';
  188. QString bss(reply);
  189. if (bss.isEmpty() || bss.startsWith("FAIL"))
  190. break;
  191. QString ssid, bssid, flags, wps_name;
  192. QStringList lines = bss.split(QRegExp("\\n"));
  193. for (QStringList::Iterator it = lines.begin();
  194. it != lines.end(); it++) {
  195. int pos = (*it).indexOf('=') + 1;
  196. if (pos < 1)
  197. continue;
  198. if ((*it).startsWith("bssid="))
  199. bssid = (*it).mid(pos);
  200. else if ((*it).startsWith("flags="))
  201. flags = (*it).mid(pos);
  202. else if ((*it).startsWith("ssid="))
  203. ssid = (*it).mid(pos);
  204. else if ((*it).startsWith("wps_device_name="))
  205. wps_name = (*it).mid(pos);
  206. }
  207. QString name = wps_name;
  208. if (name.isEmpty())
  209. name = ssid + "\n" + bssid;
  210. QStandardItem *item = new QStandardItem(*default_icon, name);
  211. if (item) {
  212. item->setData(bssid, peer_role_address);
  213. if (flags.contains("[WPS"))
  214. item->setData(PEER_TYPE_AP_WPS,
  215. peer_role_type);
  216. else
  217. item->setData(PEER_TYPE_AP, peer_role_type);
  218. for (int i = 0; i < lines.size(); i++) {
  219. if (lines[i].length() > 60) {
  220. lines[i].remove(
  221. 60, lines[i].length());
  222. lines[i] += "..";
  223. }
  224. }
  225. item->setToolTip(lines.join("\n"));
  226. model.appendRow(item);
  227. }
  228. }
  229. }
  230. void Peers::update_peers()
  231. {
  232. model.clear();
  233. if (wpagui == NULL)
  234. return;
  235. add_stations();
  236. add_scan_results();
  237. }
  238. QStandardItem * Peers::find_addr(QString addr)
  239. {
  240. if (model.rowCount() == 0)
  241. return NULL;
  242. QModelIndexList lst = model.match(model.index(0, 0), peer_role_address,
  243. addr);
  244. if (lst.size() == 0)
  245. return NULL;
  246. return model.itemFromIndex(lst[0]);
  247. }
  248. void Peers::event_notify(WpaMsg msg)
  249. {
  250. QString text = msg.getMsg();
  251. if (text.startsWith(WPS_EVENT_PIN_NEEDED)) {
  252. /*
  253. * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7
  254. * 02:2a:c4:18:5b:f3
  255. * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
  256. */
  257. QStringList items = text.split(' ');
  258. QString uuid = items[1];
  259. QString addr = items[2];
  260. QString name = "";
  261. QStandardItem *item = find_addr(addr);
  262. if (item)
  263. return;
  264. int pos = text.indexOf('[');
  265. if (pos >= 0) {
  266. int pos2 = text.lastIndexOf(']');
  267. if (pos2 >= pos) {
  268. items = text.mid(pos + 1, pos2 - pos - 1).
  269. split('|');
  270. name = items[0];
  271. items.append(addr);
  272. }
  273. }
  274. item = new QStandardItem(*default_icon, name);
  275. if (item) {
  276. item->setData(addr, peer_role_address);
  277. item->setData(PEER_TYPE_WPS_PIN_NEEDED,
  278. peer_role_type);
  279. item->setToolTip(items.join(QString("\n")));
  280. model.appendRow(item);
  281. }
  282. }
  283. }