diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ba8683..27a3ac6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,8 @@ SET(LIB_METHOD STATIC) #SHARED / STATIC option(BUILD_DOC "Build documentation" ON) # additional dependency for Doxygen option(PACKAGING "Allow Packaging to , or " ON) # additional dependencies for RPMbuild,dpkg or NSIS option(TESTS "Build Tests" ON) # additional dependencies for GTEST - to build tests -option(WinBuild "cross compile for Windows Platform" OFF) +option(GUI "Build GUI elements" ON) # additional dependencies to QT libraries needed +option(WinBuild "cross compile for Windows Platform" ON) # helper variables SET(CMAKE_CXX_STANDARD 17) @@ -112,6 +113,10 @@ if (${WinBuild}) message(STATUS "Using LIBCONFIG++ include dir(s): ${LIBCONFIG++_INCLUDE_DIRS}") message(STATUS "Using LIBCONFIG++ lib(s): ${LIBCONFIG++_LIBRARIES}") + if (${GUI}) + set(CMAKE_PREFIX_PATH "/usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/lib/cmake") + endif () + include_directories(${LIBCONFIG++_INCLUDE_DIRS}) else () find_package(CURL REQUIRED) @@ -144,6 +149,16 @@ else () include_directories(${LIBCONFIG_INCLUDE_DIRS}) endif () + +if (${GUI}) + set(CMAKE_AUTOMOC ON) + set(CMAKE_INCLUDE_CURRENT_DIR ON) + + find_package(Qt5Widgets REQUIRED) + find_package(Qt5PrintSupport REQUIRED) + find_package(Qt5Sql REQUIRED) +endif () + include_directories(inc) message("") @@ -192,34 +207,112 @@ add_executable(${Application_Name} src/main.cpp) # LINK generated LIBS # target_link_libraries(${Application_Name} libdynuiprefresher api ${CURL_LIBRARIES} ${LIBCONFIG++_LIBRARIES}) +if (${GUI}) + set(QT5_LIBRARIES Qt5::Widgets Qt5::PrintSupport Qt5::Sql) + + set(UI_SOURCES + src/gui/mainwindow.ui + ) + + # + # Generate necessary headers from .ui files. (qmake lets `uic` do this job.) + # hint from [Cross-platform Qt5 project using cmake](http://stackoverflow.com/questions/21174586/cross-platform-qt5-project-using-cmake) + # + qt5_wrap_ui(UI_GENERATED_HEADERS ${UI_SOURCES}) + + add_executable(${Application_Name}-gui + src/maingui.cpp + src/gui/MainWindow.cpp + inc/gui/MainWindow.h + ${UI_GENERATED_HEADERS}) + + if (${WinBuild}) + # hide console window when starting ui on windows + set_target_properties(${Application_Name}-gui PROPERTIES LINK_FLAGS "-mwindows") + endif () + + # LINK generated LIBS # + target_link_libraries(${Application_Name}-gui -lpthread libdynuiprefresher api ${CURL_LIBRARIES} ${LIBCONFIG++_LIBRARIES} ${QT5_LIBRARIES}) +endif () + # setting install targets IF (NOT ${WinBuild}) # INSTALL to Linux SYSTEM # # install binaries - install(TARGETS ${Application_Name} DESTINATION usr/bin) + install( + TARGETS ${Application_Name} + DESTINATION usr/bin + COMPONENT ${Application_Name}) # install systemd service and enable it - install(FILES service/${Application_Name}.service DESTINATION lib/systemd/system) + install( + FILES service/${Application_Name}.service + DESTINATION lib/systemd/system + COMPONENT ${Application_Name}) + + if (${GUI}) + # install binaries + install( + TARGETS ${Application_Name}-gui + DESTINATION usr/bin + COMPONENT ${Application_Name}gui) + endif () ELSE () # INSTALL to Windows SYSTEM # # install binary to current folder set_target_properties(${Application_Name} PROPERTIES SUFFIX ".exe") - install(TARGETS ${Application_Name} DESTINATION .) + install( + TARGETS ${Application_Name} + DESTINATION . + COMPONENT ${Application_Name}) # install .dll dependencies # todo check if files exist... + SET(LIBBINARYPATH "/usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin") install(FILES /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libcurl-4.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libssh2-1.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libstdc++-6.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libgcc_s_seh-1.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libcrypto-1_1-x64.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libssl-1_1-x64.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libwinpthread-1.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/zlib1.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libidn2-0.dll - /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/bin/libconfig++-11.dll - DESTINATION .) + ${LIBBINARYPATH}/libssh2-1.dll + ${LIBBINARYPATH}/libstdc++-6.dll + ${LIBBINARYPATH}/libgcc_s_seh-1.dll + ${LIBBINARYPATH}/libcrypto-1_1-x64.dll + ${LIBBINARYPATH}/libssl-1_1-x64.dll + ${LIBBINARYPATH}/libwinpthread-1.dll + ${LIBBINARYPATH}/zlib1.dll + ${LIBBINARYPATH}/libidn2-0.dll + ${LIBBINARYPATH}/libconfig++-11.dll + DESTINATION . + COMPONENT ${Application_Name}) + + if (${GUI}) + # install binaries + set_target_properties(${Application_Name}-gui PROPERTIES SUFFIX ".exe") + install( + TARGETS ${Application_Name}-gui + DESTINATION . + COMPONENT ${Application_Name}gui) + + # install .dll dependencies + install(FILES + ${LIBBINARYPATH}/Qt5Widgets.dll + ${LIBBINARYPATH}/Qt5Core.dll + ${LIBBINARYPATH}/Qt5Gui.dll + ${LIBBINARYPATH}/iconv.dll + ${LIBBINARYPATH}/libpcre2-16-0.dll + ${LIBBINARYPATH}/libpng16-16.dll + ${LIBBINARYPATH}/libharfbuzz-0.dll + ${LIBBINARYPATH}/libglib-2.0-0.dll + ${LIBBINARYPATH}/libintl-8.dll + ${LIBBINARYPATH}/libpcre-1.dll + ${LIBBINARYPATH}/libbz2-1.dll + ${LIBBINARYPATH}/libfreetype-6.dll + DESTINATION . + COMPONENT ${Application_Name}gui) + + install(FILES + /usr/${TOOLCHAIN_PREFIX}/sys-root/mingw/lib/qt5/plugins/platforms/qwindows.dll + DESTINATION ./platforms + COMPONENT ${Application_Name}gui) + endif () ENDIF () if (${PACKAGING}) @@ -265,8 +358,19 @@ systemctl start ${Application_Name}.service") message(STATUS "found rpm build executeable --> able to build rpm") SET(CPACK_GENERATOR "${CPACK_GENERATOR};RPM") SET(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/postinst") - SET(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/lib/systemd/system" "/lib/systemd" "/lib" "/usr/local/bin" "/usr/local") # --> needed to not override existing folders + SET(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION + "/lib/systemd/system" + "/lib/systemd" + "/lib" + "/usr/local/bin" + "/usr/local") # --> not override existing folders + + # dependency management tested with fedora! set(CPACK_RPM_PACKAGE_REQUIRES "libcurl,libconfig") + if (${GUI}) + # append rpm GUI dependencies (qt5) + set(CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},qt5-qtbase") + endif () else (NOT ${RPMBUILD_EXECUTABLE} STREQUAL "RPMBUILD_EXECUTABLE-NOTFOUND") message(STATUS "not found rpm build tools --> not building rpm") endif (NOT ${RPMBUILD_EXECUTABLE} STREQUAL "RPMBUILD_EXECUTABLE-NOTFOUND") @@ -276,7 +380,13 @@ systemctl start ${Application_Name}.service") message(STATUS "found deb build tools --> able to build deb") SET(CPACK_GENERATOR "${CPACK_GENERATOR};DEB") # add deb generator set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst") # set post inst file + + # dependency management tested with fedora! set(CPACK_DEBIAN_PACKAGE_DEPENDS "libcurl4,libconfig++9v5") # add debian dependencies + if (${GUI}) + # append debian GUI dependencies (qt5) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},qt5-default") + endif () else (NOT ${DEB_EXECUTABLE} STREQUAL "DEB_EXECUTABLE-NOTFOUND") message(STATUS "not found deb build tools --> not building deb") endif (NOT ${DEB_EXECUTABLE} STREQUAL "DEB_EXECUTABLE-NOTFOUND") @@ -291,9 +401,37 @@ systemctl start ${Application_Name}.service") set(CPACK_GENERATOR NSIS) message(STATUS "Using NSIS Package build.") - set(CPACK_NSIS_testcomp_INSTALL_DIRECTORY /) + set(CPACK_NSIS_EXECUTABLES_DIRECTORY "DynuIpRefresher") set(CPACK_PACKAGE_INSTALL_DIRECTORY "DynuIpRefresher") SET(CPACK_NSIS_MODIFY_PATH ON) + set(CPACK_NSIS_MENU_LINKS + "${Application_Name}.exe" "DynuIpRefresher Console" + "${Application_Name}-gui.exe" "DynuIpRefresher GUI") + + # varnames need uppercase strings + string(TOUPPER ${Application_Name} APPLICATION_NAME_UPPER) + # Define components and their display names + set (CPACK_COMPONENTS_ALL ${Application_Name} ${Application_Name}gui) + set (CPACK_COMPONENT_${APPLICATION_NAME_UPPER}_DISPLAY_NAME "Dynu IP Refresher Console") + set (CPACK_COMPONENT_${APPLICATION_NAME_UPPER}GUI_DISPLAY_NAME "Dynu IP Refresher GUI") + + # Human readable component descriptions + set(CPACK_COMPONENT_${APPLICATION_NAME_UPPER}_DESCRIPTION "An extremely useful application that makes use of MyLib") + set(CPACK_COMPONENT_${APPLICATION_NAME_UPPER}GUI_DESCRIPTION "Static libraries used to build programs with MyLib") + + # Define dependencies between components + set(CPACK_COMPONENT_${APPLICATION_NAME_UPPER}GUI_DEPENDS ${Application_Name}) + + # Define groups + set(CPACK_COMPONENT_${APPLICATION_NAME_UPPER}_GROUP "Runtime") + set(CPACK_COMPONENT_${APPLICATION_NAME_UPPER}GUI_GROUP "Development") + + set(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION "All of the tools you'll ever need to develop software") + + # Define NSIS installation types + set(CPACK_ALL_INSTALL_TYPES Full Developer) + set(CPACK_COMPONENT_${APPLICATION_NAME_UPPER}_INSTALL_TYPES Developer Full) + set(CPACK_COMPONENT_${APPLICATION_NAME_UPPER}GUI_INSTALL_TYPES Full) ENDIF () INCLUDE(CPack) diff --git a/Docker/Linux/Dockerfile b/Docker/Linux/Dockerfile new file mode 100644 index 0000000..00b37ec --- /dev/null +++ b/Docker/Linux/Dockerfile @@ -0,0 +1,19 @@ +FROM gcc:latest +MAINTAINER luki42 + +RUN \ + \ + # Install texlive + echo "instaling cmake" && \ + apt-get update && \ + apt-get install -y --no-install-recommends cmake libgtest-dev && \ + echo "installing build dependencies" && \ + apt-get install -y --no-install-recommends libcurl4-openssl-dev libconfig++-dev && \ + echo "installing packaging tools" && \ + apt-get install -y --no-install-recommends dpkg rpm && \ + # clean up + apt-get clean + +# Expose /home as workin dir +WORKDIR /home +VOLUME ["/home"] \ No newline at end of file diff --git a/Docker/Windows/Dockerfile b/Docker/Windows/Dockerfile new file mode 100644 index 0000000..c52d108 --- /dev/null +++ b/Docker/Windows/Dockerfile @@ -0,0 +1,20 @@ +FROM fedora:33 +MAINTAINER luki42 + +RUN \ + \ + # Install texlive + echo "instaling cmake" && \ + dnf install -y mingw64-gcc-c++ mingw64-curl-static mingw64-qt5-qtbase wget cmake make tar xz mingw32-nsis gtest gtest-devel && \ + wget http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-libconfig-1.7.2-1-any.pkg.tar.xz && \ + tar -xf mingw-w64-x86_64-libconfig-1.7.2-1-any.pkg.tar.xz && \ + mv ./mingw64/bin/* /usr/x86_64-w64-mingw32/sys-root/mingw/bin && \ + mv ./mingw64/include/* /usr/x86_64-w64-mingw32/sys-root/mingw/include && \ + mv ./mingw64/lib/*.a /usr/x86_64-w64-mingw32/sys-root/mingw/lib && \ + mv ./mingw64/lib/cmake/* /usr/x86_64-w64-mingw32/sys-root/mingw/lib/cmake && \ + rm -Rv mingw-w64-x86_64-libconfig-1.7.2-1-any.pkg.tar.xz mingw64 && \ + #cleanup + dnf clean dbcache && dnf clean packages +# Expose /home as workin dir +WORKDIR /home +VOLUME ["/home"] \ No newline at end of file diff --git a/README.md b/README.md index bf7f869..5642a69 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ # DynuIPRefresher A lightweight C++ application to setup a service for refreshing a dynamic IP to the Dynu servers. Dynu.com is a free DDns service and provides an API. +There is also a GUI for Windows Users and beginners. ## Installation Download the latest Release at [Release_Page](https://github.com/Lukas-Heiligenbrunner/DynuIPRefresher/releases). @@ -31,6 +32,17 @@ help page: [no argument] normal ip check and refresh ``` +### GUI + +You can also build the grapical user inteface if you want. +There you can manually trigger a refresh in a gui and set all the config parameters. + +Home Page: +![couldn't load image](https://i.ibb.co/syDwWQg/Screenshot-20200608-104253.png) + +Config Page: +![couldn't load image](https://i.ibb.co/89vnJXY/Screenshot-20200608-104308.png) + ## Build ## Basic Build @@ -85,6 +97,10 @@ cd into downloaded files and Generate makefiles: `make package` +### GUI Build + +please use the predefined Docker-Image here: +[DockerHub](https://hub.docker.com/repository/docker/luki42/dynuiprefresher_build) ### Windows cross build @@ -99,5 +115,7 @@ Optional dependencies * NSIS Pack tool (for creating installer) * doxygen (for generating html doc) -Some addition configuration of lib paths may be needed in CMakeList.txt. +The Simplest way to install all dependencies is the preconfigured Docker-Image: +[DockerHub](https://hub.docker.com/repository/docker/luki42/dynuiprefresher_build) + `make package` will pack it into a NSIS installer for Windows. diff --git a/inc/Config.h b/inc/Config.h index 1529671..db806e7 100644 --- a/inc/Config.h +++ b/inc/Config.h @@ -18,6 +18,13 @@ public: */ static bool readConfig(); + /** + * save back configuration to file + * + * @return success of config write + */ + static bool saveConfig(); + /** * validate config file * @@ -63,12 +70,32 @@ public: */ static const std::string &getChatId(); + /** + * set all parameters without telegram support + * + * @param domainname Dynu Domain name + * @param dynuapikey Dynu api key + * @param domainid Dynu domain id + */ + static void setValues(const std::string &domainname, const std::string &dynuapikey, const std::string &domainid); + + /** + * set all parameters with telegram support + * + * @param domainname Dynu Domain name + * @param dynuapikey Dynu api key + * @param domainid Dynu domain id + * @param telegramApiKey Telegram api key + * @param chatId Telegram chat id + */ + static void setValues(const std::string &domainname, const std::string &dynuapikey, const std::string &domainid, + const std::string &telegramApiKey, const std::string &chatId); private: /** * private constructor --> don't allow instance of this class */ - Config(); + Config() = default; /** * helper variable for managing telegram Support diff --git a/inc/IPRefresher.h b/inc/IPRefresher.h index 6bc713d..91819b1 100644 --- a/inc/IPRefresher.h +++ b/inc/IPRefresher.h @@ -9,22 +9,25 @@ #pragma once -class IPRefresher { -public: +namespace IPRefresher { + /** + * Status return-codes for startUpService + */ + namespace Status_Code { + const int SUCCESS = 1; + const int ERROR = -1; + const int ERROR_NO_INTERNET = -2; + const int NOREFRESH = 0; + } + /** * refresh ip address on Dynu server */ - void checkIPAdress(bool force); - - /** - * default constructor - */ - IPRefresher() = default; + bool checkIPAdress(bool force); /** * start the service in loop mode * every 5 minutes the ip is checked an refreshed (needed for .service) - * @param loop true->loopmode on */ - explicit IPRefresher(bool loop); -}; + void startUpService(int interval = 300); +} \ No newline at end of file diff --git a/inc/gui/MainWindow.h b/inc/gui/MainWindow.h new file mode 100644 index 0000000..88879e7 --- /dev/null +++ b/inc/gui/MainWindow.h @@ -0,0 +1,63 @@ +/** + * Main GUI controller - User IO handlings + * + * @author Lukas Heiligenbrunner + * @date 09.05.2020 + */ + +#pragma once + +#include + +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow { +Q_OBJECT + +public: + /** + * constructor with basic initializations + */ + explicit MainWindow(); + + /** + * destruct all gui elements + */ + ~MainWindow(); + +private: + Ui::MainWindow *ui; + + /** + * all static initializations of custom gui elements + */ + void initGui(); + +private slots: + + /** + * executed click handler for config button + */ + void checkConfigBtn(); + + /** + * executed click handler for refresh btn + */ + void refreshIPBtn(); + + /** + * executed click handler for save config btn + */ + void saveConfigBtn(); + +signals: + + /** + * append a String line to the Log field + * + * @param QString string to be appended + */ + void appendLogField(QString); +}; \ No newline at end of file diff --git a/src/Config.cpp b/src/Config.cpp index 26ad6ba..80cb95f 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -91,11 +91,16 @@ bool Config::readConfig() { return !(Config::dynuapikey.empty() || Config::domainid.empty() || Config::domainname.empty()); } +bool Config::saveConfig() { + // todo save config + return false; +} + bool Config::validateConfig() { libconfig::Config cfg; try { Logger::message("reading config file"); - cfg.readFile(StaticData::ConfigDir.c_str()); + cfg.readFile(std::string(StaticData::ConfigDir + StaticData::ConfName).c_str()); } catch (const libconfig::FileIOException &fioex) { Logger::warning("config file doesn't exist or permission denied!"); @@ -164,4 +169,14 @@ const std::string &Config::getChatId() { return chatId; } -Config::Config() = default; +void Config::setValues(const std::string &domainname, const std::string &dynuapikey, const std::string &domainid) { + Config::domainname = domainname; + Config::dynuapikey = dynuapikey; + Config::domainid = domainid; +} + +void Config::setValues(const std::string &domainname, const std::string &dynuapikey, const std::string &domainid, const std::string &telegramApiKey, const std::string &chatId) { + setValues(domainname, dynuapikey, domainid); + Config::telegramApiKey = telegramApiKey; + Config::chatId = chatId; +} diff --git a/src/IPRefresher.cpp b/src/IPRefresher.cpp index af66491..ee4d7fa 100644 --- a/src/IPRefresher.cpp +++ b/src/IPRefresher.cpp @@ -11,7 +11,9 @@ #include #include -void IPRefresher::checkIPAdress(bool force) { +using namespace IPRefresher; + +bool IPRefresher::checkIPAdress(bool force) { FileLogger logger; IPAPI ipapi; @@ -20,14 +22,17 @@ void IPRefresher::checkIPAdress(bool force) { if (ip.empty()) { //no internet connection (or other error) Logger::warning("no internet connection"); + return Status_Code::ERROR_NO_INTERNET; } else if (!IpHelper::isIpValid(ip)) { // error when ip doesn't contain a : Logger::warning("an error occured when getting the global ip"); + return Status_Code::ERROR; } else { std::string oldip = logger.readip(); if (oldip == ip && !force) { Logger::message("no change -- ip: " + ip); + return Status_Code::NOREFRESH; } else { Logger::message("ip changed! -- from :" + oldip + "to: " + ip); @@ -43,18 +48,19 @@ void IPRefresher::checkIPAdress(bool force) { } else if (!result) { //error Logger::error("failed to write ip to dynu api!"); + return Status_Code::ERROR; } logger.safeip(ip); + return result ? Status_Code::SUCCESS : Status_Code::ERROR; } } } -IPRefresher::IPRefresher(bool loop) { - if (loop) { - Logger::message("startup of service"); - Logger::message("Version: " + StaticData::VERSION); - +void IPRefresher::startUpService(int interval) { + Logger::message("startup of service"); + Logger::message("Version: " + StaticData::VERSION); + if (Config::readConfig()) { while (true) { Logger::message("starting check"); if (Config::readConfig()) { @@ -62,7 +68,9 @@ IPRefresher::IPRefresher(bool loop) { } else { std::cout << "incorrect credentials!" << std::endl; } - std::this_thread::sleep_for(std::chrono::milliseconds(300000)); + std::this_thread::sleep_for(std::chrono::milliseconds(interval * 1000)); } + } else { + std::cout << "incorrect credentials!" << std::endl; } } diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp new file mode 100644 index 0000000..0a4c720 --- /dev/null +++ b/src/gui/MainWindow.cpp @@ -0,0 +1,129 @@ +#include "inc/gui/MainWindow.h" +#include "ui_mainwindow.h" + +#include "api/IPAPI.h" +#include "IPRefresher.h" +#include "Config.h" +#include "Logger.h" + +#include + +MainWindow::MainWindow() : QMainWindow(), ui(new Ui::MainWindow) { + ui->setupUi(this); + + // initialize gui with start parameters + initGui(); + + connect(ui->buttonCheckConfig, SIGNAL(clicked()), this, SLOT(checkConfigBtn())); + connect(ui->buttonRefreshIP, SIGNAL(clicked()), this, SLOT(refreshIPBtn())); + connect(ui->buttonSaveConfig, SIGNAL(clicked()), this, SLOT(saveConfigBtn())); + + connect(this, SIGNAL(appendLogField(QString)), ui->textLog, SLOT(appendPlainText(QString))); +} + +MainWindow::~MainWindow() { + // todo check if disconnects are really necessary + disconnect(ui->buttonCheckConfig); + disconnect(ui->buttonRefreshIP); + this->destroy(); + delete ui; +} + +void MainWindow::checkConfigBtn() { + Logger::message("checking config!"); + appendLogField("checking config!"); + + if (Config::validateConfig()) { + Logger::message("Config file is OK"); + appendLogField("Config file is OK"); + ui->labelConfig->setText("Config is: OK"); + } else { + Logger::error("There are errors in config file!"); + appendLogField("There are errors in config file!"); + } + appendLogField(""); +} + +void MainWindow::refreshIPBtn() { + Logger::message("start refreshing Dynu IP."); + appendLogField(""); + appendLogField("start refreshing Dynu IP."); + new std::thread([this]() { + if (Config::readConfig()) { + int code = IPRefresher::checkIPAdress(false); + switch (code) { + case IPRefresher::Status_Code::SUCCESS: + appendLogField("successfully refreshed IP!"); + break; + case IPRefresher::Status_Code::NOREFRESH: + appendLogField("IP is already correct."); + break; + case IPRefresher::Status_Code::ERROR_NO_INTERNET: + appendLogField("Error: No Internet connection"); + break; + case IPRefresher::Status_Code::ERROR: + appendLogField("An error occured while refreshing."); + break; + default: + appendLogField("An unknown error code occured"); + } + } else { + std::cout << "incorrect credentials!" << std::endl; + } + + Logger::message("Finished refreshing Dynu IP."); + this->appendLogField("Finished refreshing Dynu IP."); + }); +} + +void MainWindow::saveConfigBtn() { + if (ui->telegramsupportCheckbox->isChecked()) { + Config::setValues( + ui->domainnameedit->text().toStdString(), + ui->dynuapikeyedit->text().toStdString(), + ui->domainidedit->text().toStdString(), + ui->telegramapikeyedit->text().toStdString(), + ui->chatidedit->text().toStdString()); + } else { + Config::setValues( + ui->domainnameedit->text().toStdString(), + ui->dynuapikeyedit->text().toStdString(), + ui->domainidedit->text().toStdString()); + } + Config::saveConfig(); +} + +void MainWindow::initGui() { + // needs to be defined with new -- would be termintated after the constructor call. + new std::thread([this]() { + IPAPI ipapi; + std::string ip = ipapi.getGlobalIp(); + Logger::message("Current global IP: " + ip); + std::string msg = "Your current global IP: " + ip; + this->ui->labelCurrentIP->setText(msg.c_str()); + }); + + // set config info label and initial check if config is valid + ui->labelConfig->setText(Config::validateConfig() ? "Config is: OK" : "Config is: NOT OK"); + + if (Config::readConfig()) { + ui->dynuapikeyedit->setText(Config::getDynuapikey().c_str()); + ui->domainidedit->setText(Config::getDomainid().c_str()); + ui->domainnameedit->setText(Config::getDomainname().c_str()); + + if (Config::isTelegramSupported()) { + ui->telegramsupportCheckbox->setCheckState(Qt::Checked); + ui->telegramapikeyedit->setText(Config::getTelegramApiKey().c_str()); + ui->chatidedit->setText(Config::getChatId().c_str()); + } else { + ui->telegramsupportCheckbox->setCheckState(Qt::Unchecked); + ui->telegramapikeyedit->setDisabled(true); + ui->chatidedit->setDisabled(true); + } + } else { + // todo duplicate code with above + ui->telegramsupportCheckbox->setCheckState(Qt::Unchecked); + ui->telegramapikeyedit->setDisabled(true); + ui->chatidedit->setDisabled(true); + } +} \ No newline at end of file diff --git a/src/gui/mainwindow.ui b/src/gui/mainwindow.ui new file mode 100644 index 0000000..d0fb62d --- /dev/null +++ b/src/gui/mainwindow.ui @@ -0,0 +1,320 @@ + + + MainWindow + + + + 0 + 0 + 823 + 618 + + + + ArrowCursor + + + MainWindow + + + /*background-color: rgb(69, 196, 255); + + + + + false + + + + 40 + 410 + 741 + 191 + + + + IBeamCursor + + + + + + 40 + 380 + 64 + 17 + + + + Log: + + + + + + 40 + 20 + 741 + 351 + + + + 0 + + + + Basic + + + + + 20 + 30 + 301 + 17 + + + + Your current global IP: + + + + + + 20 + 70 + 141 + 17 + + + + Config is: undefined + + + + + + 20 + 120 + 231 + 151 + + + + Actions + + + + + 30 + 50 + 91 + 33 + + + + ArrowCursor + + + Check Config + + + + + + 30 + 100 + 91 + 33 + + + + Refresh IP + + + + + + + Config + + + + + 30 + 120 + 181 + 21 + + + + Telegram Notifications + + + + + + 630 + 270 + 91 + 33 + + + + Save Config + + + + + + 30 + 20 + 101 + 17 + + + + Dynu API Key + + + + + + 460 + 20 + 111 + 17 + + + + Domain ID + + + + + + 30 + 170 + 131 + 17 + + + + Telegram API Key + + + + + + 30 + 240 + 64 + 17 + + + + Chat ID + + + + + + 30 + 40 + 211 + 31 + + + + + + + 460 + 40 + 113 + 31 + + + + + + + 30 + 260 + 113 + 31 + + + + + + + 30 + 190 + 311 + 31 + + + + + + + 280 + 40 + 161 + 31 + + + + domain.dynu.net + + + + + + 280 + 20 + 111 + 17 + + + + Domainname + + + + + + Settings + + + + + 20 + 30 + 161 + 17 + + + + Select your language: + + + + + + 20 + 60 + 94 + 31 + + + + + + + + + + + diff --git a/src/main.cpp b/src/main.cpp index 5f830a6..8e55acd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,15 +21,14 @@ int main(int argc, char *argv[]) { } else if (firstarg == "-v" || firstarg == "--version") { std::cout << "Version " << StaticData::VERSION << std::endl; } else if (firstarg == "-f" || firstarg == "--force") { - IPRefresher ipr; if (Config::readConfig()) { - ipr.checkIPAdress(true); + IPRefresher::checkIPAdress(true); } else { std::cout << "incorrect credentials!" << std::endl; } } else if (firstarg == "-l" || firstarg == "--loop") { - IPRefresher(true); + IPRefresher::startUpService(true); } else if (firstarg == "-c" || firstarg == "--checkconfig") { if (Config::validateConfig()) { Logger::message("Config file is OK"); @@ -44,10 +43,9 @@ int main(int argc, char *argv[]) { Logger::message("wrong arguments! -h for help"); } } else { - IPRefresher ipr; Logger::message("starting check"); if (Config::readConfig()) { - ipr.checkIPAdress(false); + IPRefresher::checkIPAdress(false); } else { std::cout << "incorrect credentials!" << std::endl; } diff --git a/src/maingui.cpp b/src/maingui.cpp new file mode 100644 index 0000000..21df7b6 --- /dev/null +++ b/src/maingui.cpp @@ -0,0 +1,14 @@ +#include +#include "gui/MainWindow.h" + +/** + * application entry point + */ +int main(int argc, char *argv[]) { + QApplication a(argc, argv); + MainWindow w; + w.setWindowTitle("Dynu IP Refresher"); + w.show(); + + return QApplication::exec(); +} \ No newline at end of file