summaryrefslogblamecommitdiff
path: root/ui/qt5/netdhcppage.cc
blob: bf223f0dfbd58d3cfe6eaf39007c53a8ceb83666 (plain) (tree)












































































































































































                                                                                                                                      
/*
 * netdhcppage.cc - Implementation of the UI.Network.Automatic 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 "netdhcppage.hh"
#include "horizonhelpwindow.hh"

#include <assert.h>
#include <QGridLayout>
#include <QProcess>
#include <QUrl>
#include <QVBoxLayout>

NetDHCPPage::NetDHCPPage(QWidget *parent) : HorizonWizardPage(parent) {
    setTitle(tr("Automatic Network Configuration"));
    loadWatermark("network");

    QLabel *overall = new QLabel(tr("Please wait while System Installation performs the following tasks:"));
    information = new QLabel;
    information->setWordWrap(true);

    addrStatus = new QLabel;
    address = new QLabel(tr("Obtain a network address"));
    inetStatus = new QLabel;
    inet = new QLabel(tr("Check Internet connectivity"));

    QGridLayout *progressLayout = new QGridLayout;
    progressLayout->addWidget(addrStatus, 0, 0);
    progressLayout->addWidget(address, 0, 1);
    progressLayout->addWidget(inetStatus, 1, 0);
    progressLayout->addWidget(inet, 1, 1);
    progressLayout->setColumnStretch(1, 100);

    logButton = new QPushButton(tr("Review DHCP Log"));
    logButton->setHidden(true);
    connect(logButton, &QPushButton::clicked, [=]() {
        QFile logfile("/var/log/horizon/dhcpcd.log");
        logfile.open(QFile::ReadOnly);
        HorizonHelpWindow logview(&logfile, this, true);
        logview.exec();
    });

    QVBoxLayout *overallLayout = new QVBoxLayout(this);
    overallLayout->addWidget(overall);
    overallLayout->addSpacing(40);
    overallLayout->addLayout(progressLayout);
    overallLayout->addSpacing(40);
    overallLayout->addWidget(information);
    overallLayout->addWidget(logButton, 0, Qt::AlignCenter);
}

void NetDHCPPage::startDHCP() {
    QProcess *dhcpcd = new QProcess(this);
    QString iface(QString::fromStdString(horizonWizard()->chosen_auto_iface));
    dhcpcd->setProgram("dhcpcd");
    dhcpcd->setArguments({"-q", "-t", "15", "-n",
                          "-j", "/var/log/horizon/dhcpcd.log", iface});
    connect(dhcpcd, &QProcess::errorOccurred,
            [=](QProcess::ProcessError error) {
        addrStatus->setPixmap(loadDPIAwarePixmap("status-issue", ".svg"));
        if(error == QProcess::FailedToStart) {
            information->setText(tr("The Installation Environment is missing a critical component: dhcpcd could not be run."));
        } else {
            information->setText(tr("The system has encountered an internal issue."));
            logButton->setHidden(false);
        }
    });
    connect(dhcpcd, static_cast<void (QProcess:: *)(int)>(&QProcess::finished),
            this, &NetDHCPPage::dhcpFinished);
    dhcpcd->start();
}

void NetDHCPPage::dhcpFinished(int exitcode) {
    if(exitcode != 0) {
        addrStatus->setPixmap(loadDPIAwarePixmap("status-issue", ".svg"));
        information->setText(tr("The system could not obtain an address."));
        logButton->setHidden(false);
    } else {
        addrStatus->setPixmap(loadDPIAwarePixmap("status-success", ".svg"));
        inetStatus->setPixmap(loadDPIAwarePixmap("status-current", ".svg"));
        QFont addrFont = address->font();
        inet->setFont(addrFont);
        addrFont.setBold(false);
        address->setFont(addrFont);
        checkInet();
    }
}

void NetDHCPPage::checkInet() {
    QString url = QString::fromStdString("http://" +
                                         horizonWizard()->mirror_domain +
                                         "/horizon.txt");
    inetReply = qnam.get(QNetworkRequest(QUrl(url)));
    connect(inetReply, &QNetworkReply::finished, this, &NetDHCPPage::inetFinished);
}

void NetDHCPPage::inetFinished() {
    assert(inetReply);

    if(inetReply->error()) {
        inetStatus->setPixmap(loadDPIAwarePixmap("status-issue", ".svg"));
        information->setText(tr("Couldn't connect to %1: %2")
                             .arg(QString::fromStdString(horizonWizard()->mirror_domain))
                             .arg(inetReply->errorString()));
        inetReply->deleteLater();
        inetReply = nullptr;
        return;
    }

    const QVariant redirUrl = inetReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
    if(!redirUrl.isNull()) {
        inetStatus->setPixmap(loadDPIAwarePixmap("status-issue", ".svg"));
        /* XXX TODO BAD UNIMPLEMENTED !!!! LOOK AT ME DO NOT RELEASE YET !!!! */
        information->setText(tr("Received redirect to %2 while connecting to %1."
                                "God help us if we don't ship Otter Browser and have to handle captive portals with QtWebKitWidgets.")
                             .arg(QString::fromStdString(horizonWizard()->mirror_domain))
                             .arg(redirUrl.toUrl().toString()));
        inetReply->deleteLater();
        inetReply = nullptr;
        return;
    }

    QByteArray result = inetReply->readAll();
    if(result.size() != 3 || result[0] != 'O' || result[1] != 'K' ||
            result[2] != '\n') {
        QString res_str(result.left(512));
        if(result.size() > 512) res_str += "...";
        inetStatus->setPixmap(loadDPIAwarePixmap("status-issue", ".svg"));
        information->setText(tr("Received unexpected %3 byte reply from %1: %2")
                             .arg(QString::fromStdString(horizonWizard()->mirror_domain))
                             .arg(res_str).arg(result.size()));
        inetReply->deleteLater();
        inetReply = nullptr;
        return;
    }

    inetStatus->setPixmap(loadDPIAwarePixmap("status-success", ".svg"));
    QFont inetFont = inet->font();
    inetFont.setBold(false);
    inet->setFont(inetFont);

    information->setText(tr("Your computer has successfully connected to the network.  You may now proceed."));

    online = true;
    emit completeChanged();
}

void NetDHCPPage::initializePage() {
    assert(!horizonWizard()->chosen_auto_iface.empty());

    addrStatus->setPixmap(loadDPIAwarePixmap("status-current", ".svg"));
    inetStatus->clear();

    QFont addrFont = address->font();
    addrFont.setBold(true);
    address->setFont(addrFont);
    addrFont.setBold(false);
    inet->setFont(addrFont);

    startDHCP();
}

bool NetDHCPPage::isComplete() const {
    return online;
}