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