You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
12 KiB
404 lines
12 KiB
#include <QDebug>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QPixmap>
|
|
#include <QPushButton>
|
|
#include <QLineEdit>
|
|
#include <QRandomGenerator>
|
|
#include <QtConcurrent>
|
|
|
|
#include "common/params.h"
|
|
#include "networking.hpp"
|
|
#include "util.h"
|
|
|
|
void clearLayout(QLayout* layout) {
|
|
while (QLayoutItem* item = layout->takeAt(0)) {
|
|
if (QWidget* widget = item->widget()) {
|
|
widget->deleteLater();
|
|
}
|
|
if (QLayout* childLayout = item->layout()) {
|
|
clearLayout(childLayout);
|
|
}
|
|
delete item;
|
|
}
|
|
}
|
|
|
|
QWidget* layoutToWidget(QLayout* l, QWidget* parent){
|
|
QWidget* q = new QWidget(parent);
|
|
q->setLayout(l);
|
|
return q;
|
|
}
|
|
|
|
// https://stackoverflow.com/questions/478898/how-do-i-execute-a-command-and-get-the-output-of-the-command-within-c-using-po
|
|
std::string exec(const char* cmd) {
|
|
std::array<char, 128> buffer;
|
|
std::string result;
|
|
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
|
if (!pipe) {
|
|
throw std::runtime_error("popen() failed!");
|
|
}
|
|
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
|
result += buffer.data();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Networking functions
|
|
|
|
Networking::Networking(QWidget* parent, bool show_advanced) : QWidget(parent), show_advanced(show_advanced){
|
|
s = new QStackedLayout;
|
|
|
|
QLabel* warning = new QLabel("Network manager is inactive!");
|
|
warning->setStyleSheet(R"(font-size: 65px;)");
|
|
|
|
s->addWidget(warning);
|
|
setLayout(s);
|
|
|
|
QTimer* timer = new QTimer(this);
|
|
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(refresh()));
|
|
timer->start(5000);
|
|
attemptInitialization();
|
|
}
|
|
|
|
void Networking::attemptInitialization(){
|
|
// Checks if network manager is active
|
|
try {
|
|
wifi = new WifiManager(this);
|
|
} catch (std::exception &e) {
|
|
return;
|
|
}
|
|
|
|
connect(wifi, SIGNAL(wrongPassword(QString)), this, SLOT(wrongPassword(QString)));
|
|
|
|
QVBoxLayout* vlayout = new QVBoxLayout;
|
|
|
|
if (show_advanced) {
|
|
QPushButton* advancedSettings = new QPushButton("Advanced");
|
|
advancedSettings->setStyleSheet(R"(margin-right: 30px)");
|
|
advancedSettings->setFixedSize(350, 100);
|
|
connect(advancedSettings, &QPushButton::released, [=](){s->setCurrentWidget(an);});
|
|
vlayout->addSpacing(10);
|
|
vlayout->addWidget(advancedSettings, 0, Qt::AlignRight);
|
|
vlayout->addSpacing(10);
|
|
}
|
|
|
|
wifiWidget = new WifiUI(0, 5, wifi);
|
|
connect(wifiWidget, SIGNAL(connectToNetwork(Network)), this, SLOT(connectToNetwork(Network)));
|
|
vlayout->addWidget(wifiWidget, 1);
|
|
|
|
wifiScreen = layoutToWidget(vlayout, this);
|
|
s->addWidget(wifiScreen);
|
|
|
|
an = new AdvancedNetworking(this, wifi);
|
|
connect(an, &AdvancedNetworking::backPress, [=](){s->setCurrentWidget(wifiScreen);});
|
|
s->addWidget(an);
|
|
|
|
setStyleSheet(R"(
|
|
QPushButton {
|
|
font-size: 50px;
|
|
margin: 0px;
|
|
padding: 15px;
|
|
border-width: 0;
|
|
border-radius: 30px;
|
|
color: #dddddd;
|
|
background-color: #444444;
|
|
}
|
|
QPushButton:disabled {
|
|
color: #777777;
|
|
background-color: #222222;
|
|
}
|
|
)");
|
|
s->setCurrentWidget(wifiScreen);
|
|
ui_setup_complete = true;
|
|
}
|
|
|
|
void Networking::refresh(){
|
|
if (!this->isVisible()) {
|
|
return;
|
|
}
|
|
if (!ui_setup_complete) {
|
|
attemptInitialization();
|
|
if (!ui_setup_complete) {
|
|
return;
|
|
}
|
|
}
|
|
wifiWidget->refresh();
|
|
an->refresh();
|
|
}
|
|
|
|
void Networking::connectToNetwork(Network n) {
|
|
if (n.security_type == SecurityType::OPEN) {
|
|
wifi->connect(n);
|
|
} else if (n.security_type == SecurityType::WPA) {
|
|
QString pass = InputDialog::getText("Enter password for \"" + n.ssid + "\"");
|
|
wifi->connect(n, pass);
|
|
}
|
|
}
|
|
|
|
void Networking::wrongPassword(QString ssid) {
|
|
return; // TODO: add this back
|
|
/*
|
|
for (Network n : wifi->seen_networks) {
|
|
if (n.ssid == ssid) {
|
|
inputField->setPromptText("Wrong password for \"" + n.ssid +"\"");
|
|
s->setCurrentIndex(0);
|
|
emit openKeyboard();
|
|
return;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
QFrame* hline(QWidget* parent = 0){
|
|
QFrame* line = new QFrame(parent);
|
|
line->setFrameShape(QFrame::StyledPanel);
|
|
line->setStyleSheet("margin-left: 40px; margin-right: 40px; border-width: 1px; border-bottom-style: solid; border-color: gray;");
|
|
line->setFixedHeight(2);
|
|
return line;
|
|
}
|
|
|
|
// AdvancedNetworking functions
|
|
|
|
AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWidget(parent), wifi(wifi){
|
|
s = new QStackedLayout; // mainPage, SSH settings
|
|
|
|
QVBoxLayout* vlayout = new QVBoxLayout;
|
|
|
|
// Back button
|
|
QHBoxLayout* backLayout = new QHBoxLayout;
|
|
QPushButton* back = new QPushButton("Back");
|
|
back->setFixedSize(500, 100);
|
|
connect(back, &QPushButton::released, [=](){emit backPress();});
|
|
backLayout->addWidget(back, 0, Qt::AlignLeft);
|
|
vlayout->addWidget(layoutToWidget(backLayout, this), 0, Qt::AlignLeft);
|
|
|
|
// Enable tethering layout
|
|
QHBoxLayout* tetheringToggleLayout = new QHBoxLayout;
|
|
tetheringToggleLayout->addWidget(new QLabel("Enable tethering"));
|
|
Toggle* toggle_switch = new Toggle;
|
|
toggle_switch->setFixedSize(150, 100);
|
|
tetheringToggleLayout->addWidget(toggle_switch);
|
|
tetheringToggleLayout->addSpacing(40);
|
|
if (wifi->tetheringEnabled()) {
|
|
toggle_switch->togglePosition();
|
|
}
|
|
QObject::connect(toggle_switch, SIGNAL(stateChanged(int)), this, SLOT(toggleTethering(int)));
|
|
vlayout->addWidget(layoutToWidget(tetheringToggleLayout, this), 0);
|
|
vlayout->addWidget(hline(), 0);
|
|
|
|
// Change tethering password
|
|
QHBoxLayout *tetheringPassword = new QHBoxLayout;
|
|
tetheringPassword->addWidget(new QLabel("Edit tethering password"), 1);
|
|
editPasswordButton = new QPushButton("EDIT");
|
|
editPasswordButton->setFixedWidth(500);
|
|
connect(editPasswordButton, &QPushButton::released, [=](){
|
|
QString pass = InputDialog::getText("Enter new tethering password");
|
|
if (pass.size()) {
|
|
wifi->changeTetheringPassword(pass);
|
|
}
|
|
});
|
|
tetheringPassword->addWidget(editPasswordButton, 1, Qt::AlignRight);
|
|
vlayout->addWidget(layoutToWidget(tetheringPassword, this), 0);
|
|
vlayout->addWidget(hline(), 0);
|
|
|
|
// IP adress
|
|
QHBoxLayout* IPlayout = new QHBoxLayout;
|
|
IPlayout->addWidget(new QLabel("IP address"), 0);
|
|
ipLabel = new QLabel(wifi->ipv4_address);
|
|
ipLabel->setStyleSheet("color: #aaaaaa");
|
|
IPlayout->addWidget(ipLabel, 0, Qt::AlignRight);
|
|
vlayout->addWidget(layoutToWidget(IPlayout, this), 0);
|
|
vlayout->addWidget(hline(), 0);
|
|
|
|
// Enable SSH
|
|
QHBoxLayout* enableSSHLayout = new QHBoxLayout(this);
|
|
enableSSHLayout->addWidget(new QLabel("Enable SSH", this));
|
|
toggle_switch_SSH = new Toggle(this);
|
|
toggle_switch_SSH->setFixedSize(150, 100);
|
|
if (isSSHEnabled()) {
|
|
toggle_switch_SSH->togglePosition();
|
|
}
|
|
QObject::connect(toggle_switch_SSH, SIGNAL(stateChanged(int)), this, SLOT(toggleSSH(int)));
|
|
enableSSHLayout->addWidget(toggle_switch_SSH);
|
|
vlayout->addWidget(layoutToWidget(enableSSHLayout, this));
|
|
vlayout->addWidget(hline(), 0);
|
|
|
|
// SSH keys
|
|
QHBoxLayout* authSSHLayout = new QHBoxLayout(this);
|
|
authSSHLayout->addWidget(new QLabel("SSH keys", this));
|
|
QPushButton* editAuthSSHButton = new QPushButton("EDIT", this);
|
|
editAuthSSHButton->setFixedWidth(500);
|
|
connect(editAuthSSHButton, &QPushButton::released, [=](){s->setCurrentWidget(ssh);});
|
|
authSSHLayout->addWidget(editAuthSSHButton);
|
|
vlayout->addWidget(layoutToWidget(authSSHLayout, this));
|
|
vlayout->addSpacing(50);
|
|
|
|
// //Disconnect or delete connections
|
|
// QHBoxLayout* dangerZone = new QHBoxLayout(this);
|
|
// QPushButton* disconnect = new QPushButton("Disconnect from WiFi", this);
|
|
// dangerZone->addWidget(disconnect);
|
|
// QPushButton* deleteAll = new QPushButton("DELETE ALL NETWORKS", this);
|
|
// dangerZone->addWidget(deleteAll);
|
|
// vlayout->addWidget(layoutToWidget(dangerZone, this));
|
|
|
|
// vlayout to widget
|
|
QWidget* settingsWidget = layoutToWidget(vlayout, this);
|
|
settingsWidget->setStyleSheet("margin-left: 40px; margin-right: 40px;");
|
|
s->addWidget(settingsWidget);
|
|
|
|
ssh = new SSH;
|
|
connect(ssh, &SSH::closeSSHSettings, [=](){s->setCurrentWidget(settingsWidget);});
|
|
s->addWidget(ssh);
|
|
|
|
setLayout(s);
|
|
}
|
|
|
|
bool AdvancedNetworking::isSSHEnabled(){
|
|
QString response = QString::fromStdString(exec("systemctl is-active ssh"));
|
|
return response.startsWith("active");
|
|
}
|
|
|
|
void AdvancedNetworking::refresh(){
|
|
ipLabel->setText(wifi->ipv4_address);
|
|
// Don't refresh while changing SSH state
|
|
if(!toggle_switch_SSH->getEnabled()){
|
|
return;
|
|
}
|
|
if (toggle_switch_SSH->on != isSSHEnabled()) {
|
|
toggle_switch_SSH->togglePosition();
|
|
}
|
|
// Qt can be lazy
|
|
repaint();
|
|
}
|
|
|
|
void AdvancedNetworking::toggleTethering(int enable) {
|
|
if (enable) {
|
|
wifi->enableTethering();
|
|
} else {
|
|
wifi->disableTethering();
|
|
}
|
|
editPasswordButton->setEnabled(!enable);
|
|
}
|
|
|
|
void enableSSH(Toggle* toggle_switch_SSH){
|
|
Params().write_db_value("SshEnabled", "1");
|
|
toggle_switch_SSH->setEnabled(true);
|
|
}
|
|
|
|
void disableSSH(Toggle* toggle_switch_SSH){
|
|
Params().write_db_value("SshEnabled", "0");
|
|
toggle_switch_SSH->setEnabled(true);
|
|
}
|
|
|
|
void AdvancedNetworking::toggleSSH(int enable) {
|
|
toggle_switch_SSH->setEnabled(false);
|
|
if (enable) {
|
|
QtConcurrent::run(enableSSH, toggle_switch_SSH);
|
|
} else {
|
|
QtConcurrent::run(disableSSH, toggle_switch_SSH);
|
|
}
|
|
}
|
|
|
|
|
|
// WifiUI functions
|
|
|
|
WifiUI::WifiUI(QWidget *parent, int page_length, WifiManager* wifi) : QWidget(parent), networks_per_page(page_length), wifi(wifi) {
|
|
vlayout = new QVBoxLayout;
|
|
|
|
// Scan on startup
|
|
QLabel *scanning = new QLabel("Scanning for networks");
|
|
scanning->setStyleSheet(R"(font-size: 65px;)");
|
|
vlayout->addWidget(scanning, 0, Qt::AlignCenter);
|
|
vlayout->setSpacing(25);
|
|
|
|
setLayout(vlayout);
|
|
page = 0;
|
|
}
|
|
|
|
void WifiUI::refresh() {
|
|
wifi->request_scan();
|
|
wifi->refreshNetworks();
|
|
clearLayout(vlayout);
|
|
|
|
connectButtons = new QButtonGroup(this); // TODO check if this is a leak
|
|
QObject::connect(connectButtons, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(handleButton(QAbstractButton*)));
|
|
|
|
int i = 0;
|
|
int countWidgets = 0;
|
|
for (Network &network : wifi->seen_networks) {
|
|
QHBoxLayout *hlayout = new QHBoxLayout;
|
|
if (page * networks_per_page <= i && i < (page + 1) * networks_per_page) {
|
|
// SSID
|
|
hlayout->addSpacing(50);
|
|
QString ssid = QString::fromUtf8(network.ssid);
|
|
if(ssid.length() > 20){
|
|
ssid = ssid.left(20 - 3) + "…";
|
|
}
|
|
|
|
QLabel *ssid_label = new QLabel(ssid);
|
|
ssid_label->setStyleSheet(R"(
|
|
font-size: 55px;
|
|
)");
|
|
ssid_label->setFixedWidth(this->width()*0.5);
|
|
hlayout->addWidget(ssid_label, 0, Qt::AlignLeft);
|
|
|
|
// TODO: don't use images for this
|
|
// strength indicator
|
|
unsigned int strength_scale = network.strength / 17;
|
|
QPixmap pix("../assets/images/network_" + QString::number(strength_scale) + ".png");
|
|
QLabel *icon = new QLabel();
|
|
icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation));
|
|
icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
|
|
hlayout->addWidget(icon, 0, Qt::AlignRight);
|
|
|
|
// connect button
|
|
QPushButton* btn = new QPushButton(network.security_type == SecurityType::UNSUPPORTED ? "Unsupported" : (network.connected == ConnectedType::CONNECTED ? "Connected" : (network.connected == ConnectedType::CONNECTING ? "Connecting" : "Connect")));
|
|
btn->setDisabled(network.connected == ConnectedType::CONNECTED || network.connected == ConnectedType::CONNECTING || network.security_type == SecurityType::UNSUPPORTED);
|
|
btn->setFixedWidth(350);
|
|
hlayout->addWidget(btn, 0, Qt::AlignRight);
|
|
|
|
connectButtons->addButton(btn, i);
|
|
|
|
vlayout->addLayout(hlayout, 1);
|
|
// Don't add the last horizontal line
|
|
if (page * networks_per_page <= i+1 && i+1 < (page + 1) * networks_per_page && i+1 < wifi->seen_networks.size()) {
|
|
vlayout->addWidget(hline(), 0);
|
|
}
|
|
countWidgets++;
|
|
}
|
|
i++;
|
|
}
|
|
vlayout->addStretch(3);
|
|
|
|
|
|
// Setup buttons for pagination
|
|
QHBoxLayout *prev_next_buttons = new QHBoxLayout;
|
|
|
|
QPushButton* prev = new QPushButton("Previous");
|
|
prev->setEnabled(page);
|
|
QObject::connect(prev, SIGNAL(released()), this, SLOT(prevPage()));
|
|
prev_next_buttons->addWidget(prev);
|
|
|
|
QPushButton* next = new QPushButton("Next");
|
|
next->setEnabled(wifi->seen_networks.size() > (page + 1) * networks_per_page);
|
|
QObject::connect(next, SIGNAL(released()), this, SLOT(nextPage()));
|
|
prev_next_buttons->addWidget(next);
|
|
|
|
vlayout->addLayout(prev_next_buttons, 2);
|
|
}
|
|
|
|
void WifiUI::handleButton(QAbstractButton* button) {
|
|
QPushButton* btn = static_cast<QPushButton*>(button);
|
|
Network n = wifi->seen_networks[connectButtons->id(btn)];
|
|
emit connectToNetwork(n);
|
|
}
|
|
|
|
void WifiUI::prevPage() {
|
|
page--;
|
|
refresh();
|
|
}
|
|
|
|
void WifiUI::nextPage() {
|
|
page++;
|
|
refresh();
|
|
}
|
|
|