summaryrefslogblamecommitdiff
path: root/ui/qt5/netsimplewifipage.cc
blob: 49b77ff106a2f1df6b345f8e7c3813e4e265fbcf (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                                           
                               
                         
 
                   
                  

                      






                                                                                              
                                                                     
                                                        
                        






                                                             



                                                                          
                      

                                                     
                     
                             
 








                                                        
                                                        
                           
                                                      

                      
 










                                                           
                                          
                      
                          
                                    



                                                         





                                                            

                                                                                                      
     


                                                        
                                                                                    











                                                                     
                                  







                                                                                    
                     






                                                                            




                                                                               

                                                                              



                                                                 
                                                                      






                                     
                                       



                             
 
 

                                                  

 



                                                    

                                               
 

                      
                                                                                
                          
 
                                 

              
                                                            

                                                                   


                                                                         



                     












                                                                                


                                            

                   
                                        
                                                                    
                                               
                                                                    
                                               
                                                                  
                                               




                                                                         





                                                                        


             











                                                                                
/*
 * netsimplewifipage.cc - Implementation of the UI.Network.Wireless page
 * horizon-qt5, the Qt 5 user interface for
 * Project Horizon
 *
 * Copyright (c) 2019 Adélie Linux and contributors.  All rights reserved.
 * This code is licensed under the AGPL 3.0 license, as noted in the
 * LICENSE-code file in the root directory of this repository.
 *
 * SPDX-License-Identifier: AGPL-3.0-only
 */

#include "netsimplewifipage.hh"
#include "netdhcppage.hh"

#include <assert.h>
#include <sstream>
#include <QVBoxLayout>

#ifdef HAS_INSTALL_ENV
int scanResults(wpactrl_t *control, char const *s, size_t len, void *page, tain_t *) {
    NetworkSimpleWirelessPage *our_page = reinterpret_cast<NetworkSimpleWirelessPage *>(page);
    return our_page->processScan(control, s, len);
}
#endif  /* HAS_INSTALL_ENV */

NetworkSimpleWirelessPage::NetworkSimpleWirelessPage(QWidget *parent)
    : HorizonWizardPage(parent), control(WPACTRL_ZERO) {
    QVBoxLayout *layout;

    loadWatermark("network");
    setTitle(tr("Select Your Network"));

    statusLabel = new QLabel(tr("Scanning for networks..."));

    rescanButton = new QPushButton(tr("&Rescan Networks"));
    connect(rescanButton, &QPushButton::clicked, [=](void) { doScan(); });

    ssidListView = new QListWidget;

#ifdef HAS_INSTALL_ENV
    exchange_item.filter = "CTRL-EVENT-SCAN-RESULTS";
    exchange_item.cb = &scanResults;
    notify = nullptr;
#endif  /* HAS_INSTALL_ENV */

    passphrase = new QLineEdit(this);
    passphrase->setEchoMode(QLineEdit::Password);
    passphrase->setPlaceholderText(tr("Passphrase"));
    passphrase->hide();

    layout = new QVBoxLayout;
    layout->addWidget(statusLabel, 0, Qt::AlignCenter);
    layout->addSpacing(10);
    layout->addWidget(ssidListView, 0, Qt::AlignCenter);
    layout->addWidget(rescanButton, 0, Qt::AlignCenter);
    layout->addSpacing(10);
    layout->addWidget(passphrase, 0, Qt::AlignCenter);
    setLayout(layout);
}

NetworkSimpleWirelessPage::~NetworkSimpleWirelessPage() {
#ifdef HAS_INSTALL_ENV
    wpactrl_end(&control);
#endif  /* HAS_INSTALL_ENV */
}

void NetworkSimpleWirelessPage::scanDone(QString message) {
    rescanButton->setEnabled(true);
    statusLabel->setText(message);
}

void NetworkSimpleWirelessPage::doScan() {
#ifdef HAS_INSTALL_ENV
    ssidListView->clear();
    rescanButton->setEnabled(false);
    statusLabel->setText(tr("Scanning for networks..."));

    tain_t deadline;
    wparesponse_t response;
    std::string suppsock = "/var/run/wpa_supplicant/" +
            horizonWizard()->chosen_auto_iface;

    tain_now_g();
    if(!wpactrl_start_g(&control, suppsock.c_str(), 2000)) {
        rescanButton->setEnabled(false);
        statusLabel->setText(tr("Couldn't communicate with wireless subsystem (Code %1)").arg(errno));
        return;
    }

    response = wpactrl_command_g(&control, "SCAN");
    if(response != WPA_OK && response != WPA_FAILBUSY) {
        scanDone(tr("Couldn't scan for wireless networks (Code %1)").arg(response));
        return;
    }

    tain_from_millisecs(&deadline, 15000);
    tain_add_g(&deadline, &deadline);
    wpactrl_xchg_init(&exchange, &exchange_item, 1, &deadline, this);
    if(!wpactrl_xchg_start(&control, &exchange)) {
        scanDone(tr("Failed to scan for wireless networks."));
        return;
    }

    if(notify != nullptr) {
        notify->setEnabled(false);
        notify->deleteLater();
        notify = nullptr;
    }

    notify = new QSocketNotifier(wpactrl_fd(&control), QSocketNotifier::Read, this);
    connect(notify, &QSocketNotifier::activated, [=](int) {
        QString status;

        tain_now_g();
        if(wpactrl_xchg_timeout_g(&control, &exchange)) {
            status = tr("Network scan timed out.");
        } else {
            if(wpactrl_update(&control) < 0) {
                status = tr("Issue communicating with wireless subsystem.");
            } else {
                int code = wpactrl_xchg_event_g(&control, &exchange);
                if(code == -2) {
                    /* if the callback is what failed, we already set status */
                    status = statusLabel->text();
                } else if(code < 0) {
                    /* non-callback failure */
                    status = tr("Issue processing scanned networks (Code %1)")
                            .arg(code);
                } else if(code == 0) {
                    /* Not finished yet, so don't do anything. */
                    return;
                } else {
                    status = tr("Select your network from the list.");
                }
            }
        }
        notify->setEnabled(false);
        notify->deleteLater();
        notify = nullptr;
        statusLabel->setText(status);
        rescanButton->setEnabled(true);
        return;
    });
    notify->setEnabled(true);
#endif  /* HAS_INSTALL_ENV */
}

void NetworkSimpleWirelessPage::initializePage() {
    doScan();
}

bool NetworkSimpleWirelessPage::isComplete() const {
    return (ssidListView->currentRow() != -1);
}

int NetworkSimpleWirelessPage::nextId() const {
    return HorizonWizard::Page_Network_DHCP;
}

#ifdef HAS_INSTALL_ENV
int NetworkSimpleWirelessPage::processScan(wpactrl_t *c, const char *, size_t) {
    assert(c == &control);

    stralloc buf = STRALLOC_ZERO;

    errno = 0;
    if(!wpactrl_querysa_g(&control, "SCAN_RESULTS", &buf)) {
        if(errno == EMSGSIZE) {
            statusLabel->setText(tr("Scan failed: Out of memory"));
            return 0;
        } else {
            statusLabel->setText(tr("Scan failed (Code %1)").arg(errno));
            return 0;
        }
    }

    genalloc nets = GENALLOC_ZERO;
    stralloc netstr = STRALLOC_ZERO;
    errno = 0;

    if(wpactrl_scan_parse(buf.s, buf.len, &nets, &netstr) != 0) {
        statusLabel->setText(tr("Network listing failed (Code %1)").arg(errno));
        return 0;
    }

    wpactrl_scanres_t *netarray = genalloc_s(wpactrl_scanres_t, &nets);
    for(size_t net = 0; net < genalloc_len(wpactrl_scanres_t, &nets); net++) {
        wpactrl_scanres_t network = netarray[net];
        std::string ssid(netstr.s + network.ssid_start, network.ssid_len);

        /* Don't bother with empty SSIDs. */
        if(ssid.empty()) continue;

        QIcon icon;
        if(network.signal_level < -90) {
            icon = QIcon::fromTheme("network-wireless-signal-none");
        } else if(network.signal_level < -80) {
            icon = QIcon::fromTheme("network-wireless-signal-weak");
        } else if(network.signal_level < -67) {
            icon = QIcon::fromTheme("network-wireless-signal-ok");
        } else if(network.signal_level < -50) {
            icon = QIcon::fromTheme("network-wireless-signal-good");
        } else {
            icon = QIcon::fromTheme("network-wireless-signal-excellent");
        }

        QListWidgetItem *netitem = new QListWidgetItem(ssidListView);
        netitem->setText(QString::fromStdString(ssid));
        netitem->setIcon(icon);
        netitem->setToolTip(tr("Frequency: %1 MHz\nBSSID: %2\nRSSI: %3")
                            .arg(network.frequency).arg("bssid.c_str()")
                            .arg(network.signal_level));
    }

    return 1;
}
#endif  /* HAS_INSTALL_ENV */

bool NetworkSimpleWirelessPage::validatePage() {
    /* What a hack!
     *
     * Independent Pages means the DHCP page is never cleaned, even when Back
     * is chosen.  So, we have to do it from here. */
    horizonWizard()->removePage(HorizonWizard::Page_Network_DHCP);
    horizonWizard()->setPage(HorizonWizard::Page_Network_DHCP, new NetDHCPPage);
    return true;
}