/****************************************************************************
** qnmap - una interfaz gráfica para nmap
**---------------------------------------------------------------------------
** qnmap - main.cpp, qnmap.cpp, qnmap.h, qnmap.qrc, qnmap.ui
**===========================================================================
** FJA - fja@neocipres.com                Febrero de 2019   (5/03/2019)
**===========================================================================
** This file may be used under the terms of the GNU General Public
** License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

#include "qnmap.h"
#include "ui_qnmap.h"
#include <QMessageBox>
#include <QCloseEvent>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QDir>
#include <QDirIterator>
#include <QSettings>

qnmap::qnmap(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::qnmap)
{
    ui->setupUi(this);

    proc = new QProcess(ui->centralWidget);
    comando = "";
    opcion = "";

    connect(ui->actionAcerca_de_Qt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
    connect(proc, SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdout()));
    connect(proc, SIGNAL(readyReadStandardError()), this, SLOT(readFromStderr()));
    connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
    connect(proc, SIGNAL(errorOccurred(QProcess::ProcessError )), this, SLOT(tipoError(QProcess::ProcessError )));

    readSettings();
}

qnmap::~qnmap()
{
    delete ui;
}

void qnmap::closeEvent(QCloseEvent *event)
{
    if (proc->exitStatus() == 0){
        writeSettings();
        event->accept();
    }
    else {
        ui->statusBar->showMessage(QString("Proceso no terminado, código de salida: %1.").arg(QString::number(proc->exitStatus())), 5000);
        proc->terminate();
        //event->ignore();
        qnmap::destroy();
    }

}

void qnmap::actualizar()
{
    comando = "nmap -v " + opcion + " " + ui->lEObjetivo->text();
    ui->lEComando->setText(comando);
}

void qnmap::on_lEObjetivo_editingFinished()
{
    actualizar();
}

void qnmap::ejecutar(QString cmd)
{
    if (proc->state() == QProcess::NotRunning) {
        ui->tEOut->clear();
        proc->start(cmd, QIODevice::ReadOnly);
    }
    else ui->statusBar->showMessage("Proceso corriendo actualmente ...", 5000);
}

void qnmap::on_cBPerfil_currentIndexChanged(int index)
{
    switch (index) {
    case 0:
        opcion = "-T4 -A";
        break;
    case 1:
        opcion = "-p 1-65535 -T4 -A";
        break;
    case 2:
        opcion = "-sS -sU -T4 -A";
        break;
    case 3:
        opcion = "-T4 -A -Pn";
        break;
    case 4:
        opcion = "-T4 -F";
        break;
    case 5:
        opcion = "-sV -T4 -O -F --version-light";
        break;
    case 6:
        opcion = "-sn --traceroute";
        break;
    case 7:
        opcion = "-sS -sU -T4 -A -v -PE -PP -PS80,443 -PA3389 -PU40125 -PY -g 53";
        break;
    case 8:
        opcion = "-sn";
    }
    actualizar();
}

void qnmap::on_pBAceptar_clicked()
{
    ejecutar(comando);
}

void qnmap::readFromStdout()
{
    QByteArray datos = proc->readAllStandardOutput();
    QString linea = QString::null;
    linea.append(QString::fromUtf8(datos));
    ui->tEOut->append(linea);
    //ui->tEOut->moveCursor(QTextCursor::Start);
}

void qnmap::readFromStderr()
{
    QByteArray datos = proc->readAllStandardError();
    QString linea = QString::null;
    linea.append(QString::fromUtf8(datos));
    ui->tEOut->append("<b>"+linea+"</b>");
}

void qnmap::processFinished(int cod, QProcess::ExitStatus)
{
    if (cod != 0){
        QMessageBox::warning( ui->centralWidget,
                                  tr("Proceso roto"),
                                  tr("Código de salida: ") + QString::number(cod),
                                  tr("Aceptar") );

    }
    else ui->statusBar->showMessage(QString("El escaneo al host %1 ha finalizado.").arg(ui->lEObjetivo->text()), 5000);

}

void qnmap::tipoError(QProcess::ProcessError error)
{
    QString cadE;

    switch (error) {
    case QProcess::FailedToStart:
        cadE = QString::fromUtf8("El proceso %1 ha fallado al iniciarse.\nPuede que no exista, o no se tengan los permisos suficientes").arg(comando);
        break;
    case  QProcess::Crashed:
        cadE = QString::fromUtf8("Después de un inicio correcto,\nel proceso %1 se ha roto.").arg(comando);
        break;
    case  QProcess::Timedout:
        cadE = "The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again.";
        break;
    case QProcess::WriteError:
        cadE = "An error occurred when attempting to write to the process.\nFor example, the process may not be running, or it may have closed its input channel.";
        break;
    case QProcess::ReadError:
        cadE = "An error occurred when attempting to read from the process.\nFor example, the process may not be running.";
        break;
    case QProcess::UnknownError:
        cadE = QString::fromUtf8("Un error desconocido en el proceso %1.").arg(comando);
        break;
    }
    QMessageBox::warning( ui->centralWidget,
                          tr("Nmap"),
                          tr("Error: ")+QString::number(error)+". "+cadE,
                          tr("Aceptar") );

}

void qnmap::on_pBKill_clicked()
{
    proc->kill();
}

void qnmap::on_actionMan_triggered()
{
    ejecutar("man nmap");
}

void qnmap::on_actionAcerca_de_qnmap_triggered()
{
    QString separador = QString::null;
    separador.fill( '-', 78 );
    separador = "<p><b>"+separador+"</b></p>";
    //QString nomAp = "<p><b><BIG><BIG> </BIG></BIG></b></p><br>";
    QString desAp1 = "<p><b>Interfaz gráfica para <a href = https://nmap.org>Nmap</a></b></p>";
    QString desAp2 = "<p> <b>Nmap</b> es un programa de código abierto para la exploración de redes.</p>";
    QString autor = "<p><b>FJA</b> - fja@neocipres.com</p>";
    QString o = QString::fromUtf8("ó");
    QString version = "<p>Versi"+o+"n: 0.9.0</p>";
    QString modificado = "<p>Febrero de 2019  -  Modificado el 5 de Mar/2019</p>";
    QString e = QString::fromUtf8("é");
    QString licencia = "<p>Distribuido de acuerdo a los t"+e+"rminos de la <a href= https://www.gnu.org/licenses/licenses.es.html>licencia GNU/GPL</a></p>";
    QString gnu = "<p><a href= http://www.gnu.org/home.es.html>Proyecto GNU</a></p>";
    //QString otro = QString::QString(self.tr("<p><em> </em> </p>"))

    QMessageBox::about(ui->centralWidget, " Acerca de ...", /*nomAp +*/ desAp1 + desAp2 + separador + autor + modificado + separador + version + licencia + gnu);
}

