From 16d5d83eecb5c4e4d7102fc2adec33d9658b6841 Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Tue, 15 May 2018 08:10:24 +0200
Subject: [PATCH] add mayu resolve

---
 main.cpp |  20 ++++++
 mayu.cpp | 185 ++++++++++++++++++++++++++++++++++++++++++-------------
 mayu.h   |  36 +++++++++--
 mayu.pro |   4 +-
 4 files changed, 195 insertions(+), 50 deletions(-)

diff --git a/main.cpp b/main.cpp
index bda8c0e..26927ad 100644
--- a/main.cpp
+++ b/main.cpp
@@ -16,6 +16,9 @@
 *****************************************************************************/
 
 #include <QCoreApplication>
+#include <QStringList>
+#include <QTextStream>
+#include <QString>
 #include <QDebug>
 #include "mayu.h"
 
@@ -28,11 +31,28 @@ int main(int argc, char *argv[])
     QStringList arguments = a.arguments();
     arguments.removeAt(0);
 
+    mayuMode a_mode = mayuMode::Ping;
+    for (int i = arguments.length(); i > 0; i--) {
+        const QString &argument = arguments.at(i-1);
+        if (argument == "-p" || argument == "--ping") {
+            a_mode = mayuMode::Ping;
+            arguments.removeAt(i-1);
+        }
+        else if (argument == "-r" || argument == "--resolve") {
+            a_mode = mayuMode::Resolve;
+            arguments.removeAt(i-1);
+        }
+    }
+
     if (arguments.length() >= 2) {
         mayu a_mayu(arguments.at(0), arguments.at(1));
+        a_mayu.setMayuMode(a_mode);
         a_mayu.work();
         return a_mayu.getResult();
     }
+    else {
+        QTextStream(stdout) << "Usage: " << a.arguments().at(0) << " [-p ping]" << " [-r resolve]" << " input.txt" << " output.json" << endl;
+    }
 
     return 0;
 }
diff --git a/mayu.cpp b/mayu.cpp
index 94fe964..96de91e 100644
--- a/mayu.cpp
+++ b/mayu.cpp
@@ -26,20 +26,29 @@
 #include <iostream>
 using namespace std;
 
+#ifdef MAYU_UNIX
 extern "C" {
 #include "oping.h"
 }
+#endif
 
-mayu::mayu(const QString &hostsFile, const QString &jsonFile, int tries, QObject *parent) : QObject(parent)
+mayu::mayu(const QString &hostsFile, const QString &jsonFile, QObject *parent) : QObject(parent)
 {
     p_return = -1;
-    p_tries = tries;
+    p_timeout = 2.5;
+    p_tries = 4;
+    p_mayuMode = mayuMode::Ping;
     if (!hostsFile.isEmpty())
         setHostsFile(hostsFile);
     if (!jsonFile.isEmpty())
         setJsonFile(jsonFile);
 }
 
+void mayu::setMayuMode(mayuMode mode)
+{
+    p_mayuMode = mode;
+}
+
 void mayu::setHostsFile(const QString &fileName)
 {
     p_hostsFile = fileName;
@@ -57,11 +66,21 @@ void mayu::setJsonFile(const QString &fileName)
     p_jsonFile = fileName;
 }
 
-void mayu::setMaxTries(int tries)
+void mayu::setPingTimeout(double timeout)
+{
+    p_timeout = timeout;
+}
+
+void mayu::setPingTries(int tries)
 {
     p_tries = tries;
 }
 
+mayuMode mayu::getMayuMode()
+{
+    return p_mayuMode;
+}
+
 const QString mayu::getHostsFile()
 {
     return p_hostsFile;
@@ -77,7 +96,12 @@ const QString mayu::getJsonFile()
     return p_jsonFile;
 }
 
-int mayu::getMaxTries()
+double mayu::getPingTimeout()
+{
+    return p_timeout;
+}
+
+int mayu::getPingTries()
 {
     return p_tries;
 }
@@ -87,21 +111,18 @@ int mayu::getResult()
     return p_return;
 }
 
