1 /* 2 * wpa_gui - WpaGui class 3 * Copyright (c) 2005-2011, Jouni Malinen <j (at) w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #ifdef CONFIG_NATIVE_WINDOWS 10 #include <windows.h> 11 #endif /* CONFIG_NATIVE_WINDOWS */ 12 13 #include <cstdio> 14 #include <unistd.h> 15 #include <QMessageBox> 16 #include <QCloseEvent> 17 #include <QImageReader> 18 #include <QSettings> 19 20 #include "wpagui.h" 21 #include "dirent.h" 22 #include "common/wpa_ctrl.h" 23 #include "userdatarequest.h" 24 #include "networkconfig.h" 25 26 27 #ifndef QT_NO_DEBUG 28 #define debug(M, ...) qDebug("DEBUG %d: " M, __LINE__, ##__VA_ARGS__) 29 #else 30 #define debug(M, ...) do {} while (0) 31 #endif 32 33 34 WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, 35 Qt::WindowFlags) 36 : QMainWindow(parent), app(_app) 37 { 38 setupUi(this); 39 this->setWindowFlags(Qt::Dialog); 40 41 #ifdef CONFIG_NATIVE_WINDOWS 42 fileStopServiceAction = new QAction(this); 43 fileStopServiceAction->setObjectName("Stop Service"); 44 fileStopServiceAction->setIconText(tr("Stop Service")); 45 fileMenu->insertAction(actionWPS, fileStopServiceAction); 46 47 fileStartServiceAction = new QAction(this); 48 fileStartServiceAction->setObjectName("Start Service"); 49 fileStartServiceAction->setIconText(tr("Start Service")); 50 fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction); 51 52 connect(fileStartServiceAction, SIGNAL(triggered()), this, 53 SLOT(startService())); 54 connect(fileStopServiceAction, SIGNAL(triggered()), this, 55 SLOT(stopService())); 56 57 addInterfaceAction = new QAction(this); 58 addInterfaceAction->setIconText(tr("Add Interface")); 59 fileMenu->insertAction(fileStartServiceAction, addInterfaceAction); 60 61 connect(addInterfaceAction, SIGNAL(triggered()), this, 62 SLOT(addInterface())); 63 #endif /* CONFIG_NATIVE_WINDOWS */ 64 65 (void) statusBar(); 66 67 /* 68 * Disable WPS tab by default; it will be enabled if wpa_supplicant is 69 * built with WPS support. 70 */ 71 wpsTab->setEnabled(false); 72 wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false); 73 74 connect(fileEventHistoryAction, SIGNAL(triggered()), this, 75 SLOT(eventHistory())); 76 connect(fileSaveConfigAction, SIGNAL(triggered()), this, 77 SLOT(saveConfig())); 78 connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog())); 79 connect(actionPeers, SIGNAL(triggered()), this, SLOT(peersDialog())); 80 connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit())); 81 connect(networkAddAction, SIGNAL(triggered()), this, 82 SLOT(addNetwork())); 83 connect(networkEditAction, SIGNAL(triggered()), this, 84 SLOT(editSelectedNetwork())); 85 connect(networkRemoveAction, SIGNAL(triggered()), this, 86 SLOT(removeSelectedNetwork())); 87 connect(networkEnableAllAction, SIGNAL(triggered()), this, 88 SLOT(enableAllNetworks())); 89 connect(networkDisableAllAction, SIGNAL(triggered()), this, 90 SLOT(disableAllNetworks())); 91 connect(networkRemoveAllAction, SIGNAL(triggered()), this, 92 SLOT(removeAllNetworks())); 93 connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex())); 94 connect(helpContentsAction, SIGNAL(triggered()), this, 95 SLOT(helpContents())); 96 connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout())); 97 connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect())); 98 connect(scanButton, SIGNAL(clicked()), this, SLOT(scan())); 99 connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB())); 100 connect(adapterSelect, SIGNAL(activated(const QString&)), this, 101 SLOT(selectAdapter(const QString&))); 102 connect(networkSelect, SIGNAL(activated(const QString&)), this, 103 SLOT(selectNetwork(const QString&))); 104 connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork())); 105 connect(editNetworkButton, SIGNAL(clicked()), this, 106 SLOT(editListedNetwork())); 107 connect(removeNetworkButton, SIGNAL(clicked()), this, 108 SLOT(removeListedNetwork())); 109 connect(networkList, SIGNAL(itemSelectionChanged()), this, 110 SLOT(updateNetworkDisabledStatus())); 111 connect(enableRadioButton, SIGNAL(toggled(bool)), this, 112 SLOT(enableListedNetwork(bool))); 113 connect(disableRadioButton, SIGNAL(toggled(bool)), this, 114 SLOT(disableListedNetwork(bool))); 115 connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan())); 116 connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), 117 this, SLOT(editListedNetwork())); 118 connect(wpaguiTab, SIGNAL(currentChanged(int)), this, 119 SLOT(tabChanged(int))); 120 connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc())); 121 connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin())); 122 connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this, 123 SLOT(wpsApPinChanged(const QString &))); 124 connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin())); 125 126 eh = NULL; 127 scanres = NULL; 128 peers = NULL; 129 add_iface = NULL; 130 udr = NULL; 131 tray_icon = NULL; 132 startInTray = false; 133 quietMode = false; 134 ctrl_iface = NULL; 135 ctrl_conn = NULL; 136 monitor_conn = NULL; 137 msgNotifier = NULL; 138 ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); 139 signalMeterInterval = 0; 140 141 parse_argv(); 142 143 #ifndef QT_NO_SESSIONMANAGER 144 if (app->isSessionRestored()) { 145 QSettings settings("wpa_supplicant", "wpa_gui"); 146 settings.beginGroup("state"); 147 if (app->sessionId().compare(settings.value("session_id"). 148 toString()) == 0) 149 startInTray = settings.value("in_tray").toBool(); 150 settings.endGroup(); 151 } 152 #endif 153 154 if (QSystemTrayIcon::isSystemTrayAvailable()) 155 createTrayIcon(startInTray); 156 else 157 show(); 158 159 connectedToService = false; 160 textStatus->setText(tr("connecting to wpa_supplicant")); 161 timer = new QTimer(this); 162 connect(timer, SIGNAL(timeout()), SLOT(ping())); 163 timer->setSingleShot(false); 164 timer->start(1000); 165 166 signalMeterTimer = new QTimer(this); 167 signalMeterTimer->setInterval(signalMeterInterval); 168 connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate())); 169 170 if (openCtrlConnection(ctrl_iface) < 0) { 171 debug("Failed to open control connection to " 172 "wpa_supplicant."); 173 } 174 175 updateStatus(); 176 networkMayHaveChanged = true; 177 updateNetworks(); 178 } 179 180 181 WpaGui::~WpaGui() 182 { 183 delete msgNotifier; 184 185 if (monitor_conn) { 186 wpa_ctrl_detach(monitor_conn); 187 wpa_ctrl_close(monitor_conn); 188 monitor_conn = NULL; 189 } 190 if (ctrl_conn) { 191 wpa_ctrl_close(ctrl_conn); 192 ctrl_conn = NULL; 193 } 194 195 if (eh) { 196 eh->close(); 197 delete eh; 198 eh = NULL; 199 } 200 201 if (scanres) { 202 scanres->close(); 203 delete scanres; 204 scanres = NULL; 205 } 206 207 if (peers) { 208 peers->close(); 209 delete peers; 210 peers = NULL; 211 } 212 213 if (add_iface) { 214 add_iface->close(); 215 delete add_iface; 216 add_iface = NULL; 217 } 218 219 if (udr) { 220 udr->close(); 221 delete udr; 222 udr = NULL; 223 } 224 225 free(ctrl_iface); 226 ctrl_iface = NULL; 227 228 free(ctrl_iface_dir); 229 ctrl_iface_dir = NULL; 230 } 231 232 233 void WpaGui::languageChange() 234 { 235 retranslateUi(this); 236 } 237 238 239 void WpaGui::parse_argv() 240 { 241 int c; 242 WpaGuiApp *app = qobject_cast<WpaGuiApp*>(qApp); 243 for (;;) { 244 c = getopt(app->argc, app->argv, "i:m:p:tq"); 245 if (c < 0) 246 break; 247 switch (c) { 248 case 'i': 249 free(ctrl_iface); 250 ctrl_iface = strdup(optarg); 251 break; 252 case 'm': 253 signalMeterInterval = atoi(optarg) * 1000; 254 break; 255 case 'p': 256 free(ctrl_iface_dir); 257 ctrl_iface_dir = strdup(optarg); 258 break; 259 case 't': 260 startInTray = true; 261 break; 262 case 'q': 263 quietMode = true; 264 break; 265 } 266 } 267 } 268 269 270 int WpaGui::openCtrlConnection(const char *ifname) 271 { 272 char *cfile; 273 int flen; 274 char buf[2048], *pos, *pos2; 275 size_t len; 276 277 if (ifname) { 278 if (ifname != ctrl_iface) { 279 free(ctrl_iface); 280 ctrl_iface = strdup(ifname); 281 } 282 } else { 283 #ifdef CONFIG_CTRL_IFACE_UDP 284 free(ctrl_iface); 285 ctrl_iface = strdup("udp"); 286 #endif /* CONFIG_CTRL_IFACE_UDP */ 287 #ifdef CONFIG_CTRL_IFACE_UNIX 288 struct dirent *dent; 289 DIR *dir = opendir(ctrl_iface_dir); 290 free(ctrl_iface); 291 ctrl_iface = NULL; 292 if (dir) { 293 while ((dent = readdir(dir))) { 294 #ifdef _DIRENT_HAVE_D_TYPE 295 /* Skip the file if it is not a socket. 296 * Also accept DT_UNKNOWN (0) in case 297 * the C library or underlying file 298 * system does not support d_type. */ 299 if (dent->d_type != DT_SOCK && 300 dent->d_type != DT_UNKNOWN) 301 continue; 302 #endif /* _DIRENT_HAVE_D_TYPE */ 303 304 if (strcmp(dent->d_name, ".") == 0 || 305 strcmp(dent->d_name, "..") == 0) 306 continue; 307 debug("Selected interface '%s'", 308 dent->d_name); 309 ctrl_iface = strdup(dent->d_name); 310 break; 311 } 312 closedir(dir); 313 } 314 #endif /* CONFIG_CTRL_IFACE_UNIX */ 315 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 316 struct wpa_ctrl *ctrl; 317 int ret; 318 319 free(ctrl_iface); 320 ctrl_iface = NULL; 321 322 ctrl = wpa_ctrl_open(NULL); 323 if (ctrl) { 324 len = sizeof(buf) - 1; 325 ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, 326 &len, NULL); 327 if (ret >= 0) { 328 connectedToService = true; 329 buf[len] = '\0'; 330 pos = strchr(buf, '\n'); 331 if (pos) 332 *pos = '\0'; 333 ctrl_iface = strdup(buf); 334 } 335 wpa_ctrl_close(ctrl); 336 } 337 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 338 } 339 340 if (ctrl_iface == NULL) { 341 #ifdef CONFIG_NATIVE_WINDOWS 342 static bool first = true; 343 if (first && !serviceRunning()) { 344 first = false; 345 if (QMessageBox::warning( 346 this, qAppName(), 347 tr("wpa_supplicant service is not " 348 "running.\n" 349 "Do you want to start it?"), 350 QMessageBox::Yes | QMessageBox::No) == 351 QMessageBox::Yes) 352 startService(); 353 } 354 #endif /* CONFIG_NATIVE_WINDOWS */ 355 return -1; 356 } 357 358 #ifdef CONFIG_CTRL_IFACE_UNIX 359 flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; 360 cfile = (char *) malloc(flen); 361 if (cfile == NULL) 362 return -1; 363 snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); 364 #else /* CONFIG_CTRL_IFACE_UNIX */ 365 flen = strlen(ctrl_iface) + 1; 366 cfile = (char *) malloc(flen); 367 if (cfile == NULL) 368 return -1; 369 snprintf(cfile, flen, "%s", ctrl_iface); 370 #endif /* CONFIG_CTRL_IFACE_UNIX */ 371 372 if (ctrl_conn) { 373 wpa_ctrl_close(ctrl_conn); 374 ctrl_conn = NULL; 375 } 376 377 if (monitor_conn) { 378 delete msgNotifier; 379 msgNotifier = NULL; 380 wpa_ctrl_detach(monitor_conn); 381 wpa_ctrl_close(monitor_conn); 382 monitor_conn = NULL; 383 } 384 385 debug("Trying to connect to '%s'", cfile); 386 ctrl_conn = wpa_ctrl_open(cfile); 387 if (ctrl_conn == NULL) { 388 free(cfile); 389 return -1; 390 } 391 monitor_conn = wpa_ctrl_open(cfile); 392 free(cfile); 393 if (monitor_conn == NULL) { 394 wpa_ctrl_close(ctrl_conn); 395 return -1; 396 } 397 if (wpa_ctrl_attach(monitor_conn)) { 398 debug("Failed to attach to wpa_supplicant"); 399 wpa_ctrl_close(monitor_conn); 400 monitor_conn = NULL; 401 wpa_ctrl_close(ctrl_conn); 402 ctrl_conn = NULL; 403 return -1; 404 } 405 406 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 407 msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), 408 QSocketNotifier::Read, this); 409 connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); 410 #endif 411 412 adapterSelect->clear(); 413 adapterSelect->addItem(ctrl_iface); 414 adapterSelect->setCurrentIndex(0); 415 416 len = sizeof(buf) - 1; 417 if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 418 0) { 419 buf[len] = '\0'; 420 pos = buf; 421 while (*pos) { 422 pos2 = strchr(pos, '\n'); 423 if (pos2) 424 *pos2 = '\0'; 425 if (strcmp(pos, ctrl_iface) != 0) 426 adapterSelect->addItem(pos); 427 if (pos2) 428 pos = pos2 + 1; 429 else 430 break; 431 } 432 } 433 434 len = sizeof(buf) - 1; 435 if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len, 436 NULL) >= 0) { 437 buf[len] = '\0'; 438 439 QString res(buf); 440 QStringList types = res.split(QChar(' ')); 441 bool wps = types.contains("WSC"); 442 actionWPS->setEnabled(wps); 443 wpsTab->setEnabled(wps); 444 wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps); 445 } 446 447 return 0; 448 } 449 450 451 int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) 452 { 453 int ret; 454 455 if (ctrl_conn == NULL) 456 return -3; 457 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL); 458 if (ret == -2) 459 debug("'%s' command timed out.", cmd); 460 else if (ret < 0) 461 debug("'%s' command failed.", cmd); 462 463 return ret; 464 } 465 466 467 QString WpaGui::wpaStateTranslate(char *state) 468 { 469 if (!strcmp(state, "DISCONNECTED")) 470 return tr("Disconnected"); 471 else if (!strcmp(state, "INACTIVE")) 472 return tr("Inactive"); 473 else if (!strcmp(state, "SCANNING")) 474 return tr("Scanning"); 475 else if (!strcmp(state, "AUTHENTICATING")) 476 return tr("Authenticating"); 477 else if (!strcmp(state, "ASSOCIATING")) 478 return tr("Associating"); 479 else if (!strcmp(state, "ASSOCIATED")) 480 return tr("Associated"); 481 else if (!strcmp(state, "4WAY_HANDSHAKE")) 482 return tr("4-Way Handshake"); 483 else if (!strcmp(state, "GROUP_HANDSHAKE")) 484 return tr("Group Handshake"); 485 else if (!strcmp(state, "COMPLETED")) 486 return tr("Completed"); 487 else 488 return tr("Unknown"); 489 } 490 491 492 void WpaGui::updateStatus() 493 { 494 char buf[2048], *start, *end, *pos; 495 size_t len; 496 497 pingsToStatusUpdate = 10; 498 499 len = sizeof(buf) - 1; 500 if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { 501 textStatus->setText(tr("Could not get status from " 502 "wpa_supplicant")); 503 textAuthentication->clear(); 504 textEncryption->clear(); 505 textSsid->clear(); 506 textBssid->clear(); 507 textIpAddress->clear(); 508 updateTrayToolTip(tr("no status information")); 509 updateTrayIcon(TrayIconOffline); 510 signalMeterTimer->stop(); 511 512 #ifdef CONFIG_NATIVE_WINDOWS 513 static bool first = true; 514 if (first && connectedToService && 515 (ctrl_iface == NULL || *ctrl_iface == '\0')) { 516 first = false; 517 if (QMessageBox::information( 518 this, qAppName(), 519 tr("No network interfaces in use.\n" 520 "Would you like to add one?"), 521 QMessageBox::Yes | QMessageBox::No) == 522 QMessageBox::Yes) 523 addInterface(); 524 } 525 #endif /* CONFIG_NATIVE_WINDOWS */ 526 return; 527 } 528 529 buf[len] = '\0'; 530 531 bool auth_updated = false, ssid_updated = false; 532 bool bssid_updated = false, ipaddr_updated = false; 533 bool status_updated = false; 534 char *pairwise_cipher = NULL, *group_cipher = NULL; 535 char *mode = NULL; 536 537 start = buf; 538 while (*start) { 539 bool last = false; 540 end = strchr(start, '\n'); 541 if (end == NULL) { 542 last = true; 543 end = start; 544 while (end[0] && end[1]) 545 end++; 546 } 547 *end = '\0'; 548 549 pos = strchr(start, '='); 550 if (pos) { 551 *pos++ = '\0'; 552 if (strcmp(start, "bssid") == 0) { 553 bssid_updated = true; 554 textBssid->setText(pos); 555 } else if (strcmp(start, "ssid") == 0) { 556 ssid_updated = true; 557 textSsid->setText(pos); 558 updateTrayToolTip(pos + tr(" (associated)")); 559 if (!signalMeterInterval) { 560 /* if signal meter is not enabled show 561 * full signal strength */ 562 updateTrayIcon(TrayIconSignalExcellent); 563 } 564 } else if (strcmp(start, "ip_address") == 0) { 565 ipaddr_updated = true; 566 textIpAddress->setText(pos); 567 } else if (strcmp(start, "wpa_state") == 0) { 568 status_updated = true; 569 textStatus->setText(wpaStateTranslate(pos)); 570 } else if (strcmp(start, "key_mgmt") == 0) { 571 auth_updated = true; 572 textAuthentication->setText(pos); 573 /* TODO: could add EAP status to this */ 574 } else if (strcmp(start, "pairwise_cipher") == 0) { 575 pairwise_cipher = pos; 576 } else if (strcmp(start, "group_cipher") == 0) { 577 group_cipher = pos; 578 } else if (strcmp(start, "mode") == 0) { 579 mode = pos; 580 } 581 } 582 583 if (last) 584 break; 585 start = end + 1; 586 } 587 if (status_updated && mode) 588 textStatus->setText(textStatus->text() + " (" + mode + ")"); 589 590 if (pairwise_cipher || group_cipher) { 591 QString encr; 592 if (pairwise_cipher && group_cipher && 593 strcmp(pairwise_cipher, group_cipher) != 0) { 594 encr.append(pairwise_cipher); 595 encr.append(" + "); 596 encr.append(group_cipher); 597 } else if (pairwise_cipher) { 598 encr.append(pairwise_cipher); 599 } else { 600 encr.append(group_cipher); 601 encr.append(" [group key only]"); 602 } 603 textEncryption->setText(encr); 604 } else 605 textEncryption->clear(); 606 607 if (signalMeterInterval) { 608 /* 609 * Handle signal meter service. When network is not associated, 610 * deactivate timer, otherwise keep it going. Tray icon has to 611 * be initialized here, because of the initial delay of the 612 * timer. 613 */ 614 if (ssid_updated) { 615 if (!signalMeterTimer->isActive()) { 616 updateTrayIcon(TrayIconConnected); 617 signalMeterTimer->start(); 618 } 619 } else { 620 signalMeterTimer->stop(); 621 } 622 } 623 624 if (!status_updated) 625 textStatus->clear(); 626 if (!auth_updated) 627 textAuthentication->clear(); 628 if (!ssid_updated) { 629 textSsid->clear(); 630 updateTrayToolTip(tr("(not-associated)")); 631 updateTrayIcon(TrayIconOffline); 632 } 633 if (!bssid_updated) 634 textBssid->clear(); 635 if (!ipaddr_updated) 636 textIpAddress->clear(); 637 } 638 639 640 void WpaGui::updateNetworks() 641 { 642 char buf[4096], *start, *end, *id, *ssid, *bssid, *flags; 643 size_t len; 644 int first_active = -1; 645 int was_selected = -1; 646 bool current = false; 647 648 if (!networkMayHaveChanged) 649 return; 650 651 if (networkList->currentRow() >= 0) 652 was_selected = networkList->currentRow(); 653 654 networkSelect->clear(); 655 networkList->clear(); 656 657 if (ctrl_conn == NULL) 658 return; 659 660 len = sizeof(buf) - 1; 661 if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) 662 return; 663 664 buf[len] = '\0'; 665 start = strchr(buf, '\n'); 666 if (start == NULL) 667 return; 668 start++; 669 670 while (*start) { 671 bool last = false; 672 end = strchr(start, '\n'); 673 if (end == NULL) { 674 last = true; 675 end = start; 676 while (end[0] && end[1]) 677 end++; 678 } 679 *end = '\0'; 680 681 id = start; 682 ssid = strchr(id, '\t'); 683 if (ssid == NULL) 684 break; 685 *ssid++ = '\0'; 686 bssid = strchr(ssid, '\t'); 687 if (bssid == NULL) 688 break; 689 *bssid++ = '\0'; 690 flags = strchr(bssid, '\t'); 691 if (flags == NULL) 692 break; 693 *flags++ = '\0'; 694 695 if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) { 696 if (last) 697 break; 698 start = end + 1; 699 continue; 700 } 701 702 QString network(id); 703 network.append(": "); 704 network.append(ssid); 705 networkSelect->addItem(network); 706 networkList->addItem(network); 707 708 if (strstr(flags, "[CURRENT]")) { 709 networkSelect->setCurrentIndex(networkSelect->count() - 710 1); 711 current = true; 712 } else if (first_active < 0 && 713 strstr(flags, "[DISABLED]") == NULL) 714 first_active = networkSelect->count() - 1; 715 716 if (last) 717 break; 718 start = end + 1; 719 } 720 721 if (networkSelect->count() > 1) 722 networkSelect->addItem(tr("Select any network")); 723 724 if (!current && first_active >= 0) 725 networkSelect->setCurrentIndex(first_active); 726 727 if (was_selected >= 0 && networkList->count() > 0) { 728 if (was_selected < networkList->count()) 729 networkList->setCurrentRow(was_selected); 730 else 731 networkList->setCurrentRow(networkList->count() - 1); 732 } 733 else 734 networkList->setCurrentRow(networkSelect->currentIndex()); 735 736 networkMayHaveChanged = false; 737 } 738 739 740 void WpaGui::helpIndex() 741 { 742 debug("helpIndex"); 743 } 744 745 746 void WpaGui::helpContents() 747 { 748 debug("helpContents"); 749 } 750 751 752 void WpaGui::helpAbout() 753 { 754 QMessageBox::about(this, "wpa_gui for wpa_supplicant", 755 "Copyright (c) 2003-2015,\n" 756 "Jouni Malinen <j (at) w1.fi>\n" 757 "and contributors.\n" 758 "\n" 759 "This software may be distributed under\n" 760 "the terms of the BSD license.\n" 761 "See README for more details.\n" 762 "\n" 763 "This product includes software developed\n" 764 "by the OpenSSL Project for use in the\n" 765 "OpenSSL Toolkit (http://www.openssl.org/)\n"); 766 } 767 768 769 void WpaGui::disconnect() 770 { 771 char reply[10]; 772 size_t reply_len = sizeof(reply); 773 ctrlRequest("DISCONNECT", reply, &reply_len); 774 stopWpsRun(false); 775 } 776 777 778 void WpaGui::scan() 779 { 780 if (scanres) { 781 scanres->close(); 782 delete scanres; 783 } 784 785 scanres = new ScanResults(); 786 if (scanres == NULL) 787 return; 788 scanres->setWpaGui(this); 789 scanres->show(); 790 scanres->exec(); 791 } 792 793 794 void WpaGui::eventHistory() 795 { 796 if (eh) { 797 eh->close(); 798 delete eh; 799 } 800 801 eh = new EventHistory(); 802 if (eh == NULL) 803 return; 804 eh->addEvents(msgs); 805 eh->show(); 806 eh->exec(); 807 } 808 809 810 void WpaGui::ping() 811 { 812 char buf[10]; 813 size_t len; 814 815 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 816 /* 817 * QSocketNotifier cannot be used with Windows named pipes, so use a 818 * timer to check for received messages for now. This could be 819 * optimized be doing something specific to named pipes or Windows 820 * events, but it is not clear what would be the best way of doing that 821 * in Qt. 822 */ 823 receiveMsgs(); 824 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 825 826 if (scanres && !scanres->isVisible()) { 827 delete scanres; 828 scanres = NULL; 829 } 830 831 if (eh && !eh->isVisible()) { 832 delete eh; 833 eh = NULL; 834 } 835 836 if (udr && !udr->isVisible()) { 837 delete udr; 838 udr = NULL; 839 } 840 841 len = sizeof(buf) - 1; 842 if (ctrlRequest("PING", buf, &len) < 0) { 843 debug("PING failed - trying to reconnect"); 844 if (openCtrlConnection(ctrl_iface) >= 0) { 845 debug("Reconnected successfully"); 846 pingsToStatusUpdate = 0; 847 } 848 } 849 850 pingsToStatusUpdate--; 851 if (pingsToStatusUpdate <= 0) { 852 updateStatus(); 853 updateNetworks(); 854 } 855 856 #ifndef CONFIG_CTRL_IFACE_NAMED_PIPE 857 /* Use less frequent pings and status updates when the main window is 858 * hidden (running in taskbar). */ 859 int interval = isHidden() ? 5000 : 1000; 860 if (timer->interval() != interval) 861 timer->setInterval(interval); 862 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 863 } 864 865 866 void WpaGui::signalMeterUpdate() 867 { 868 char reply[128]; 869 size_t reply_len = sizeof(reply); 870 char *rssi; 871 int rssi_value; 872 873 ctrlRequest("SIGNAL_POLL", reply, &reply_len); 874 875 /* In order to eliminate signal strength fluctuations, try 876 * to obtain averaged RSSI value in the first place. */ 877 if ((rssi = strstr(reply, "AVG_RSSI=")) != NULL) 878 rssi_value = atoi(&rssi[sizeof("AVG_RSSI")]); 879 else if ((rssi = strstr(reply, "RSSI=")) != NULL) 880 rssi_value = atoi(&rssi[sizeof("RSSI")]); 881 else { 882 debug("Failed to get RSSI value"); 883 updateTrayIcon(TrayIconSignalNone); 884 return; 885 } 886 887 debug("RSSI value: %d", rssi_value); 888 889 /* 890 * NOTE: The code below assumes, that the unit of the value returned 891 * by the SIGNAL POLL request is dBm. It might not be true for all 892 * wpa_supplicant drivers. 893 */ 894 895 /* 896 * Calibration is based on "various Internet sources". Nonetheless, 897 * it seems to be compatible with the Windows 8.1 strength meter - 898 * tested on Intel Centrino Advanced-N 6235. 899 */ 900 if (rssi_value >= -60) 901 updateTrayIcon(TrayIconSignalExcellent); 902 else if (rssi_value >= -68) 903 updateTrayIcon(TrayIconSignalGood); 904 else if (rssi_value >= -76) 905 updateTrayIcon(TrayIconSignalOk); 906 else if (rssi_value >= -84) 907 updateTrayIcon(TrayIconSignalWeak); 908 else 909 updateTrayIcon(TrayIconSignalNone); 910 } 911 912 913 static int str_match(const char *a, const char *b) 914 { 915 return strncmp(a, b, strlen(b)) == 0; 916 } 917 918 919 void WpaGui::processMsg(char *msg) 920 { 921 char *pos = msg, *pos2; 922 int priority = 2; 923 924 if (*pos == '<') { 925 /* skip priority */ 926 pos++; 927 priority = atoi(pos); 928 pos = strchr(pos, '>'); 929 if (pos) 930 pos++; 931 else 932 pos = msg; 933 } 934 935 WpaMsg wm(pos, priority); 936 if (eh) 937 eh->addEvent(wm); 938 if (peers) 939 peers->event_notify(wm); 940 msgs.append(wm); 941 while (msgs.count() > 100) 942 msgs.pop_front(); 943 944 /* Update last message with truncated version of the event */ 945 if (strncmp(pos, "CTRL-", 5) == 0) { 946 pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); 947 if (pos2) 948 pos2++; 949 else 950 pos2 = pos; 951 } else 952 pos2 = pos; 953 QString lastmsg = pos2; 954 lastmsg.truncate(40); 955 textLastMessage->setText(lastmsg); 956 957 pingsToStatusUpdate = 0; 958 networkMayHaveChanged = true; 959 960 if (str_match(pos, WPA_CTRL_REQ)) 961 processCtrlReq(pos + strlen(WPA_CTRL_REQ)); 962 else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres) 963 scanres->updateResults(); 964 else if (str_match(pos, WPA_EVENT_DISCONNECTED)) 965 showTrayMessage(QSystemTrayIcon::Information, 3, 966 tr("Disconnected from network.")); 967 else if (str_match(pos, WPA_EVENT_CONNECTED)) { 968 showTrayMessage(QSystemTrayIcon::Information, 3, 969 tr("Connection to network established.")); 970 QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus())); 971 stopWpsRun(true); 972 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) { 973 wpsStatusText->setText(tr("WPS AP in active PBC mode found")); 974 if (textStatus->text() == "INACTIVE" || 975 textStatus->text() == "DISCONNECTED") 976 wpaguiTab->setCurrentWidget(wpsTab); 977 wpsInstructions->setText(tr("Press the PBC button on the " 978 "screen to start registration")); 979 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) { 980 wpsStatusText->setText(tr("WPS AP with recently selected " 981 "registrar")); 982 if (textStatus->text() == "INACTIVE" || 983 textStatus->text() == "DISCONNECTED") 984 wpaguiTab->setCurrentWidget(wpsTab); 985 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) { 986 showTrayMessage(QSystemTrayIcon::Information, 3, 987 "Wi-Fi Protected Setup (WPS) AP\n" 988 "indicating this client is authorized."); 989 wpsStatusText->setText("WPS AP indicating this client is " 990 "authorized"); 991 if (textStatus->text() == "INACTIVE" || 992 textStatus->text() == "DISCONNECTED") 993 wpaguiTab->setCurrentWidget(wpsTab); 994 } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) { 995 wpsStatusText->setText(tr("WPS AP detected")); 996 } else if (str_match(pos, WPS_EVENT_OVERLAP)) { 997 wpsStatusText->setText(tr("PBC mode overlap detected")); 998 wpsInstructions->setText(tr("More than one AP is currently in " 999 "active WPS PBC mode. Wait couple " 1000 "of minutes and try again")); 1001 wpaguiTab->setCurrentWidget(wpsTab); 1002 } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) { 1003 wpsStatusText->setText(tr("Network configuration received")); 1004 wpaguiTab->setCurrentWidget(wpsTab); 1005 } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) { 1006 if (strstr(pos, "(WSC)")) 1007 wpsStatusText->setText(tr("Registration started")); 1008 } else if (str_match(pos, WPS_EVENT_M2D)) { 1009 wpsStatusText->setText(tr("Registrar does not yet know PIN")); 1010 } else if (str_match(pos, WPS_EVENT_FAIL)) { 1011 wpsStatusText->setText(tr("Registration failed")); 1012 } else if (str_match(pos, WPS_EVENT_SUCCESS)) { 1013 wpsStatusText->setText(tr("Registration succeeded")); 1014 } 1015 } 1016 1017 1018 void WpaGui::processCtrlReq(const char *req) 1019 { 1020 if (udr) { 1021 udr->close(); 1022 delete udr; 1023 } 1024 udr = new UserDataRequest(); 1025 if (udr == NULL) 1026 return; 1027 if (udr->setParams(this, req) < 0) { 1028 delete udr; 1029 udr = NULL; 1030 return; 1031 } 1032 udr->show(); 1033 udr->exec(); 1034 } 1035 1036 1037 void WpaGui::receiveMsgs() 1038 { 1039 char buf[256]; 1040 size_t len; 1041 1042 while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { 1043 len = sizeof(buf) - 1; 1044 if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { 1045 buf[len] = '\0'; 1046 processMsg(buf); 1047 } 1048 } 1049 } 1050 1051 1052 void WpaGui::connectB() 1053 { 1054 char reply[10]; 1055 size_t reply_len = sizeof(reply); 1056 ctrlRequest("REASSOCIATE", reply, &reply_len); 1057 } 1058 1059 1060 void WpaGui::selectNetwork( const QString &sel ) 1061 { 1062 QString cmd(sel); 1063 char reply[10]; 1064 size_t reply_len = sizeof(reply); 1065 1066 if (cmd.contains(QRegExp("^\\d+:"))) 1067 cmd.truncate(cmd.indexOf(':')); 1068 else 1069 cmd = "any"; 1070 cmd.prepend("SELECT_NETWORK "); 1071 ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); 1072 triggerUpdate(); 1073 stopWpsRun(false); 1074 } 1075 1076 1077 void WpaGui::enableNetwork(const QString &sel) 1078 { 1079 QString cmd(sel); 1080 char reply[10]; 1081 size_t reply_len = sizeof(reply); 1082 1083 if (cmd.contains(QRegExp("^\\d+:"))) 1084 cmd.truncate(cmd.indexOf(':')); 1085 else if (!cmd.startsWith("all")) { 1086 debug("Invalid editNetwork '%s'", 1087 cmd.toLocal8Bit().constData()); 1088 return; 1089 } 1090 cmd.prepend("ENABLE_NETWORK "); 1091 ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); 1092 triggerUpdate(); 1093 } 1094 1095 1096 void WpaGui::disableNetwork(const QString &sel) 1097 { 1098 QString cmd(sel); 1099 char reply[10]; 1100 size_t reply_len = sizeof(reply); 1101 1102 if (cmd.contains(QRegExp("^\\d+:"))) 1103 cmd.truncate(cmd.indexOf(':')); 1104 else if (!cmd.startsWith("all")) { 1105 debug("Invalid editNetwork '%s'", 1106 cmd.toLocal8Bit().constData()); 1107 return; 1108 } 1109 cmd.prepend("DISABLE_NETWORK "); 1110 ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); 1111 triggerUpdate(); 1112 } 1113 1114 1115 void WpaGui::editNetwork(const QString &sel) 1116 { 1117 QString cmd(sel); 1118 int id = -1; 1119 1120 if (cmd.contains(QRegExp("^\\d+:"))) { 1121 cmd.truncate(cmd.indexOf(':')); 1122 id = cmd.toInt(); 1123 } 1124 1125 NetworkConfig *nc = new NetworkConfig(); 1126 if (nc == NULL) 1127 return; 1128 nc->setWpaGui(this); 1129 1130 if (id >= 0) 1131 nc->paramsFromConfig(id); 1132 else 1133 nc->newNetwork(); 1134 1135 nc->show(); 1136 nc->exec(); 1137 } 1138 1139 1140 void WpaGui::editSelectedNetwork() 1141 { 1142 if (networkSelect->count() < 1) { 1143 QMessageBox::information( 1144 this, tr("No Networks"), 1145 tr("There are no networks to edit.\n")); 1146 return; 1147 } 1148 QString sel(networkSelect->currentText()); 1149 editNetwork(sel); 1150 } 1151 1152 1153 void WpaGui::editListedNetwork() 1154 { 1155 if (networkList->currentRow() < 0) { 1156 QMessageBox::information(this, tr("Select A Network"), 1157 tr("Select a network from the list to" 1158 " edit it.\n")); 1159 return; 1160 } 1161 QString sel(networkList->currentItem()->text()); 1162 editNetwork(sel); 1163 } 1164 1165 1166 void WpaGui::triggerUpdate() 1167 { 1168 updateStatus(); 1169 networkMayHaveChanged = true; 1170 updateNetworks(); 1171 } 1172 1173 1174 void WpaGui::addNetwork() 1175 { 1176 NetworkConfig *nc = new NetworkConfig(); 1177 if (nc == NULL) 1178 return; 1179 nc->setWpaGui(this); 1180 nc->newNetwork(); 1181 nc->show(); 1182 nc->exec(); 1183 } 1184 1185 1186 void WpaGui::removeNetwork(const QString &sel) 1187 { 1188 QString cmd(sel); 1189 char reply[10]; 1190 size_t reply_len = sizeof(reply); 1191 1192 if (cmd.contains(QRegExp("^\\d+:"))) 1193 cmd.truncate(cmd.indexOf(':')); 1194 else if (!cmd.startsWith("all")) { 1195 debug("Invalid editNetwork '%s'", 1196 cmd.toLocal8Bit().constData()); 1197 return; 1198 } 1199 cmd.prepend("REMOVE_NETWORK "); 1200 ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); 1201 triggerUpdate(); 1202 } 1203 1204 1205 void WpaGui::removeSelectedNetwork() 1206 { 1207 if (networkSelect->count() < 1) { 1208 QMessageBox::information(this, tr("No Networks"), 1209 tr("There are no networks to remove." 1210 "\n")); 1211 return; 1212 } 1213 QString sel(networkSelect->currentText()); 1214 removeNetwork(sel); 1215 } 1216 1217 1218 void WpaGui::removeListedNetwork() 1219 { 1220 if (networkList->currentRow() < 0) { 1221 QMessageBox::information(this, tr("Select A Network"), 1222 tr("Select a network from the list " 1223 "to remove it.\n")); 1224 return; 1225 } 1226 QString sel(networkList->currentItem()->text()); 1227 removeNetwork(sel); 1228 } 1229 1230 1231 void WpaGui::enableAllNetworks() 1232 { 1233 QString sel("all"); 1234 enableNetwork(sel); 1235 } 1236 1237 1238 void WpaGui::disableAllNetworks() 1239 { 1240 QString sel("all"); 1241 disableNetwork(sel); 1242 } 1243 1244 1245 void WpaGui::removeAllNetworks() 1246 { 1247 QString sel("all"); 1248 removeNetwork(sel); 1249 } 1250 1251 1252 int WpaGui::getNetworkDisabled(const QString &sel) 1253 { 1254 QString cmd(sel); 1255 char reply[10]; 1256 size_t reply_len = sizeof(reply) - 1; 1257 int pos = cmd.indexOf(':'); 1258 if (pos < 0) { 1259 debug("Invalid getNetworkDisabled '%s'", 1260 cmd.toLocal8Bit().constData()); 1261 return -1; 1262 } 1263 cmd.truncate(pos); 1264 cmd.prepend("GET_NETWORK "); 1265 cmd.append(" disabled"); 1266 1267 if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) >= 0 1268 && reply_len >= 1) { 1269 reply[reply_len] = '\0'; 1270 if (!str_match(reply, "FAIL")) 1271 return atoi(reply); 1272 } 1273 1274 return -1; 1275 } 1276 1277 1278 void WpaGui::updateNetworkDisabledStatus() 1279 { 1280 if (networkList->currentRow() < 0) 1281 return; 1282 1283 QString sel(networkList->currentItem()->text()); 1284 1285 switch (getNetworkDisabled(sel)) { 1286 case 0: 1287 if (!enableRadioButton->isChecked()) 1288 enableRadioButton->setChecked(true); 1289 return; 1290 case 1: 1291 if (!disableRadioButton->isChecked()) 1292 disableRadioButton->setChecked(true); 1293 return; 1294 } 1295 } 1296 1297 1298 void WpaGui::enableListedNetwork(bool enabled) 1299 { 1300 if (networkList->currentRow() < 0 || !enabled) 1301 return; 1302 1303 QString sel(networkList->currentItem()->text()); 1304 1305 if (getNetworkDisabled(sel) == 1) 1306 enableNetwork(sel); 1307 } 1308 1309 1310 void WpaGui::disableListedNetwork(bool disabled) 1311 { 1312 if (networkList->currentRow() < 0 || !disabled) 1313 return; 1314 1315 QString sel(networkList->currentItem()->text()); 1316 1317 if (getNetworkDisabled(sel) == 0) 1318 disableNetwork(sel); 1319 } 1320 1321 1322 void WpaGui::saveConfig() 1323 { 1324 char buf[10]; 1325 size_t len; 1326 1327 len = sizeof(buf) - 1; 1328 ctrlRequest("SAVE_CONFIG", buf, &len); 1329 1330 buf[len] = '\0'; 1331 1332 if (str_match(buf, "FAIL")) 1333 QMessageBox::warning( 1334 this, tr("Failed to save configuration"), 1335 tr("The configuration could not be saved.\n" 1336 "\n" 1337 "The update_config=1 configuration option\n" 1338 "must be used for configuration saving to\n" 1339 "be permitted.\n")); 1340 else 1341 QMessageBox::information( 1342 this, tr("Saved configuration"), 1343 tr("The current configuration was saved." 1344 "\n")); 1345 } 1346 1347 1348 void WpaGui::selectAdapter( const QString & sel ) 1349 { 1350 if (openCtrlConnection(sel.toLocal8Bit().constData()) < 0) 1351 debug("Failed to open control connection to " 1352 "wpa_supplicant."); 1353 updateStatus(); 1354 updateNetworks(); 1355 } 1356 1357 1358 void WpaGui::createTrayIcon(bool trayOnly) 1359 { 1360 QApplication::setQuitOnLastWindowClosed(false); 1361 1362 tray_icon = new QSystemTrayIcon(this); 1363 updateTrayIcon(TrayIconOffline); 1364 1365 connect(tray_icon, 1366 SIGNAL(activated(QSystemTrayIcon::ActivationReason)), 1367 this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); 1368 1369 ackTrayIcon = false; 1370 1371 tray_menu = new QMenu(this); 1372 1373 disconnectAction = new QAction(tr("&Disconnect"), this); 1374 reconnectAction = new QAction(tr("Re&connect"), this); 1375 connect(disconnectAction, SIGNAL(triggered()), this, 1376 SLOT(disconnect())); 1377 connect(reconnectAction, SIGNAL(triggered()), this, 1378 SLOT(connectB())); 1379 tray_menu->addAction(disconnectAction); 1380 tray_menu->addAction(reconnectAction); 1381 tray_menu->addSeparator(); 1382 1383 eventAction = new QAction(tr("&Event History"), this); 1384 scanAction = new QAction(tr("Scan &Results"), this); 1385 statAction = new QAction(tr("S&tatus"), this); 1386 connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory())); 1387 connect(scanAction, SIGNAL(triggered()), this, SLOT(scan())); 1388 connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus())); 1389 tray_menu->addAction(eventAction); 1390 tray_menu->addAction(scanAction); 1391 tray_menu->addAction(statAction); 1392 tray_menu->addSeparator(); 1393 1394 showAction = new QAction(tr("&Show Window"), this); 1395 hideAction = new QAction(tr("&Hide Window"), this); 1396 quitAction = new QAction(tr("&Quit"), this); 1397 connect(showAction, SIGNAL(triggered()), this, SLOT(show())); 1398 connect(hideAction, SIGNAL(triggered()), this, SLOT(hide())); 1399 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); 1400 tray_menu->addAction(showAction); 1401 tray_menu->addAction(hideAction); 1402 tray_menu->addSeparator(); 1403 tray_menu->addAction(quitAction); 1404 1405 tray_icon->setContextMenu(tray_menu); 1406 1407 tray_icon->show(); 1408 1409 if (!trayOnly) 1410 show(); 1411 inTray = trayOnly; 1412 } 1413 1414 1415 void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, 1416 const QString & msg) 1417 { 1418 if (!QSystemTrayIcon::supportsMessages()) 1419 return; 1420 1421 if (isVisible() || !tray_icon || !tray_icon->isVisible() || quietMode) 1422 return; 1423 1424 tray_icon->showMessage(qAppName(), msg, type, sec * 1000); 1425 } 1426 1427 1428 void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how) 1429 { 1430 switch (how) { 1431 /* use close() here instead of hide() and allow the 1432 * custom closeEvent handler take care of children */ 1433 case QSystemTrayIcon::Trigger: 1434 ackTrayIcon = true; 1435 if (isVisible()) { 1436 close(); 1437 inTray = true; 1438 } else { 1439 show(); 1440 inTray = false; 1441 } 1442 break; 1443 case QSystemTrayIcon::MiddleClick: 1444 showTrayStatus(); 1445 break; 1446 default: 1447 break; 1448 } 1449 } 1450 1451 1452 void WpaGui::showTrayStatus() 1453 { 1454 char buf[2048]; 1455 size_t len; 1456 1457 len = sizeof(buf) - 1; 1458 if (ctrlRequest("STATUS", buf, &len) < 0) 1459 return; 1460 buf[len] = '\0'; 1461 1462 QString msg, status(buf); 1463 1464 QStringList lines = status.split(QRegExp("\\n")); 1465 for (QStringList::Iterator it = lines.begin(); 1466 it != lines.end(); it++) { 1467 int pos = (*it).indexOf('=') + 1; 1468 if (pos < 1) 1469 continue; 1470 1471 if ((*it).startsWith("bssid=")) 1472 msg.append("BSSID:\t" + (*it).mid(pos) + "\n"); 1473 else if ((*it).startsWith("ssid=")) 1474 msg.append("SSID: \t" + (*it).mid(pos) + "\n"); 1475 else if ((*it).startsWith("pairwise_cipher=")) 1476 msg.append("PAIR: \t" + (*it).mid(pos) + "\n"); 1477 else if ((*it).startsWith("group_cipher=")) 1478 msg.append("GROUP:\t" + (*it).mid(pos) + "\n"); 1479 else if ((*it).startsWith("key_mgmt=")) 1480 msg.append("AUTH: \t" + (*it).mid(pos) + "\n"); 1481 else if ((*it).startsWith("wpa_state=")) 1482 msg.append("STATE:\t" + (*it).mid(pos) + "\n"); 1483 else if ((*it).startsWith("ip_address=")) 1484 msg.append("IP: \t" + (*it).mid(pos) + "\n"); 1485 else if ((*it).startsWith("Supplicant PAE state=")) 1486 msg.append("PAE: \t" + (*it).mid(pos) + "\n"); 1487 else if ((*it).startsWith("EAP state=")) 1488 msg.append("EAP: \t" + (*it).mid(pos) + "\n"); 1489 } 1490 1491 if (!msg.isEmpty()) 1492 showTrayMessage(QSystemTrayIcon::Information, 10, msg); 1493 } 1494 1495 1496 void WpaGui::updateTrayToolTip(const QString &msg) 1497 { 1498 if (tray_icon) 1499 tray_icon->setToolTip(msg); 1500 } 1501 1502 1503 void WpaGui::updateTrayIcon(TrayIconType type) 1504 { 1505 if (!tray_icon || currentIconType == type) 1506 return; 1507 1508 QIcon fallback_icon; 1509 QStringList names; 1510 1511 if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) 1512 fallback_icon = QIcon(":/icons/wpa_gui.svg"); 1513 else 1514 fallback_icon = QIcon(":/icons/wpa_gui.png"); 1515 1516 switch (type) { 1517 case TrayIconOffline: 1518 names << "network-wireless-offline-symbolic" 1519 << "network-wireless-offline" 1520 << "network-wireless-signal-none-symbolic" 1521 << "network-wireless-signal-none"; 1522 break; 1523 case TrayIconAcquiring: 1524 names << "network-wireless-acquiring-symbolic" 1525 << "network-wireless-acquiring"; 1526 break; 1527 case TrayIconConnected: 1528 names << "network-wireless-connected-symbolic" 1529 << "network-wireless-connected"; 1530 break; 1531 case TrayIconSignalNone: 1532 names << "network-wireless-signal-none-symbolic" 1533 << "network-wireless-signal-none"; 1534 break; 1535 case TrayIconSignalWeak: 1536 names << "network-wireless-signal-weak-symbolic" 1537 << "network-wireless-signal-weak"; 1538 break; 1539 case TrayIconSignalOk: 1540 names << "network-wireless-signal-ok-symbolic" 1541 << "network-wireless-signal-ok"; 1542 break; 1543 case TrayIconSignalGood: 1544 names << "network-wireless-signal-good-symbolic" 1545 << "network-wireless-signal-good"; 1546 break; 1547 case TrayIconSignalExcellent: 1548 names << "network-wireless-signal-excellent-symbolic" 1549 << "network-wireless-signal-excellent"; 1550 break; 1551 } 1552 1553 currentIconType = type; 1554 tray_icon->setIcon(loadThemedIcon(names, fallback_icon)); 1555 } 1556 1557 1558 QIcon WpaGui::loadThemedIcon(const QStringList &names, 1559 const QIcon &fallback) 1560 { 1561 QIcon icon; 1562 1563 for (QStringList::ConstIterator it = names.begin(); 1564 it != names.end(); it++) { 1565 icon = QIcon::fromTheme(*it); 1566 if (!icon.isNull()) 1567 return icon; 1568 } 1569 1570 return fallback; 1571 } 1572 1573 1574 void WpaGui::closeEvent(QCloseEvent *event) 1575 { 1576 if (eh) { 1577 eh->close(); 1578 delete eh; 1579 eh = NULL; 1580 } 1581 1582 if (scanres) { 1583 scanres->close(); 1584 delete scanres; 1585 scanres = NULL; 1586 } 1587 1588 if (peers) { 1589 peers->close(); 1590 delete peers; 1591 peers = NULL; 1592 } 1593 1594 if (udr) { 1595 udr->close(); 1596 delete udr; 1597 udr = NULL; 1598 } 1599 1600 if (tray_icon && !ackTrayIcon) { 1601 /* give user a visual hint that the tray icon exists */ 1602 if (QSystemTrayIcon::supportsMessages()) { 1603 hide(); 1604 showTrayMessage(QSystemTrayIcon::Information, 3, 1605 qAppName() + 1606 tr(" will keep running in " 1607 "the system tray.")); 1608 } else { 1609 QMessageBox::information(this, qAppName() + 1610 tr(" systray"), 1611 tr("The program will keep " 1612 "running in the system " 1613 "tray.")); 1614 } 1615 ackTrayIcon = true; 1616 } 1617 1618 event->accept(); 1619 } 1620 1621 1622 void WpaGui::wpsDialog() 1623 { 1624 wpaguiTab->setCurrentWidget(wpsTab); 1625 } 1626 1627 1628 void WpaGui::peersDialog() 1629 { 1630 if (peers) { 1631 peers->close(); 1632 delete peers; 1633 } 1634 1635 peers = new Peers(); 1636 if (peers == NULL) 1637 return; 1638 peers->setWpaGui(this); 1639 peers->show(); 1640 peers->exec(); 1641 } 1642 1643 1644 void WpaGui::tabChanged(int index) 1645 { 1646 if (index != 2) 1647 return; 1648 1649 if (wpsRunning) 1650 return; 1651 1652 wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); 1653 if (bssFromScan.isEmpty()) 1654 wpsApPinButton->setEnabled(false); 1655 } 1656 1657 1658 void WpaGui::wpsPbc() 1659 { 1660 char reply[20]; 1661 size_t reply_len = sizeof(reply); 1662 1663 if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0) 1664 return; 1665 1666 wpsPinEdit->setEnabled(false); 1667 if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) { 1668 wpsInstructions->setText(tr("Press the push button on the AP to " 1669 "start the PBC mode.")); 1670 } else { 1671 wpsInstructions->setText(tr("If you have not yet done so, press " 1672 "the push button on the AP to start " 1673 "the PBC mode.")); 1674 } 1675 wpsStatusText->setText(tr("Waiting for Registrar")); 1676 wpsRunning = true; 1677 } 1678 1679 1680 void WpaGui::wpsGeneratePin() 1681 { 1682 char reply[20]; 1683 size_t reply_len = sizeof(reply) - 1; 1684 1685 if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0) 1686 return; 1687 1688 reply[reply_len] = '\0'; 1689 1690 wpsPinEdit->setText(reply); 1691 wpsPinEdit->setEnabled(true); 1692 wpsInstructions->setText(tr("Enter the generated PIN into the Registrar " 1693 "(either the internal one in the AP or an " 1694 "external one).")); 1695 wpsStatusText->setText(tr("Waiting for Registrar")); 1696 wpsRunning = true; 1697 } 1698 1699 1700 void WpaGui::setBssFromScan(const QString &bssid) 1701 { 1702 bssFromScan = bssid; 1703 wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); 1704 wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8); 1705 wpsStatusText->setText(tr("WPS AP selected from scan results")); 1706 wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., " 1707 "from a label in the device, enter the eight " 1708 "digit AP PIN and click Use AP PIN button.")); 1709 } 1710 1711 1712 void WpaGui::wpsApPinChanged(const QString &text) 1713 { 1714 wpsApPinButton->setEnabled(text.length() == 8); 1715 } 1716 1717 1718 void WpaGui::wpsApPin() 1719 { 1720 char reply[20]; 1721 size_t reply_len = sizeof(reply); 1722 1723 QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text()); 1724 if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) < 0) 1725 return; 1726 1727 wpsStatusText->setText(tr("Waiting for AP/Enrollee")); 1728 wpsRunning = true; 1729 } 1730 1731 1732 void WpaGui::stopWpsRun(bool success) 1733 { 1734 if (wpsRunning) 1735 wpsStatusText->setText(success ? tr("Connected to the network") : 1736 tr("Stopped")); 1737 else 1738 wpsStatusText->setText(""); 1739 wpsPinEdit->setEnabled(false); 1740 wpsInstructions->setText(""); 1741 wpsRunning = false; 1742 bssFromScan = ""; 1743 wpsApPinEdit->setEnabled(false); 1744 wpsApPinButton->setEnabled(false); 1745 } 1746 1747 1748 #ifdef CONFIG_NATIVE_WINDOWS 1749 1750 #ifndef WPASVC_NAME 1751 #define WPASVC_NAME TEXT("wpasvc") 1752 #endif 1753 1754 class ErrorMsg : public QMessageBox { 1755 public: 1756 ErrorMsg(QWidget *parent, DWORD last_err = GetLastError()); 1757 void showMsg(QString msg); 1758 private: 1759 DWORD err; 1760 }; 1761 1762 ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) : 1763 QMessageBox(parent), err(last_err) 1764 { 1765 setWindowTitle(tr("wpa_gui error")); 1766 setIcon(QMessageBox::Warning); 1767 } 1768 1769 void ErrorMsg::showMsg(QString msg) 1770 { 1771 LPTSTR buf; 1772 1773 setText(msg); 1774 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1775 FORMAT_MESSAGE_FROM_SYSTEM, 1776 NULL, err, 0, (LPTSTR) (void *) &buf, 1777 0, NULL) > 0) { 1778 QString msg = QString::fromWCharArray(buf); 1779 setInformativeText(QString("[%1] %2").arg(err).arg(msg)); 1780 LocalFree(buf); 1781 } else { 1782 setInformativeText(QString("[%1]").arg(err)); 1783 } 1784 1785 exec(); 1786 } 1787 1788 1789 void WpaGui::startService() 1790 { 1791 SC_HANDLE svc, scm; 1792 1793 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); 1794 if (!scm) { 1795 ErrorMsg(this).showMsg(tr("OpenSCManager failed")); 1796 return; 1797 } 1798 1799 svc = OpenService(scm, WPASVC_NAME, SERVICE_START); 1800 if (!svc) { 1801 ErrorMsg(this).showMsg(tr("OpenService failed")); 1802 CloseServiceHandle(scm); 1803 return; 1804 } 1805 1806 if (!StartService(svc, 0, NULL)) { 1807 ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant " 1808 "service")); 1809 } 1810 1811 CloseServiceHandle(svc); 1812 CloseServiceHandle(scm); 1813 } 1814 1815 1816 void WpaGui::stopService() 1817 { 1818 SC_HANDLE svc, scm; 1819 SERVICE_STATUS status; 1820 1821 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); 1822 if (!scm) { 1823 ErrorMsg(this).showMsg(tr("OpenSCManager failed")); 1824 return; 1825 } 1826 1827 svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP); 1828 if (!svc) { 1829 ErrorMsg(this).showMsg(tr("OpenService failed")); 1830 CloseServiceHandle(scm); 1831 return; 1832 } 1833 1834 if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) { 1835 ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant " 1836 "service")); 1837 } 1838 1839 CloseServiceHandle(svc); 1840 CloseServiceHandle(scm); 1841 } 1842 1843 1844 bool WpaGui::serviceRunning() 1845 { 1846 SC_HANDLE svc, scm; 1847 SERVICE_STATUS status; 1848 bool running = false; 1849 1850 scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); 1851 if (!scm) { 1852 debug("OpenSCManager failed: %d", (int) GetLastError()); 1853 return false; 1854 } 1855 1856 svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS); 1857 if (!svc) { 1858 debug("OpenService failed: %d", (int) GetLastError()); 1859 CloseServiceHandle(scm); 1860 return false; 1861 } 1862 1863 if (QueryServiceStatus(svc, &status)) { 1864 if (status.dwCurrentState != SERVICE_STOPPED) 1865 running = true; 1866 } 1867 1868 CloseServiceHandle(svc); 1869 CloseServiceHandle(scm); 1870 1871 return running; 1872 } 1873 1874 #endif /* CONFIG_NATIVE_WINDOWS */ 1875 1876 1877 void WpaGui::addInterface() 1878 { 1879 if (add_iface) { 1880 add_iface->close(); 1881 delete add_iface; 1882 } 1883 add_iface = new AddInterface(this, this); 1884 add_iface->show(); 1885 add_iface->exec(); 1886 } 1887 1888 1889 #ifndef QT_NO_SESSIONMANAGER 1890 void WpaGui::saveState() 1891 { 1892 QSettings settings("wpa_supplicant", "wpa_gui"); 1893 settings.beginGroup("state"); 1894 settings.setValue("session_id", app->sessionId()); 1895 settings.setValue("in_tray", inTray); 1896 settings.endGroup(); 1897 } 1898 #endif 1899