void qnmap::on_actionAlgunas_opciones_triggered()
{
    QString dirH = QDir::homePath();
    QString nomF = "";
    QDirIterator dirIt(dirH, QDirIterator::Subdirectories);
    while (dirIt.hasNext()) {
        dirIt.next();
        if (QFileInfo(dirIt.filePath()).isFile())
            if (QFileInfo(dirIt.filePath()).fileName() == "opnmap.txt")
                nomF = dirIt.filePath();
    }
    if (nomF.isEmpty()) nomF = "opnmap.txt";
    QFile fichero(nomF);
    if (!fichero.open( QFile::ReadOnly | QFile::Text )){
        QString aviso = tr("No se puede abrir el archivo:\n\n %1\n\n%2").arg(nomF).arg(fichero.errorString());
        QMessageBox::critical(ui->centralWidget,
                              "Error al abrir",
                              aviso,
                              "Aceptar");
        return;
        }
    QTextStream ts(&fichero);
    ui->tEOut->clear();
    ui->tEOut->setText(ts.readAll());
    fichero.close();
    ui->statusBar->showMessage(QString("Archivo de opciones: %1.").arg(nomF), 5000);
}

void qnmap::readSettings()
{
    QSettings settings("ElCipresSL0", "qnmap");
    QPoint pos = settings.value("pos", QPoint(294, 20)).toPoint();
    QSize size = settings.value("size", QSize(800, 600)).toSize();
    QByteArray state = settings.value("state", QByteArray()).toByteArray();
    QString obj = settings.value("obj", "").toString();
    QString cmd = settings.value("cmd", "").toString();
    restoreState(state);
    resize(size);
    move(pos);
    ui->lEObjetivo->setText(obj);
    ui->lEComando->setText(cmd);
    comando = cmd;
}

void qnmap::writeSettings()
{
    /* Save postion/size of main window */

    QSettings settings("ElCipresSL0", "qnmap");
    settings.setValue("pos", pos());
    settings.setValue("size", size());
    settings.setValue("state", saveState());
    settings.setValue("obj", ui->lEObjetivo->text());
    settings.setValue("cmd", comando);
}