+#ifdef MAYU_UNIX
 double mayu::ping(const QString &host, int tries, double timeout)
 {
     double latency;
     pingobj_t *pingObj;
     pingobj_iter_t *pingIter;
     if ((pingObj = ping_construct()) == NULL) {
-#ifdef E_DEBUG
-        qDebug() << "Ping construction failed";
-#endif
+        QTextStream(stderr) << "Ping construction failed " << endl;
         return -1;
     }
     if (ping_setopt(pingObj, PING_OPT_TIMEOUT, (void*)(&timeout)) < 0) {
-#ifdef E_DEBUG
-        qDebug() << "Setting timeout to" << timeout << "have failed";
-#endif
+        QTextStream(stderr) << "Setting timeout to"  << timeout << " have failed" << endl;
         ping_destroy(pingObj);
         return -1;
     }
@@ -148,9 +169,7 @@ double mayu::ping(const QString &host, int tries, double timeout)
     int curTry = 0;
     while (!hostUp && curTry != tries) {
         if (ping_send(pingObj) < 0) {
-#ifdef E_DEBUG
-            qDebug() << "Pinging host" << host << " has failed";
-#endif
+            QTextStream(stderr) << "Pinging host " << host << " has failed" << endl;
             ping_destroy(pingObj);
             return -1;
         }
@@ -165,7 +184,7 @@ double mayu::ping(const QString &host, int tries, double timeout)
             char hostname[100];
             len = 100;
             ping_iterator_get_info(pingIter, PING_INFO_HOSTNAME, hostname, &len);
-            qDebug() << hostname << latency << pingSuccess;
+            QTextStream(stdout) << "Host: " << hostname << " Ping: " << latency << "ms" << " Status: " << (pingSuccess ? "true" : "false") << endl;
 #endif
         }
         if (pingSuccess) {
@@ -178,14 +197,44 @@ double mayu::ping(const QString &host, int tries, double timeout)
         return latency;
     return -1;
 }
+#endif
+
+const QList<mayuResult> mayu::resolve(const QString &host)
+{
+    QList<mayuResult> resultList;
+    QList<QHostAddress> hostAddresses = QHostInfo::fromName(host).addresses();
+    if (hostAddresses.length() >= 1) {
+        for (const QHostAddress &hostAddress : hostAddresses) {
+#ifdef E_DEBUG
+            qDebug() << "Hostname" << host << "found and resolved" << hostAddress.toString();
+#endif
+            mayuResult m_result;
+            m_result.host = host;
+            m_result.result = hostAddress.toString();
+            resultList += m_result;
+        }
+    }
+    else {
+#ifdef E_DEBUG
+        qDebug() << "Hostname" << host << "not found";
+#endif
+        mayuResult m_result;
+        m_result.host = host;
+        m_result.result = "-1";
+        resultList += m_result;
+    }
+    return resultList;
+}
 
 void mayu::parse_hosts()
 {
     p_hostsList.clear();
-    if (!dropPrivileges()) {
+#ifdef PRIVILEGE_DROP_REQUIRED
+    if (!p_dropPrivileges()) {
         p_return = 2;
         return;
     }
+#endif
     QFile hostsFile(p_hostsFile);
     if (hostsFile.open(QFile::ReadOnly)) {
         const QList<QByteArray> hostsArray = hostsFile.readAll().split('\n');
@@ -210,57 +259,104 @@ void mayu::parse_hosts()
     }
     else
     {
-        qCritical() << "Failed read hosts from" << p_hostsFile;
+        QTextStream(stderr) << "Failed read hosts from " << p_hostsFile << endl;
     }
-    if (!regainPrivileges()) {
+#ifdef PRIVILEGE_DROP_REQUIRED
+    if (!p_regainPrivileges()) {
         p_return = 3;
         return;
     }
+#endif
+}
+
+void mayu::p_saveWork(QJsonObject jsonObject)
+{
+    QJsonDocument jsonDocument;
+    jsonDocument.setObject(jsonObject);
+    QByteArray jsonArray = jsonDocument.toJson();
+#ifdef PRIVILEGE_DROP_REQUIRED
+    if (!p_dropPrivileges()) {
+        p_return = 2;
+        return;
+    }
+#endif
+    QSaveFile jsonFile(p_jsonFile);
+    if (jsonFile.open(QSaveFile::WriteOnly)) {
+        jsonFile.write(jsonArray);
+        if (!jsonFile.commit()) {
+            QTextStream(stderr) << "Failed save result to " << p_jsonFile << " because file can't be saved!" << endl;
+            p_return = 1;
+        }
+    }
+    else {
+        QTextStream(stderr) << "Failed save result to " << p_jsonFile << " because file can't be opened!" << endl;
+        p_return = 1;
+    }
+#ifdef PRIVILEGE_DROP_REQUIRED
+    if (!p_regainPrivileges()) {
+        p_return = 3;
+        return;
+    }
+#endif
+    p_return = 0;
 }
 
 void mayu::work()
+{
+    switch(p_mayuMode) {
+    case mayuMode::Ping:
+#ifdef MAYU_UNIX
+        p_workPing();
+#else
+        QTextStream(stderr) << "Mayu doesn't support pinging on your Operating System!" << endl;
+#endif
+        break;
+    case mayuMode::Resolve:
+        p_workResolve();
+        break;
+    }
+}
+
+#ifdef MAYU_UNIX
+void mayu::p_workPing()
 {
     if (!p_hostsParsed)
         parse_hosts();
     QJsonObject jsonObject;
     const QStringList hostsList = getHosts();
     for (const QString &host : hostsList) {
-        double result = ping(host, p_tries);
+        double result = ping(host, p_tries, p_timeout);
         jsonObject[host] = result;
     }
-    QJsonDocument jsonDocument;
-    jsonDocument.setObject(jsonObject);
-    QByteArray jsonArray = jsonDocument.toJson();
-    if (!dropPrivileges()) {
-        p_return = 2;
-        return;
-    }
-    QSaveFile jsonFile(p_jsonFile);
-    if (jsonFile.open(QSaveFile::WriteOnly)) {
-        jsonFile.write(jsonArray);
-        if (!jsonFile.commit()) {
-            qCritical() << "Failed save result to" << p_jsonFile << "because file can't be saved!";
-            p_return = 1;
+    p_saveWork(jsonObject);
+}
+#endif
+
+void mayu::p_workResolve()
+{
+    if (!p_hostsParsed)
+        parse_hosts();
+    QJsonObject jsonObject;
+    const QStringList hostsList = getHosts();
+    for (const QString &host : hostsList) {
+        const QList<mayuResult> resultList = resolve(host);
+        QJsonArray arrayList;
+        for (const mayuResult &result : resultList) {
+            arrayList += result.result;
         }
+        jsonObject[host] = arrayList;
     }
-    else {
-        qCritical() << "Failed save result to" << p_jsonFile << "because file can't be opened!";
-        p_return = 1;
-    }
-    if (!regainPrivileges()) {
-        p_return = 3;
-        return;
-    }
-    p_return = 0;
+    p_saveWork(jsonObject);
 }
 
-bool mayu::dropPrivileges()
+#ifdef PRIVILEGE_DROP_REQUIRED
+bool mayu::p_dropPrivileges()
 {
 #if _POSIX_SAVED_IDS
     p_uid = geteuid();
     int status = seteuid(getuid());
     if (status != 0) {
-        qCritical() << "Dropping of privileges has failed!";
+        QTextStream(stderr) << "Dropping of privileges has failed!" << endl;
         return false;
     }
     return true;
@@ -269,12 +365,12 @@ bool mayu::dropPrivileges()
 #endif
 }
 
-bool mayu::regainPrivileges()
+bool mayu::p_regainPrivileges()
 {
 #if _POSIX_SAVED_IDS
     int status = seteuid(p_uid);
     if (status != 0) {
-        qCritical() << "Regaining of privileges has failed!";
+        QTextStream(stderr) << "Regaining of privileges has failed!" << endl;
         return false;
     }
     return true;
@@ -282,3 +378,4 @@ bool mayu::regainPrivileges()
     return false;
 #endif
 }
+#endif
diff --git a/mayu.h b/mayu.h
index 79a23fe..9ac3c27 100644
--- a/mayu.h
+++ b/mayu.h
@@ -21,38 +21,64 @@
 #include <QJsonDocument>
 #include <QJsonObject>
 #include <QStringList>
+#include <QJsonArray>
 #include <QObject>
+#include <QList>
+
+enum class mayuMode : int{Ping = 0, Resolve = 1};
+struct mayuResult {
+    QString host;
+    QString result;
+};
 
 class mayu : public QObject
 {
     Q_OBJECT
 public:
-    explicit mayu(const QString &hostsFile = QString(), const QString &jsonFile = QString(), int tries = 4, QObject *parent = nullptr);
+    explicit mayu(const QString &hostsFile = QString(), const QString &jsonFile = QString(), QObject *parent = nullptr);
+    void setMayuMode(mayuMode mode);
     void setHostsFile(const QString &fileName);
     void setHosts(const QStringList &hostsList);
     void setJsonFile(const QString &fileName);
-    void setMaxTries(int tries);
+    void setPingTimeout(double timeout);
+    void setPingTries(int tries);
+    mayuMode getMayuMode();
     const QString getHostsFile();
     const QStringList getHosts();
     const QString getJsonFile();
-    int getMaxTries();
+    double getPingTimeout();
+    int getPingTries();
     int getResult();
+#ifdef MAYU_UNIX
     static double ping(const QString &host, int tries, double timeout = 2.5);
+#endif
+    static const QList<mayuResult> resolve(const QString &host);
 
 public slots:
     void parse_hosts();
     void work();
 
 private:
-    bool dropPrivileges();
-    bool regainPrivileges();
+#ifdef PRIVILEGE_DROP_REQUIRED
+    bool p_dropPrivileges();
+    bool p_regainPrivileges();
+#endif
+    void p_saveWork(QJsonObject jsonObject);
+#ifdef MAYU_UNIX
+    void p_workPing();
+#endif
+    void p_workResolve();
     QStringList p_hostsList;
     QString p_hostsFile;
     QString p_jsonFile;
+    mayuMode p_mayuMode;
     bool p_hostsParsed;
+    double p_timeout;
     int p_return;
     int p_tries;
+#ifdef PRIVILEGE_DROP_REQUIRED
     uid_t p_uid;
+#endif
 };
 
 #endif // MAYU_H
diff --git a/mayu.pro b/mayu.pro
index 1a2a1c4..accb72a 100644
--- a/mayu.pro
+++ b/mayu.pro
@@ -18,7 +18,9 @@
 QT -= gui
 QT += network
 
-LIBS += -loping
+unix: DEFINES += PRIVILEGE_DROP_REQUIRED
+unix: DEFINES += MAYU_UNIX
+unix: LIBS += -loping
 
 CONFIG += c++11 console
 CONFIG -= app_bundle